diff --git a/.ci/compute_projects.py b/.ci/compute_projects.py index 40dd0507a9ea..80e4e0221b3d 100644 --- a/.ci/compute_projects.py +++ b/.ci/compute_projects.py @@ -49,12 +49,22 @@ DEPENDENTS_TO_TEST = { }, "lld": {"bolt", "cross-project-tests"}, # TODO(issues/132795): LLDB should be enabled on clang changes. - "clang": {"clang-tools-extra", "compiler-rt", "cross-project-tests"}, - "clang-tools-extra": {"libc"}, + "clang": {"clang-tools-extra", "cross-project-tests"}, "mlir": {"flang"}, # Test everything if ci scripts are changed. - # FIXME: Figure out what is missing and add here. - ".ci": {"llvm", "clang", "lld", "lldb"}, + ".ci": { + "llvm", + "clang", + "lld", + "lldb", + "bolt", + "clang-tools-extra", + "mlir", + "polly", + "flang", + "libclc", + "openmp", + }, } # This mapping describes runtimes that should be enabled for a specific project, @@ -64,7 +74,16 @@ DEPENDENT_RUNTIMES_TO_BUILD = {"lldb": {"libcxx", "libcxxabi", "libunwind"}} # This mapping describes runtimes that should be tested when the key project is # touched. -DEPENDENT_RUNTIMES_TO_TEST = {"clang": {"libcxx", "libcxxabi", "libunwind"}} +DEPENDENT_RUNTIMES_TO_TEST = { + "clang": {"compiler-rt"}, + "clang-tools-extra": {"libc"}, + ".ci": {"compiler-rt", "libc"}, +} +DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG = { + "llvm": {"libcxx", "libcxxabi", "libunwind"}, + "clang": {"libcxx", "libcxxabi", "libunwind"}, + ".ci": {"libcxx", "libcxxabi", "libunwind"}, +} EXCLUDE_LINUX = { "cross-project-tests", # TODO(issues/132796): Tests are failing. @@ -93,9 +112,6 @@ EXCLUDE_MAC = { "cross-project-tests", "flang", "libc", - "libcxx", - "libcxxabi", - "libunwind", "lldb", "openmp", "polly", @@ -122,21 +138,35 @@ PROJECT_CHECK_TARGETS = { "polly": "check-polly", } -RUNTIMES = {"libcxx", "libcxxabi", "libunwind"} +RUNTIMES = {"libcxx", "libcxxabi", "libunwind", "compiler-rt", "libc"} -def _add_dependencies(projects: Set[str]) -> Set[str]: +def _add_dependencies(projects: Set[str], runtimes: Set[str]) -> Set[str]: projects_with_dependents = set(projects) current_projects_count = 0 while current_projects_count != len(projects_with_dependents): current_projects_count = len(projects_with_dependents) for project in list(projects_with_dependents): - if project not in PROJECT_DEPENDENCIES: - continue - projects_with_dependents.update(PROJECT_DEPENDENCIES[project]) + if project in PROJECT_DEPENDENCIES: + projects_with_dependents.update(PROJECT_DEPENDENCIES[project]) + for runtime in runtimes: + if runtime in PROJECT_DEPENDENCIES: + projects_with_dependents.update(PROJECT_DEPENDENCIES[runtime]) return projects_with_dependents +def _exclude_projects(current_projects: Set[str], platform: str) -> Set[str]: + if platform == "Linux": + to_exclude = EXCLUDE_LINUX + elif platform == "Windows": + to_exclude = EXCLUDE_WINDOWS + elif platform == "Darwin": + to_exclude = EXCLUDE_MAC + else: + raise ValueError(f"Unexpected platform: {platform}") + return current_projects.difference(to_exclude) + + def _compute_projects_to_test(modified_projects: Set[str], platform: str) -> Set[str]: projects_to_test = set() for modified_project in modified_projects: @@ -154,54 +184,52 @@ def _compute_projects_to_test(modified_projects: Set[str], platform: str) -> Set ): continue projects_to_test.add(dependent_project) - if platform == "Linux": - for to_exclude in EXCLUDE_LINUX: - if to_exclude in projects_to_test: - projects_to_test.remove(to_exclude) - elif platform == "Windows": - for to_exclude in EXCLUDE_WINDOWS: - if to_exclude in projects_to_test: - projects_to_test.remove(to_exclude) - elif platform == "Darwin": - for to_exclude in EXCLUDE_MAC: - if to_exclude in projects_to_test: - projects_to_test.remove(to_exclude) - else: - raise ValueError("Unexpected platform.") + projects_to_test = _exclude_projects(projects_to_test, platform) return projects_to_test -def _compute_projects_to_build(projects_to_test: Set[str]) -> Set[str]: - return _add_dependencies(projects_to_test) +def _compute_projects_to_build( + projects_to_test: Set[str], runtimes: Set[str] +) -> Set[str]: + return _add_dependencies(projects_to_test, runtimes) def _compute_project_check_targets(projects_to_test: Set[str]) -> Set[str]: check_targets = set() for project_to_test in projects_to_test: - if project_to_test not in PROJECT_CHECK_TARGETS: - continue - check_targets.add(PROJECT_CHECK_TARGETS[project_to_test]) + if project_to_test in PROJECT_CHECK_TARGETS: + check_targets.add(PROJECT_CHECK_TARGETS[project_to_test]) return check_targets -def _compute_runtimes_to_test(projects_to_test: Set[str]) -> Set[str]: +def _compute_runtimes_to_test(modified_projects: Set[str], platform: str) -> Set[str]: runtimes_to_test = set() - for project_to_test in projects_to_test: - if project_to_test in DEPENDENT_RUNTIMES_TO_TEST: - runtimes_to_test.update(DEPENDENT_RUNTIMES_TO_TEST[project_to_test]) - if project_to_test in DEPENDENT_RUNTIMES_TO_BUILD: - runtimes_to_test.update(DEPENDENT_RUNTIMES_TO_BUILD[project_to_test]) - return runtimes_to_test + for modified_project in modified_projects: + if modified_project in DEPENDENT_RUNTIMES_TO_TEST: + runtimes_to_test.update(DEPENDENT_RUNTIMES_TO_TEST[modified_project]) + return _exclude_projects(runtimes_to_test, platform) -def _compute_runtime_check_targets(projects_to_test: Set[str]) -> Set[str]: - check_targets = set() - for project_to_test in projects_to_test: - if project_to_test not in DEPENDENT_RUNTIMES_TO_TEST: - continue - for runtime_to_test in DEPENDENT_RUNTIMES_TO_TEST[project_to_test]: - check_targets.add(PROJECT_CHECK_TARGETS[runtime_to_test]) - return check_targets +def _compute_runtimes_to_test_needs_reconfig( + modified_projects: Set[str], platform: str +) -> Set[str]: + runtimes_to_test = set() + for modified_project in modified_projects: + if modified_project in DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG: + runtimes_to_test.update( + DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG[modified_project] + ) + return _exclude_projects(runtimes_to_test, platform) + + +def _compute_runtimes_to_build( + runtimes_to_test: Set[str], modified_projects: Set[str], platform: str +) -> Set[str]: + runtimes_to_build = set(runtimes_to_test) + for modified_project in modified_projects: + if modified_project in DEPENDENT_RUNTIMES_TO_BUILD: + runtimes_to_build.update(DEPENDENT_RUNTIMES_TO_BUILD[modified_project]) + return _exclude_projects(runtimes_to_build, platform) def _get_modified_projects(modified_files: list[str]) -> Set[str]: @@ -225,10 +253,19 @@ def _get_modified_projects(modified_files: list[str]) -> Set[str]: def get_env_variables(modified_files: list[str], platform: str) -> Set[str]: modified_projects = _get_modified_projects(modified_files) projects_to_test = _compute_projects_to_test(modified_projects, platform) - projects_to_build = _compute_projects_to_build(projects_to_test) + runtimes_to_test = _compute_runtimes_to_test(modified_projects, platform) + runtimes_to_test_needs_reconfig = _compute_runtimes_to_test_needs_reconfig( + modified_projects, platform + ) + runtimes_to_build = _compute_runtimes_to_build( + runtimes_to_test | runtimes_to_test_needs_reconfig, modified_projects, platform + ) + projects_to_build = _compute_projects_to_build(projects_to_test, runtimes_to_build) projects_check_targets = _compute_project_check_targets(projects_to_test) - runtimes_to_build = _compute_runtimes_to_test(projects_to_test) - runtimes_check_targets = _compute_runtime_check_targets(projects_to_test) + runtimes_check_targets = _compute_project_check_targets(runtimes_to_test) + runtimes_check_targets_needs_reconfig = _compute_project_check_targets( + runtimes_to_test_needs_reconfig + ) # We use a semicolon to separate the projects/runtimes as they get passed # to the CMake invocation and thus we need to use the CMake list separator # (;). We use spaces to separate the check targets as they end up getting @@ -238,6 +275,9 @@ def get_env_variables(modified_files: list[str], platform: str) -> Set[str]: "project_check_targets": " ".join(sorted(projects_check_targets)), "runtimes_to_build": ";".join(sorted(runtimes_to_build)), "runtimes_check_targets": " ".join(sorted(runtimes_check_targets)), + "runtimes_check_targets_needs_reconfig": " ".join( + sorted(runtimes_check_targets_needs_reconfig) + ), } diff --git a/.ci/compute_projects_test.py b/.ci/compute_projects_test.py index ae376ea6a43c..5efac2636698 100644 --- a/.ci/compute_projects_test.py +++ b/.ci/compute_projects_test.py @@ -26,6 +26,10 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual( env_variables["runtimes_check_targets"], + "", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -46,6 +50,10 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual( env_variables["runtimes_check_targets"], + "", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -66,6 +74,10 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual( env_variables["runtimes_check_targets"], + "", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -75,17 +87,21 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual( env_variables["projects_to_build"], - "clang;clang-tools-extra;compiler-rt;lld;llvm", + "clang;clang-tools-extra;lld;llvm", ) self.assertEqual( env_variables["project_check_targets"], - "check-clang check-clang-tools check-compiler-rt", + "check-clang check-clang-tools", ) self.assertEqual( - env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind" + env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind" ) self.assertEqual( env_variables["runtimes_check_targets"], + "check-compiler-rt", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -104,6 +120,10 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual( env_variables["runtimes_check_targets"], + "", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -115,6 +135,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "check-bolt") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_lldb(self): env_variables = compute_projects.get_env_variables( @@ -124,6 +145,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "check-lldb") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_mlir(self): env_variables = compute_projects.get_env_variables( @@ -135,6 +157,7 @@ class TestComputeProjects(unittest.TestCase): ) self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_flang(self): env_variables = compute_projects.get_env_variables( @@ -144,6 +167,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "check-flang") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_invalid_subproject(self): env_variables = compute_projects.get_env_variables( @@ -153,6 +177,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_top_level_file(self): env_variables = compute_projects.get_env_variables(["README.md"], "Linux") @@ -160,6 +185,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_exclude_runtiems_in_projects(self): env_variables = compute_projects.get_env_variables( @@ -169,6 +195,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_exclude_docs(self): env_variables = compute_projects.get_env_variables( @@ -178,6 +205,7 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_exclude_gn(self): env_variables = compute_projects.get_env_variables( @@ -187,21 +215,30 @@ class TestComputeProjects(unittest.TestCase): self.assertEqual(env_variables["project_check_targets"], "") self.assertEqual(env_variables["runtimes_to_build"], "") self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") def test_ci(self): env_variables = compute_projects.get_env_variables( [".ci/compute_projects.py"], "Linux" ) - self.assertEqual(env_variables["projects_to_build"], "clang;lld;lldb;llvm") self.assertEqual( - env_variables["project_check_targets"], - "check-clang check-lld check-lldb check-llvm", + env_variables["projects_to_build"], + "bolt;clang;clang-tools-extra;flang;libclc;lld;lldb;llvm;mlir;polly", ) self.assertEqual( - env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind" + env_variables["project_check_targets"], + "check-bolt check-clang check-clang-tools check-flang check-lld check-lldb check-llvm check-mlir check-polly", + ) + self.assertEqual( + env_variables["runtimes_to_build"], + "compiler-rt;libc;libcxx;libcxxabi;libunwind", ) self.assertEqual( env_variables["runtimes_check_targets"], + "check-compiler-rt check-libc", + ) + self.assertEqual( + env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -215,6 +252,19 @@ class TestComputeProjects(unittest.TestCase): env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind" ) self.assertEqual(env_variables["runtimes_check_targets"], "") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") + + def test_clang_tools_extra(self): + env_variables = compute_projects.get_env_variables( + ["clang-tools-extra/CMakeLists.txt"], "Linux" + ) + self.assertEqual( + env_variables["projects_to_build"], "clang;clang-tools-extra;lld;llvm" + ) + self.assertEqual(env_variables["project_check_targets"], "check-clang-tools") + self.assertEqual(env_variables["runtimes_to_build"], "libc") + self.assertEqual(env_variables["runtimes_check_targets"], "check-libc") + self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "") if __name__ == "__main__": diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge deleted file mode 100755 index 5e5f916f35b7..000000000000 --- a/.ci/generate-buildkite-pipeline-premerge +++ /dev/null @@ -1,131 +0,0 @@ -#!/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 generates a Buildkite pipeline that triggers the various CI jobs for -# the LLVM project during pre-commit CI. -# -# See https://buildkite.com/docs/agent/v3/cli-pipeline#pipeline-format. -# -# As this outputs a yaml file, it's possible to log messages to stderr or -# prefix with "#". - - -set -eu -set -o pipefail - -# Environment variables script works with: - -# Set by buildkite -: ${BUILDKITE_PULL_REQUEST_BASE_BRANCH:=} -: ${BUILDKITE_COMMIT:=} -: ${BUILDKITE_BRANCH:=} -# Fetch origin to have an up to date merge base for the diff. -git fetch origin -# List of files affected by this commit -: ${MODIFIED_FILES:=$(git diff --name-only origin/${BUILDKITE_PULL_REQUEST_BASE_BRANCH}...HEAD)} -# Filter rules for generic windows tests -: ${WINDOWS_AGENTS:='{"queue": "windows"}'} -# Filter rules for generic linux tests -: ${LINUX_AGENTS:='{"queue": "linux"}'} - -reviewID="$(git log --format=%B -n 1 | sed -nE 's/^Review-ID:[[:space:]]*(.+)$/\1/p')" -if [[ "${reviewID}" != "" ]]; then - buildMessage="https://llvm.org/${reviewID}" -else - buildMessage="Push to branch ${BUILDKITE_BRANCH}" -fi - -cat <&2 -echo "$MODIFIED_FILES" >&2 -modified_dirs=$(echo "$MODIFIED_FILES" | cut -d'/' -f1 | sort -u) -echo "Directories modified:" >&2 -echo "$modified_dirs" >&2 - -# Project specific pipelines. - -# If libc++ or one of the runtimes directories changed. -if echo "$modified_dirs" | grep -q -E "^(libcxx|libcxxabi|libunwind|runtimes|cmake)$"; then - cat <&1 >/dev/null - then - python3 "${MONOREPO_ROOT}"/.ci/generate_test_report_buildkite.py ":linux: Linux x64 Test Results" \ - "linux-x64-test-results" $retcode "${BUILD_DIR}"/test-results.*.xml - else - python3 "${MONOREPO_ROOT}"/.ci/generate_test_report_github.py ":penguin: Linux x64 Test Results" \ - $retcode "${BUILD_DIR}"/test-results.*.xml >> $GITHUB_STEP_SUMMARY - fi + + python3 "${MONOREPO_ROOT}"/.ci/generate_test_report_github.py ":penguin: Linux x64 Test Results" \ + $retcode "${BUILD_DIR}"/test-results.*.xml >> $GITHUB_STEP_SUMMARY } trap at-exit EXIT @@ -57,6 +52,7 @@ projects="${1}" targets="${2}" runtimes="${3}" runtime_targets="${4}" +runtime_targets_needs_reconfig="${5}" lit_args="-v --xunit-xml-output ${BUILD_DIR}/test-results.xml --use-unique-output-file-name --timeout=1200 --time-tests" @@ -93,9 +89,15 @@ echo "--- ninja" # Targets are not escaped as they are passed as separate arguments. ninja -C "${BUILD_DIR}" -k 0 ${targets} +if [[ "${runtime_targets}" != "" ]]; then + echo "--- ninja runtimes" + + ninja -C "${BUILD_DIR}" ${runtime_targets} +fi + # Compiling runtimes with just-built Clang and running their tests # as an additional testing for Clang. -if [[ "${runtimes_targets}" != "" ]]; then +if [[ "${runtime_targets_needs_reconfig}" != "" ]]; then echo "--- cmake runtimes C++26" cmake \ @@ -105,7 +107,7 @@ if [[ "${runtimes_targets}" != "" ]]; then echo "--- ninja runtimes C++26" - ninja -C "${BUILD_DIR}" ${runtime_targets} + ninja -C "${BUILD_DIR}" ${runtime_targets_needs_reconfig} echo "--- cmake runtimes clang modules" @@ -116,5 +118,5 @@ if [[ "${runtimes_targets}" != "" ]]; then echo "--- ninja runtimes clang modules" - ninja -C "${BUILD_DIR}" ${runtime_targets} + ninja -C "${BUILD_DIR}" ${runtime_targets_needs_reconfig} fi diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index a0997420b0d3..dc2913830e92 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -37,14 +37,9 @@ function at-exit { # If building fails there will be no results files. shopt -s nullglob - if command -v buildkite-agent 2>&1 >/dev/null - then - python "${MONOREPO_ROOT}"/.ci/generate_test_report_buildkite.py ":windows: Windows x64 Test Results" \ - "windows-x64-test-results" $retcode "${BUILD_DIR}"/test-results.*.xml - else - python "${MONOREPO_ROOT}"/.ci/generate_test_report_github.py ":window: Windows x64 Test Results" \ - $retcode "${BUILD_DIR}"/test-results.*.xml >> $GITHUB_STEP_SUMMARY - fi + + python "${MONOREPO_ROOT}"/.ci/generate_test_report_github.py ":window: Windows x64 Test Results" \ + $retcode "${BUILD_DIR}"/test-results.*.xml >> $GITHUB_STEP_SUMMARY } trap at-exit EXIT diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 162161ff13fb..2f8d5745668d 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -777,6 +777,10 @@ backend:NVPTX: - 'llvm/**/*nvptx*/**' - 'llvm/**/*NVPTX*/**' +backend:MIPS: + - '**/*mips*' + - '**/*Mips*' + backend:RISC-V: - clang/**/*riscv* - clang/**/*RISCV* diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index 80f2432b78de..f0bdf6c0b589 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -52,8 +52,8 @@ jobs: cxx: [ 'clang++-21' ] include: - config: 'generic-gcc' - cc: 'gcc-14' - cxx: 'g++-14' + cc: 'gcc-15' + cxx: 'g++-15' steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: ${{ matrix.config }}.${{ matrix.cxx }} @@ -92,8 +92,8 @@ jobs: cxx: [ 'clang++-21' ] include: - config: 'generic-gcc-cxx11' - cc: 'gcc-14' - cxx: 'g++-14' + cc: 'gcc-15' + cxx: 'g++-15' - config: 'generic-cxx26' cc: 'clang-20' cxx: 'clang++-20' diff --git a/.github/workflows/libcxx-restart-preempted-jobs.yaml b/.github/workflows/libcxx-restart-preempted-jobs.yaml index 7b341d7f22e4..9706f0459922 100644 --- a/.github/workflows/libcxx-restart-preempted-jobs.yaml +++ b/.github/workflows/libcxx-restart-preempted-jobs.yaml @@ -33,7 +33,7 @@ jobs: with: script: | const failure_regex = /Process completed with exit code 1./ - const preemption_regex = /The runner has received a shutdown signal/ + const preemption_regex = /(The runner has received a shutdown signal)|(The operation was canceled)/ const wf_run = context.payload.workflow_run core.notice(`Running on "${wf_run.display_title}" by @${wf_run.actor.login} (event: ${wf_run.event})\nWorkflow run URL: ${wf_run.html_url}`) diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml index 709b6d03d94c..4435a3e90576 100644 --- a/.github/workflows/premerge.yaml +++ b/.github/workflows/premerge.yaml @@ -56,11 +56,12 @@ jobs: echo "Running project checks targets: ${project_check_targets}" echo "Building runtimes: ${runtimes_to_build}" echo "Running runtimes checks targets: ${runtimes_check_targets}" + echo "Running runtimes checks requiring reconfiguring targets: ${runtimes_check_targets_needs_reconfig}" export CC=/opt/llvm/bin/clang export CXX=/opt/llvm/bin/clang++ - ./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" + ./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" "${runtimes_check_targets_needs_reconfig}" - name: Upload Artifacts uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: diff --git a/bolt/include/bolt/Passes/PAuthGadgetScanner.h b/bolt/include/bolt/Passes/PAuthGadgetScanner.h index c6b9cc2eb4b9..721fd664a325 100644 --- a/bolt/include/bolt/Passes/PAuthGadgetScanner.h +++ b/bolt/include/bolt/Passes/PAuthGadgetScanner.h @@ -199,8 +199,7 @@ namespace PAuthGadgetScanner { // to distinguish intermediate and final results at the type level. // // Here is an overview of issue life-cycle: -// * an analysis (SrcSafetyAnalysis at now, DstSafetyAnalysis will be added -// later to support the detection of authentication oracles) computes register +// * an analysis (SrcSafetyAnalysis or DstSafetyAnalysis) computes register // state for each instruction in the function. // * for each instruction, it is checked whether it is a gadget of some kind, // taking the computed state into account. If a gadget is found, its kind @@ -273,6 +272,11 @@ public: virtual ~ExtraInfo() {} }; +/// The set of instructions writing to the affected register in an unsafe +/// manner. +/// +/// This is a hint to be printed alongside the report. It should be further +/// analyzed by the user. class ClobberingInfo : public ExtraInfo { SmallVector ClobberingInstrs; @@ -282,6 +286,20 @@ public: void print(raw_ostream &OS, const MCInstReference Location) const override; }; +/// The set of instructions leaking the authenticated pointer before the +/// result of authentication was checked. +/// +/// This is a hint to be printed alongside the report. It should be further +/// analyzed by the user. +class LeakageInfo : public ExtraInfo { + SmallVector LeakingInstrs; + +public: + LeakageInfo(ArrayRef Instrs) : LeakingInstrs(Instrs) {} + + void print(raw_ostream &OS, const MCInstReference Location) const override; +}; + /// A brief version of a report that can be further augmented with the details. /// /// A half-baked report produced on the first run of the analysis. An extra, @@ -322,6 +340,9 @@ class FunctionAnalysisContext { void findUnsafeUses(SmallVector> &Reports); void augmentUnsafeUseReports(ArrayRef> Reports); + void findUnsafeDefs(SmallVector> &Reports); + void augmentUnsafeDefReports(ArrayRef> Reports); + /// Process the reports which do not have to be augmented, and remove them /// from Reports. void handleSimpleReports(SmallVector> &Reports); diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index 3f07a6dc03a4..cc28a06c151e 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -85,6 +85,8 @@ private: }; friend raw_ostream &operator<<(raw_ostream &OS, const LBREntry &); + friend struct PerfSpeEventsTestHelper; + struct PerfBranchSample { SmallVector LBR; }; @@ -99,24 +101,29 @@ private: uint64_t Addr; }; + /// Container for the unit of branch data, matching pre-aggregated trace type. + /// Backwards compatible with branch and fall-through types: + /// - if \p To is < 0, the trace only contains branch data (BR_ONLY), + /// - if \p Branch is < 0, the trace only contains fall-through data + /// (FT_ONLY, FT_EXTERNAL_ORIGIN, or FT_EXTERNAL_RETURN). struct Trace { + static constexpr const uint64_t EXTERNAL = 0ULL; + static constexpr const uint64_t BR_ONLY = -1ULL; + static constexpr const uint64_t FT_ONLY = -1ULL; + static constexpr const uint64_t FT_EXTERNAL_ORIGIN = -2ULL; + static constexpr const uint64_t FT_EXTERNAL_RETURN = -3ULL; + + uint64_t Branch; uint64_t From; uint64_t To; - Trace(uint64_t From, uint64_t To) : From(From), To(To) {} - bool operator==(const Trace &Other) const { - return From == Other.From && To == Other.To; - } + auto tie() const { return std::tie(Branch, From, To); } + bool operator==(const Trace &Other) const { return tie() == Other.tie(); } + bool operator<(const Trace &Other) const { return tie() < Other.tie(); } }; + friend raw_ostream &operator<<(raw_ostream &OS, const Trace &); struct TraceHash { - size_t operator()(const Trace &L) const { - return std::hash()(L.From << 32 | L.To); - } - }; - - struct FTInfo { - uint64_t InternCount{0}; - uint64_t ExternCount{0}; + size_t operator()(const Trace &L) const { return hash_combine(L.tie()); } }; struct TakenBranchInfo { @@ -126,8 +133,11 @@ private: /// Intermediate storage for profile data. We save the results of parsing /// and use them later for processing and assigning profile. - std::unordered_map BranchLBRs; - std::unordered_map FallthroughLBRs; + std::unordered_map TraceMap; + std::vector> Traces; + /// Pre-populated addresses of returns, coming from pre-aggregated data or + /// disassembly. Used to disambiguate call-continuation fall-throughs. + std::unordered_set Returns; std::unordered_map BasicSamples; std::vector MemSamples; @@ -200,8 +210,8 @@ private: /// Return a vector of offsets corresponding to a trace in a function /// if the trace is valid, std::nullopt otherwise. std::optional, 16>> - getFallthroughsInTrace(BinaryFunction &BF, const LBREntry &First, - const LBREntry &Second, uint64_t Count = 1) const; + getFallthroughsInTrace(BinaryFunction &BF, const Trace &Trace, uint64_t Count, + bool IsReturn) const; /// Record external entry into the function \p BF. /// @@ -261,12 +271,14 @@ private: uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds); + /// Checks if \p Addr corresponds to a return instruction. + bool checkReturn(uint64_t Addr); + /// Register a \p Branch. bool doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds); /// Register a trace between two LBR entries supplied in execution order. - bool doTrace(const LBREntry &First, const LBREntry &Second, - uint64_t Count = 1); + bool doTrace(const Trace &Trace, uint64_t Count, bool IsReturn); /// Parser helpers /// Return false if we exhausted our parser buffer and finished parsing @@ -379,9 +391,9 @@ private: /// File format syntax: /// E /// S - /// T + /// [TR] /// B - /// [Ff] + /// [Ffr] /// /// where , , have the format [:] /// @@ -392,8 +404,11 @@ private: /// f - an aggregated fall-through with external origin - used to disambiguate /// between a return hitting a basic block head and a regular internal /// jump to the block + /// r - an aggregated fall-through originating at an external return, no + /// checks are performed for a fallthrough start /// T - an aggregated trace: branch from to with a fall-through /// to + /// R - an aggregated trace originating at a return /// /// - build id of the object containing the address. We can skip it for /// the main binary and use "X" for an unknown object. This will save some @@ -516,6 +531,26 @@ inline raw_ostream &operator<<(raw_ostream &OS, OS << formatv("{0:x} -> {1:x}/{2}", L.From, L.To, L.Mispred ? 'M' : 'P'); return OS; } + +inline raw_ostream &operator<<(raw_ostream &OS, + const DataAggregator::Trace &T) { + switch (T.Branch) { + case DataAggregator::Trace::FT_ONLY: + break; + case DataAggregator::Trace::FT_EXTERNAL_ORIGIN: + OS << "X:0 -> "; + break; + case DataAggregator::Trace::FT_EXTERNAL_RETURN: + OS << "X:R -> "; + break; + default: + OS << Twine::utohexstr(T.Branch) << " -> "; + } + OS << Twine::utohexstr(T.From); + if (T.To != DataAggregator::Trace::BR_ONLY) + OS << " ... " << Twine::utohexstr(T.To); + return OS; +} } // namespace bolt } // namespace llvm diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h index 4acce5a3e832..a75b6bf720ec 100644 --- a/bolt/include/bolt/Utils/CommandLineOpts.h +++ b/bolt/include/bolt/Utils/CommandLineOpts.h @@ -48,6 +48,7 @@ extern llvm::cl::OptionCategory BinaryAnalysisCategory; extern llvm::cl::opt AlignText; extern llvm::cl::opt AlignFunctions; extern llvm::cl::opt AggregateOnly; +extern llvm::cl::opt ArmSPE; extern llvm::cl::opt BucketsPerLine; extern llvm::cl::opt CompactCodeModel; extern llvm::cl::opt DiffOnly; diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp index 971ea5fdef42..95e831fe9c8c 100644 --- a/bolt/lib/Passes/PAuthGadgetScanner.cpp +++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp @@ -152,6 +152,8 @@ public: // in the gadgets to be reported. This information is used in the second run // to also track which instructions last wrote to those registers. +typedef SmallPtrSet SetOfRelatedInsts; + /// A state representing which registers are safe to use by an instruction /// at a given program point. /// @@ -195,7 +197,7 @@ struct SrcState { /// pac-ret analysis, the expectation is that almost all return instructions /// only use register `X30`, and therefore, this vector will probably have /// length 1 in the second run. - std::vector> LastInstWritingReg; + std::vector LastInstWritingReg; /// Construct an empty state. SrcState() {} @@ -230,12 +232,11 @@ struct SrcState { bool operator!=(const SrcState &RHS) const { return !((*this) == RHS); } }; -static void -printLastInsts(raw_ostream &OS, - ArrayRef> LastInstWritingReg) { +static void printInstsShort(raw_ostream &OS, + ArrayRef Insts) { OS << "Insts: "; - for (unsigned I = 0; I < LastInstWritingReg.size(); ++I) { - auto &Set = LastInstWritingReg[I]; + for (unsigned I = 0; I < Insts.size(); ++I) { + auto &Set = Insts[I]; OS << "[" << I << "]("; for (const MCInst *MCInstP : Set) OS << MCInstP << " "; @@ -243,14 +244,14 @@ printLastInsts(raw_ostream &OS, } } -raw_ostream &operator<<(raw_ostream &OS, const SrcState &S) { +static raw_ostream &operator<<(raw_ostream &OS, const SrcState &S) { OS << "src-state<"; if (S.empty()) { OS << "empty"; } else { OS << "SafeToDerefRegs: " << S.SafeToDerefRegs << ", "; OS << "TrustedRegs: " << S.TrustedRegs << ", "; - printLastInsts(OS, S.LastInstWritingReg); + printInstsShort(OS, S.LastInstWritingReg); } OS << ">"; return OS; @@ -279,7 +280,7 @@ void SrcStatePrinter::print(raw_ostream &OS, const SrcState &S) const { OS << ", TrustedRegs: "; RegStatePrinter.print(OS, S.TrustedRegs); OS << ", "; - printLastInsts(OS, S.LastInstWritingReg); + printInstsShort(OS, S.LastInstWritingReg); } OS << ">"; } @@ -323,13 +324,12 @@ protected: DenseMap> CheckerSequenceInfo; - SmallPtrSet &lastWritingInsts(SrcState &S, - MCPhysReg Reg) const { + SetOfRelatedInsts &lastWritingInsts(SrcState &S, MCPhysReg Reg) const { unsigned Index = RegsToTrackInstsFor.getIndex(Reg); return S.LastInstWritingReg[Index]; } - const SmallPtrSet &lastWritingInsts(const SrcState &S, - MCPhysReg Reg) const { + const SetOfRelatedInsts &lastWritingInsts(const SrcState &S, + MCPhysReg Reg) const { unsigned Index = RegsToTrackInstsFor.getIndex(Reg); return S.LastInstWritingReg[Index]; } @@ -430,11 +430,13 @@ protected: } SrcState computeNext(const MCInst &Point, const SrcState &Cur) { + if (BC.MIB->isCFI(Point)) + return Cur; + SrcStatePrinter P(BC); LLVM_DEBUG({ dbgs() << " SrcSafetyAnalysis::ComputeNext("; - BC.InstPrinter->printInst(&const_cast(Point), 0, "", *BC.STI, - dbgs()); + BC.InstPrinter->printInst(&Point, 0, "", *BC.STI, dbgs()); dbgs() << ", "; P.print(dbgs(), Cur); dbgs() << ")\n"; @@ -612,6 +614,42 @@ protected: StringRef getAnnotationName() const { return "DataflowSrcSafetyAnalysis"; } }; +/// A helper base class for implementing a simplified counterpart of a dataflow +/// analysis for functions without CFG information. +template class CFGUnawareAnalysis { + BinaryContext &BC; + BinaryFunction &BF; + MCPlusBuilder::AllocatorIdTy AllocId; + unsigned StateAnnotationIndex; + + void cleanStateAnnotations() { + for (auto &I : BF.instrs()) + BC.MIB->removeAnnotation(I.second, StateAnnotationIndex); + } + +protected: + CFGUnawareAnalysis(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId, + StringRef AnnotationName) + : BC(BF.getBinaryContext()), BF(BF), AllocId(AllocId) { + StateAnnotationIndex = BC.MIB->getOrCreateAnnotationIndex(AnnotationName); + } + + void setState(MCInst &Inst, const StateTy &S) { + // Check if we need to remove an old annotation (this is the case if + // this is the second, detailed run of the analysis). + if (BC.MIB->hasAnnotation(Inst, StateAnnotationIndex)) + BC.MIB->removeAnnotation(Inst, StateAnnotationIndex); + // Attach the state. + BC.MIB->addAnnotation(Inst, StateAnnotationIndex, S, AllocId); + } + + const StateTy &getState(const MCInst &Inst) const { + return BC.MIB->getAnnotationAs(Inst, StateAnnotationIndex); + } + + virtual ~CFGUnawareAnalysis() { cleanStateAnnotations(); } +}; + // A simplified implementation of DataflowSrcSafetyAnalysis for functions // lacking CFG information. // @@ -646,15 +684,10 @@ protected: // of instructions without labels in between. These sequences can be processed // the same way basic blocks are processed by data-flow analysis, assuming // pessimistically that all registers are unsafe at the start of each sequence. -class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis { +class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis, + public CFGUnawareAnalysis { + using SrcSafetyAnalysis::BC; BinaryFunction &BF; - MCPlusBuilder::AllocatorIdTy AllocId; - unsigned StateAnnotationIndex; - - void cleanStateAnnotations() { - for (auto &I : BF.instrs()) - BC.MIB->removeAnnotation(I.second, StateAnnotationIndex); - } /// Creates a state with all registers marked unsafe (not to be confused /// with empty state). @@ -666,15 +699,16 @@ public: CFGUnawareSrcSafetyAnalysis(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId, ArrayRef RegsToTrackInstsFor) - : SrcSafetyAnalysis(BF, RegsToTrackInstsFor), BF(BF), AllocId(AllocId) { - StateAnnotationIndex = - BC.MIB->getOrCreateAnnotationIndex("CFGUnawareSrcSafetyAnalysis"); + : SrcSafetyAnalysis(BF, RegsToTrackInstsFor), + CFGUnawareAnalysis(BF, AllocId, "CFGUnawareSrcSafetyAnalysis"), BF(BF) { } void run() override { SrcState S = createEntryState(); for (auto &I : BF.instrs()) { MCInst &Inst = I.second; + if (BC.MIB->isCFI(Inst)) + continue; // If there is a label before this instruction, it is possible that it // can be jumped-to, thus conservatively resetting S. As an exception, @@ -687,12 +721,8 @@ public: S = createUnsafeState(); } - // Check if we need to remove an old annotation (this is the case if - // this is the second, detailed, run of the analysis). - if (BC.MIB->hasAnnotation(Inst, StateAnnotationIndex)) - BC.MIB->removeAnnotation(Inst, StateAnnotationIndex); // Attach the state *before* this instruction executes. - BC.MIB->addAnnotation(Inst, StateAnnotationIndex, S, AllocId); + setState(Inst, S); // Compute the state after this instruction executes. S = computeNext(Inst, S); @@ -700,10 +730,8 @@ public: } const SrcState &getStateBefore(const MCInst &Inst) const override { - return BC.MIB->getAnnotationAs(Inst, StateAnnotationIndex); + return getState(Inst); } - - ~CFGUnawareSrcSafetyAnalysis() { cleanStateAnnotations(); } }; std::shared_ptr @@ -717,6 +745,483 @@ SrcSafetyAnalysis::create(BinaryFunction &BF, RegsToTrackInstsFor); } +/// A state representing which registers are safe to be used as the destination +/// operand of an authentication instruction. +/// +/// Similar to SrcState, it is the responsibility of the analysis to take +/// register aliasing into account. +/// +/// Depending on the implementation (such as whether FEAT_FPAC is implemented +/// by an AArch64 CPU or not), it may be possible that an authentication +/// instruction returns an invalid pointer on failure instead of terminating +/// the program immediately (assuming the program will crash as soon as that +/// pointer is dereferenced). Since few bits are usually allocated for the PAC +/// field (such as less than 16 bits on a typical AArch64 system), an attacker +/// can try every possible signature and guess the correct one if there is a +/// gadget that tells whether the particular pointer has a correct signature +/// (a so called "authentication oracle"). For that reason, it should be +/// impossible for an attacker to test if a pointer is correctly signed - +/// either the program should be terminated on authentication failure or +/// the result of authentication should not be accessible to an attacker. +/// +/// Considering the instructions in forward order as they are executed, a +/// restricted set of operations can be allowed on any register containing a +/// value derived from the result of an authentication instruction until that +/// value is checked not to contain the result of a failed authentication. +/// In DstSafetyAnalysis, these rules are adapted, so that the safety property +/// for a register is computed by iterating the instructions in backward order. +/// Then the resulting properties are used at authentication instruction sites +/// to check output registers and report the particular instruction if it writes +/// to an unsafe register. +/// +/// Another approach would be to simulate the above rules as-is, iterating over +/// the instructions in forward direction. To make it possible to report the +/// particular instructions as oracles, this would probably require tracking +/// references to these instructions for each register currently containing +/// sensitive data. +/// +/// In DstSafetyAnalysis, the source register Xn of an instruction Inst is safe +/// if at least one of the following is true: +/// * Inst checks if Xn contains the result of a successful authentication and +/// terminates the program on failure. Note that Inst can either naturally +/// dereference Xn (load, branch, return, etc. instructions) or be the first +/// instruction of an explicit checking sequence. +/// * Inst performs safe address arithmetic AND both source and result +/// registers, as well as any temporary registers, must be safe after +/// execution of Inst (temporaries are not used on AArch64 and thus not +/// currently supported/allowed). +/// See MCPlusBuilder::analyzeAddressArithmeticsForPtrAuth for the details. +/// * Inst fully overwrites Xn with a constant. +struct DstState { + /// The set of registers whose values cannot be inspected by an attacker in + /// a way usable as an authentication oracle. The results of authentication + /// instructions should only be written to such registers. + BitVector CannotEscapeUnchecked; + + /// A vector of sets, only used on the second analysis run. + /// Each element in this vector represents one of the tracked registers. + /// For each such register we track the set of first instructions that leak + /// the authenticated pointer before it was checked. This is intended to + /// provide clues on which instruction made the particular register unsafe. + /// + /// Please note that the mapping from MCPhysReg values to indexes in this + /// vector is provided by RegsToTrackInstsFor field of DstSafetyAnalysis. + std::vector FirstInstLeakingReg; + + /// Constructs an empty state. + DstState() {} + + DstState(unsigned NumRegs, unsigned NumRegsToTrack) + : CannotEscapeUnchecked(NumRegs), FirstInstLeakingReg(NumRegsToTrack) {} + + DstState &merge(const DstState &StateIn) { + if (StateIn.empty()) + return *this; + if (empty()) + return (*this = StateIn); + + CannotEscapeUnchecked &= StateIn.CannotEscapeUnchecked; + for (unsigned I = 0; I < FirstInstLeakingReg.size(); ++I) + for (const MCInst *J : StateIn.FirstInstLeakingReg[I]) + FirstInstLeakingReg[I].insert(J); + return *this; + } + + /// Returns true if this object does not store state of any registers - + /// neither safe, nor unsafe ones. + bool empty() const { return CannotEscapeUnchecked.empty(); } + + bool operator==(const DstState &RHS) const { + return CannotEscapeUnchecked == RHS.CannotEscapeUnchecked && + FirstInstLeakingReg == RHS.FirstInstLeakingReg; + } + bool operator!=(const DstState &RHS) const { return !((*this) == RHS); } +}; + +static raw_ostream &operator<<(raw_ostream &OS, const DstState &S) { + OS << "dst-state<"; + if (S.empty()) { + OS << "empty"; + } else { + OS << "CannotEscapeUnchecked: " << S.CannotEscapeUnchecked << ", "; + printInstsShort(OS, S.FirstInstLeakingReg); + } + OS << ">"; + return OS; +} + +class DstStatePrinter { +public: + void print(raw_ostream &OS, const DstState &S) const; + explicit DstStatePrinter(const BinaryContext &BC) : BC(BC) {} + +private: + const BinaryContext &BC; +}; + +void DstStatePrinter::print(raw_ostream &OS, const DstState &S) const { + RegStatePrinter RegStatePrinter(BC); + OS << "dst-state<"; + if (S.empty()) { + assert(S.CannotEscapeUnchecked.empty()); + assert(S.FirstInstLeakingReg.empty()); + OS << "empty"; + } else { + OS << "CannotEscapeUnchecked: "; + RegStatePrinter.print(OS, S.CannotEscapeUnchecked); + OS << ", "; + printInstsShort(OS, S.FirstInstLeakingReg); + } + OS << ">"; +} + +/// Computes which registers are safe to be written to by auth instructions. +/// +/// This is the base class for two implementations: a dataflow-based analysis +/// which is intended to be used for most functions and a simplified CFG-unaware +/// version for functions without reconstructed CFG. +class DstSafetyAnalysis { +public: + DstSafetyAnalysis(BinaryFunction &BF, ArrayRef RegsToTrackInstsFor) + : BC(BF.getBinaryContext()), NumRegs(BC.MRI->getNumRegs()), + RegsToTrackInstsFor(RegsToTrackInstsFor) {} + + virtual ~DstSafetyAnalysis() {} + + static std::shared_ptr + create(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId, + ArrayRef RegsToTrackInstsFor); + + virtual void run() = 0; + virtual const DstState &getStateAfter(const MCInst &Inst) const = 0; + +protected: + BinaryContext &BC; + const unsigned NumRegs; + + const TrackedRegisters RegsToTrackInstsFor; + + /// Stores information about the detected instruction sequences emitted to + /// check an authenticated pointer. Specifically, if such sequence is detected + /// in a basic block, it maps the first instruction of that sequence to the + /// register being checked. + /// + /// As the detection of such sequences requires iterating over the adjacent + /// instructions, it should be done before calling computeNext(), which + /// operates on separate instructions. + DenseMap RegCheckedAt; + + SetOfRelatedInsts &firstLeakingInsts(DstState &S, MCPhysReg Reg) const { + unsigned Index = RegsToTrackInstsFor.getIndex(Reg); + return S.FirstInstLeakingReg[Index]; + } + const SetOfRelatedInsts &firstLeakingInsts(const DstState &S, + MCPhysReg Reg) const { + unsigned Index = RegsToTrackInstsFor.getIndex(Reg); + return S.FirstInstLeakingReg[Index]; + } + + /// Creates a state with all registers marked unsafe (not to be confused + /// with empty state). + DstState createUnsafeState() { + return DstState(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters()); + } + + /// Returns the set of registers that can be leaked by this instruction. + /// A register is considered leaked if it has any intersection with any + /// register read by Inst. This is similar to how the set of clobbered + /// registers is computed, but taking input operands instead of outputs. + BitVector getLeakedRegs(const MCInst &Inst) const { + BitVector Leaked(NumRegs); + + // Assume a call can read all registers. + if (BC.MIB->isCall(Inst)) { + Leaked.set(); + return Leaked; + } + + // Compute the set of registers overlapping with any register used by + // this instruction. + + const MCInstrDesc &Desc = BC.MII->get(Inst.getOpcode()); + + for (MCPhysReg Reg : Desc.implicit_uses()) + Leaked |= BC.MIB->getAliases(Reg, /*OnlySmaller=*/false); + + for (const MCOperand &Op : BC.MIB->useOperands(Inst)) { + if (Op.isReg()) + Leaked |= BC.MIB->getAliases(Op.getReg(), /*OnlySmaller=*/false); + } + + return Leaked; + } + + SmallVector getRegsMadeProtected(const MCInst &Inst, + const BitVector &LeakedRegs, + const DstState &Cur) const { + SmallVector Regs; + + // A pointer can be checked, or + if (auto CheckedReg = + BC.MIB->getAuthCheckedReg(Inst, /*MayOverwrite=*/true)) + Regs.push_back(*CheckedReg); + if (RegCheckedAt.contains(&Inst)) + Regs.push_back(RegCheckedAt.at(&Inst)); + + // ... it can be used as a branch target, or + if (BC.MIB->isIndirectBranch(Inst) || BC.MIB->isIndirectCall(Inst)) { + bool IsAuthenticated; + MCPhysReg BranchDestReg = + BC.MIB->getRegUsedAsIndirectBranchDest(Inst, IsAuthenticated); + assert(BranchDestReg != BC.MIB->getNoRegister()); + if (!IsAuthenticated) + Regs.push_back(BranchDestReg); + } + + // ... it can be used as a return target, or + if (BC.MIB->isReturn(Inst)) { + bool IsAuthenticated = false; + std::optional RetReg = + BC.MIB->getRegUsedAsRetDest(Inst, IsAuthenticated); + if (RetReg && !IsAuthenticated) + Regs.push_back(*RetReg); + } + + // ... an address can be updated in a safe manner, or + if (auto DstAndSrc = BC.MIB->analyzeAddressArithmeticsForPtrAuth(Inst)) { + MCPhysReg DstReg, SrcReg; + std::tie(DstReg, SrcReg) = *DstAndSrc; + // Note that *all* registers containing the derived values must be safe, + // both source and destination ones. No temporaries are supported at now. + if (Cur.CannotEscapeUnchecked[SrcReg] && + Cur.CannotEscapeUnchecked[DstReg]) + Regs.push_back(SrcReg); + } + + // ... the register can be overwritten in whole with a constant: for that + // purpose, look for the instructions with no register inputs (neither + // explicit nor implicit ones) and no side effects (to rule out reading + // not modelled locations). + const MCInstrDesc &Desc = BC.MII->get(Inst.getOpcode()); + bool HasExplicitSrcRegs = llvm::any_of(BC.MIB->useOperands(Inst), + [](auto Op) { return Op.isReg(); }); + if (!Desc.hasUnmodeledSideEffects() && !HasExplicitSrcRegs && + Desc.implicit_uses().empty()) { + for (const MCOperand &Def : BC.MIB->defOperands(Inst)) + Regs.push_back(Def.getReg()); + } + + return Regs; + } + + DstState computeNext(const MCInst &Point, const DstState &Cur) { + if (BC.MIB->isCFI(Point)) + return Cur; + + DstStatePrinter P(BC); + LLVM_DEBUG({ + dbgs() << " DstSafetyAnalysis::ComputeNext("; + BC.InstPrinter->printInst(&Point, 0, "", *BC.STI, dbgs()); + dbgs() << ", "; + P.print(dbgs(), Cur); + dbgs() << ")\n"; + }); + + // If this instruction is reachable by the analysis, a non-empty state will + // be propagated to it sooner or later. Until then, skip computeNext(). + if (Cur.empty()) { + LLVM_DEBUG( + { dbgs() << "Skipping computeNext(Point, Cur) as Cur is empty.\n"; }); + return DstState(); + } + + // First, compute various properties of the instruction, taking the state + // after its execution into account, if necessary. + + BitVector LeakedRegs = getLeakedRegs(Point); + SmallVector NewProtectedRegs = + getRegsMadeProtected(Point, LeakedRegs, Cur); + + // Then, compute the state before this instruction is executed. + DstState Next = Cur; + + Next.CannotEscapeUnchecked.reset(LeakedRegs); + for (MCPhysReg Reg : RegsToTrackInstsFor.getRegisters()) { + if (LeakedRegs[Reg]) + firstLeakingInsts(Next, Reg) = {&Point}; + } + + BitVector NewProtectedSubregs(NumRegs); + for (MCPhysReg Reg : NewProtectedRegs) + NewProtectedSubregs |= BC.MIB->getAliases(Reg, /*OnlySmaller=*/true); + Next.CannotEscapeUnchecked |= NewProtectedSubregs; + for (MCPhysReg Reg : RegsToTrackInstsFor.getRegisters()) { + if (NewProtectedSubregs[Reg]) + firstLeakingInsts(Next, Reg).clear(); + } + + LLVM_DEBUG({ + dbgs() << " .. result: ("; + P.print(dbgs(), Next); + dbgs() << ")\n"; + }); + + return Next; + } + +public: + std::vector getLeakingInsts(const MCInst &Inst, + BinaryFunction &BF, + MCPhysReg LeakedReg) const { + const DstState &S = getStateAfter(Inst); + + std::vector Result; + for (const MCInst *Inst : firstLeakingInsts(S, LeakedReg)) { + MCInstReference Ref = MCInstReference::get(Inst, BF); + assert(Ref && "Expected Inst to be found"); + Result.push_back(Ref); + } + return Result; + } +}; + +class DataflowDstSafetyAnalysis + : public DstSafetyAnalysis, + public DataflowAnalysis { + using DFParent = DataflowAnalysis; + friend DFParent; + + using DstSafetyAnalysis::BC; + using DstSafetyAnalysis::computeNext; + +public: + DataflowDstSafetyAnalysis(BinaryFunction &BF, + MCPlusBuilder::AllocatorIdTy AllocId, + ArrayRef RegsToTrackInstsFor) + : DstSafetyAnalysis(BF, RegsToTrackInstsFor), DFParent(BF, AllocId) {} + + const DstState &getStateAfter(const MCInst &Inst) const override { + // The dataflow analysis base class iterates backwards over the + // instructions, thus "after" vs. "before" difference. + return DFParent::getStateBefore(Inst).get(); + } + + void run() override { + for (BinaryBasicBlock &BB : Func) { + if (auto CheckerInfo = BC.MIB->getAuthCheckedReg(BB)) { + LLVM_DEBUG({ + dbgs() << "Found pointer checking sequence in " << BB.getName() + << ":\n"; + traceReg(BC, "Checked register", CheckerInfo->first); + traceInst(BC, "First instruction", *CheckerInfo->second); + }); + RegCheckedAt[CheckerInfo->second] = CheckerInfo->first; + } + } + DFParent::run(); + } + +protected: + void preflight() {} + + DstState getStartingStateAtBB(const BinaryBasicBlock &BB) { + // In general, the initial state should be empty, not everything-is-unsafe, + // to give a chance for some meaningful state to be propagated to BB from + // an indirectly reachable "exit basic block" ending with a return or tail + // call instruction. + // + // A basic block without any successors, on the other hand, can be + // pessimistically initialized to everything-is-unsafe: this will naturally + // handle both return and tail call instructions and is harmless for + // internal indirect branch instructions (such as computed gotos). + if (BB.succ_empty()) + return createUnsafeState(); + + return DstState(); + } + + DstState getStartingStateAtPoint(const MCInst &Point) { return DstState(); } + + void doConfluence(DstState &StateOut, const DstState &StateIn) { + DstStatePrinter P(BC); + LLVM_DEBUG({ + dbgs() << " DataflowDstSafetyAnalysis::Confluence(\n"; + dbgs() << " State 1: "; + P.print(dbgs(), StateOut); + dbgs() << "\n"; + dbgs() << " State 2: "; + P.print(dbgs(), StateIn); + dbgs() << ")\n"; + }); + + StateOut.merge(StateIn); + + LLVM_DEBUG({ + dbgs() << " merged state: "; + P.print(dbgs(), StateOut); + dbgs() << "\n"; + }); + } + + StringRef getAnnotationName() const { return "DataflowDstSafetyAnalysis"; } +}; + +class CFGUnawareDstSafetyAnalysis : public DstSafetyAnalysis, + public CFGUnawareAnalysis { + using DstSafetyAnalysis::BC; + BinaryFunction &BF; + +public: + CFGUnawareDstSafetyAnalysis(BinaryFunction &BF, + MCPlusBuilder::AllocatorIdTy AllocId, + ArrayRef RegsToTrackInstsFor) + : DstSafetyAnalysis(BF, RegsToTrackInstsFor), + CFGUnawareAnalysis(BF, AllocId, "CFGUnawareDstSafetyAnalysis"), BF(BF) { + } + + void run() override { + DstState S = createUnsafeState(); + for (auto &I : llvm::reverse(BF.instrs())) { + MCInst &Inst = I.second; + if (BC.MIB->isCFI(Inst)) + continue; + + // If Inst can change the control flow, we cannot be sure that the next + // instruction (to be executed in analyzed program) is the one processed + // on the previous iteration, thus pessimistically reset S before + // starting to analyze Inst. + if (BC.MIB->isCall(Inst) || BC.MIB->isBranch(Inst) || + BC.MIB->isReturn(Inst)) { + LLVM_DEBUG({ traceInst(BC, "Control flow instruction", Inst); }); + S = createUnsafeState(); + } + + // Attach the state *after* this instruction executes. + setState(Inst, S); + + // Compute the next state. + S = computeNext(Inst, S); + } + } + + const DstState &getStateAfter(const MCInst &Inst) const override { + return getState(Inst); + } +}; + +std::shared_ptr +DstSafetyAnalysis::create(BinaryFunction &BF, + MCPlusBuilder::AllocatorIdTy AllocId, + ArrayRef RegsToTrackInstsFor) { + if (BF.hasCFG()) + return std::make_shared(BF, AllocId, + RegsToTrackInstsFor); + return std::make_shared(BF, AllocId, + RegsToTrackInstsFor); +} + // This function could return PartialReport, but currently T is always // MCPhysReg, even though it is an implementation detail. static PartialReport make_generic_report(MCInstReference Location, @@ -808,6 +1313,37 @@ shouldReportSigningOracle(const BinaryContext &BC, const MCInstReference &Inst, return make_gadget_report(SigningOracleKind, Inst, *SignedReg); } +static std::optional> +shouldReportAuthOracle(const BinaryContext &BC, const MCInstReference &Inst, + const DstState &S) { + static const GadgetKind AuthOracleKind("authentication oracle found"); + + bool IsChecked = false; + std::optional AuthReg = + BC.MIB->getWrittenAuthenticatedReg(Inst, IsChecked); + if (!AuthReg || IsChecked) + return std::nullopt; + + LLVM_DEBUG({ + traceInst(BC, "Found auth inst", Inst); + traceReg(BC, "Authenticated reg", *AuthReg); + }); + + if (S.empty()) { + LLVM_DEBUG({ dbgs() << " DstState is empty!\n"; }); + return make_generic_report( + Inst, "Warning: no state computed for an authentication instruction " + "(possibly unreachable)"); + } + + LLVM_DEBUG( + { traceRegMask(BC, "safe output registers", S.CannotEscapeUnchecked); }); + if (S.CannotEscapeUnchecked[*AuthReg]) + return std::nullopt; + + return make_gadget_report(AuthOracleKind, Inst, *AuthReg); +} + template static void iterateOverInstrs(BinaryFunction &BF, T Fn) { if (BF.hasCFG()) { for (BinaryBasicBlock &BB : BF) @@ -840,6 +1376,9 @@ void FunctionAnalysisContext::findUnsafeUses( }); iterateOverInstrs(BF, [&](MCInstReference Inst) { + if (BC.MIB->isCFI(Inst)) + return; + const SrcState &S = Analysis->getStateBefore(Inst); // If non-empty state was never propagated from the entry basic block @@ -889,6 +1428,55 @@ void FunctionAnalysisContext::augmentUnsafeUseReports( } } +void FunctionAnalysisContext::findUnsafeDefs( + SmallVector> &Reports) { + if (PacRetGadgetsOnly) + return; + + auto Analysis = DstSafetyAnalysis::create(BF, AllocatorId, {}); + LLVM_DEBUG({ dbgs() << "Running dst register safety analysis...\n"; }); + Analysis->run(); + LLVM_DEBUG({ + dbgs() << "After dst register safety analysis:\n"; + BF.dump(); + }); + + iterateOverInstrs(BF, [&](MCInstReference Inst) { + if (BC.MIB->isCFI(Inst)) + return; + + const DstState &S = Analysis->getStateAfter(Inst); + + if (auto Report = shouldReportAuthOracle(BC, Inst, S)) + Reports.push_back(*Report); + }); +} + +void FunctionAnalysisContext::augmentUnsafeDefReports( + ArrayRef> Reports) { + SmallVector RegsToTrack = collectRegsToTrack(Reports); + // Re-compute the analysis with register tracking. + auto Analysis = DstSafetyAnalysis::create(BF, AllocatorId, RegsToTrack); + LLVM_DEBUG( + { dbgs() << "\nRunning detailed dst register safety analysis...\n"; }); + Analysis->run(); + LLVM_DEBUG({ + dbgs() << "After detailed dst register safety analysis:\n"; + BF.dump(); + }); + + // Augment gadget reports. + for (auto &Report : Reports) { + MCInstReference Location = Report.Issue->Location; + LLVM_DEBUG({ traceInst(BC, "Attaching leakage info to", Location); }); + assert(Report.RequestedDetails && + "Should be removed by handleSimpleReports"); + auto DetailedInfo = std::make_shared( + Analysis->getLeakingInsts(Location, BF, *Report.RequestedDetails)); + Result.Diagnostics.emplace_back(Report.Issue, DetailedInfo); + } +} + void FunctionAnalysisContext::handleSimpleReports( SmallVector> &Reports) { // Before re-running the detailed analysis, process the reports which do not @@ -912,6 +1500,12 @@ void FunctionAnalysisContext::run() { handleSimpleReports(UnsafeUses); if (!UnsafeUses.empty()) augmentUnsafeUseReports(UnsafeUses); + + SmallVector> UnsafeDefs; + findUnsafeDefs(UnsafeDefs); + handleSimpleReports(UnsafeDefs); + if (!UnsafeDefs.empty()) + augmentUnsafeDefReports(UnsafeDefs); } void Analysis::runOnFunction(BinaryFunction &BF, @@ -1015,6 +1609,12 @@ void ClobberingInfo::print(raw_ostream &OS, printRelatedInstrs(OS, Location, ClobberingInstrs); } +void LeakageInfo::print(raw_ostream &OS, const MCInstReference Location) const { + OS << " The " << LeakingInstrs.size() + << " instructions that leak the affected registers are:\n"; + printRelatedInstrs(OS, Location, LeakingInstrs); +} + void GenericDiagnostic::generateReport(raw_ostream &OS, const BinaryContext &BC) const { printBasicInfo(OS, BC, Text); diff --git a/bolt/lib/Passes/RetpolineInsertion.cpp b/bolt/lib/Passes/RetpolineInsertion.cpp index 98e5a8fba645..bda26206e16c 100644 --- a/bolt/lib/Passes/RetpolineInsertion.cpp +++ b/bolt/lib/Passes/RetpolineInsertion.cpp @@ -195,7 +195,7 @@ std::string createRetpolineFunctionTag(BinaryContext &BC, TagOS << "+"; if (MemRef.DispExpr) - MemRef.DispExpr->print(TagOS, BC.AsmInfo.get()); + BC.AsmInfo->printExpr(TagOS, *MemRef.DispExpr); else TagOS << MemRef.DispImm; diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp index a253522e4fb1..7ad4e6a2e141 100644 --- a/bolt/lib/Profile/BoltAddressTranslation.cpp +++ b/bolt/lib/Profile/BoltAddressTranslation.cpp @@ -546,7 +546,7 @@ BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress, return Res; for (auto Iter = FromIter; Iter != ToIter;) { - const uint32_t Src = Iter->first; + const uint32_t Src = Iter->second >> 1; if (Iter->second & BRANCHENTRY) { ++Iter; continue; @@ -557,7 +557,7 @@ BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress, ++Iter; if (Iter->second & BRANCHENTRY) break; - Res.emplace_back(Src, Iter->first); + Res.emplace_back(Src, Iter->second >> 1); } return Res; diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 308346e5d02c..5c8af3710720 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -49,6 +49,9 @@ static cl::opt cl::desc("aggregate basic samples (without LBR info)"), cl::cat(AggregatorCategory)); +cl::opt ArmSPE("spe", cl::desc("Enable Arm SPE mode."), + cl::cat(AggregatorCategory)); + static cl::opt ITraceAggregation("itrace", cl::desc("Generate LBR info with perf itrace argument"), @@ -61,6 +64,12 @@ FilterMemProfile("filter-mem-profile", cl::init(true), cl::cat(AggregatorCategory)); +static cl::opt ParseMemProfile( + "parse-mem-profile", + cl::desc("enable memory profile parsing if it's present in the input data, " + "on by default unless `--itrace` is set."), + cl::init(true), cl::cat(AggregatorCategory)); + static cl::opt FilterPID("pid", cl::desc("only use samples from process with specified PID"), @@ -175,12 +184,26 @@ void DataAggregator::start() { findPerfExecutable(); + if (opts::ArmSPE) { + // pid from_ip to_ip flags + // where flags could be: + // P/M: whether branch was Predicted or Mispredicted. + // N: optionally appears when the branch was Not-Taken (ie fall-through) + // 12345 0x123/0x456/PN/-/-/8/RET/- + opts::ITraceAggregation = "bl"; + opts::ParseMemProfile = true; + opts::BasicAggregation = false; + } + if (opts::BasicAggregation) { - launchPerfProcess("events without LBR", - MainEventsPPI, + launchPerfProcess("events without LBR", MainEventsPPI, "script -F pid,event,ip", - /*Wait = */false); + /*Wait = */ false); } else if (!opts::ITraceAggregation.empty()) { + // Disable parsing memory profile from trace data, unless requested by user. + if (!opts::ParseMemProfile.getNumOccurrences()) + opts::ParseMemProfile = false; + std::string ItracePerfScriptArgs = llvm::formatv( "script -F pid,brstack --itrace={0}", opts::ITraceAggregation); launchPerfProcess("branch events with itrace", MainEventsPPI, @@ -191,12 +214,9 @@ void DataAggregator::start() { /*Wait = */ false); } - // Note: we launch script for mem events regardless of the option, as the - // command fails fairly fast if mem events were not collected. - launchPerfProcess("mem events", - MemEventsPPI, - "script -F pid,event,addr,ip", - /*Wait = */false); + if (opts::ParseMemProfile) + launchPerfProcess("mem events", MemEventsPPI, "script -F pid,event,addr,ip", + /*Wait = */ false); launchPerfProcess("process events", MMapEventsPPI, "script --show-mmap-events --no-itrace", @@ -217,7 +237,8 @@ void DataAggregator::abort() { sys::Wait(TaskEventsPPI.PI, 1, &Error); sys::Wait(MMapEventsPPI.PI, 1, &Error); sys::Wait(MainEventsPPI.PI, 1, &Error); - sys::Wait(MemEventsPPI.PI, 1, &Error); + if (opts::ParseMemProfile) + sys::Wait(MemEventsPPI.PI, 1, &Error); deleteTempFiles(); @@ -506,7 +527,8 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) { errs() << "PERF2BOLT: failed to parse samples\n"; // Special handling for memory events - if (!prepareToParse("mem events", MemEventsPPI, MemEventsErrorCallback)) + if (opts::ParseMemProfile && + !prepareToParse("mem events", MemEventsPPI, MemEventsErrorCallback)) if (const std::error_code EC = parseMemEvents()) errs() << "PERF2BOLT: failed to parse memory events: " << EC.message() << '\n'; @@ -514,6 +536,9 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) { deleteTempFiles(); heatmap: + // Sort parsed traces for faster processing. + llvm::sort(Traces, llvm::less_first()); + if (!opts::HeatmapMode) return Error::success(); @@ -589,8 +614,7 @@ void DataAggregator::processProfile(BinaryContext &BC) { llvm::stable_sort(MemEvents.second.Data); // Release intermediate storage. - clear(BranchLBRs); - clear(FallthroughLBRs); + clear(Traces); clear(BasicSamples); clear(MemSamples); } @@ -718,50 +742,54 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, return true; } +bool DataAggregator::checkReturn(uint64_t Addr) { + auto isReturn = [&](auto MI) { return MI && BC->MIB->isReturn(*MI); }; + if (llvm::is_contained(Returns, Addr)) + return true; + + BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr); + if (!Func) + return false; + + const uint64_t Offset = Addr - Func->getAddress(); + if (Func->hasInstructions() + ? isReturn(Func->getInstructionAtOffset(Offset)) + : isReturn(Func->disassembleInstructionAtOffset(Offset))) { + Returns.emplace(Addr); + return true; + } + return false; +} + bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds) { - // Returns whether \p Offset in \p Func contains a return instruction. - auto checkReturn = [&](const BinaryFunction &Func, const uint64_t Offset) { - auto isReturn = [&](auto MI) { return MI && BC->MIB->isReturn(*MI); }; - return Func.hasInstructions() - ? isReturn(Func.getInstructionAtOffset(Offset)) - : isReturn(Func.disassembleInstructionAtOffset(Offset)); - }; - // Mutates \p Addr to an offset into the containing function, performing BAT // offset translation and parent lookup. // - // Returns the containing function (or BAT parent) and whether the address - // corresponds to a return (if \p IsFrom) or a call continuation (otherwise). + // Returns the containing function (or BAT parent). auto handleAddress = [&](uint64_t &Addr, bool IsFrom) { BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr); if (!Func) { Addr = 0; - return std::pair{Func, false}; + return Func; } Addr -= Func->getAddress(); - bool IsRet = IsFrom && checkReturn(*Func, Addr); - if (BAT) Addr = BAT->translate(Func->getAddress(), Addr, IsFrom); if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) - Func = ParentFunc; + return ParentFunc; - return std::pair{Func, IsRet}; + return Func; }; - auto [FromFunc, IsReturn] = handleAddress(From, /*IsFrom*/ true); - auto [ToFunc, _] = handleAddress(To, /*IsFrom*/ false); + BinaryFunction *FromFunc = handleAddress(From, /*IsFrom*/ true); + BinaryFunction *ToFunc = handleAddress(To, /*IsFrom*/ false); if (!FromFunc && !ToFunc) return false; - // Ignore returns. - if (IsReturn) - return true; - // Treat recursive control transfers as inter-branches. if (FromFunc == ToFunc && To != 0) { recordBranch(*FromFunc, From, To, Count, Mispreds); @@ -771,37 +799,20 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, return doInterBranch(FromFunc, ToFunc, From, To, Count, Mispreds); } -bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, - uint64_t Count) { - BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(First.To); - BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(Second.From); +bool DataAggregator::doTrace(const Trace &Trace, uint64_t Count, + bool IsReturn) { + const uint64_t From = Trace.From, To = Trace.To; + BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(From); + BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(To); + NumTraces += Count; if (!FromFunc || !ToFunc) { - LLVM_DEBUG({ - dbgs() << "Out of range trace starting in "; - if (FromFunc) - dbgs() << formatv("{0} @ {1:x}", *FromFunc, - First.To - FromFunc->getAddress()); - else - dbgs() << Twine::utohexstr(First.To); - dbgs() << " and ending in "; - if (ToFunc) - dbgs() << formatv("{0} @ {1:x}", *ToFunc, - Second.From - ToFunc->getAddress()); - else - dbgs() << Twine::utohexstr(Second.From); - dbgs() << '\n'; - }); + LLVM_DEBUG(dbgs() << "Out of range trace " << Trace << '\n'); NumLongRangeTraces += Count; return false; } if (FromFunc != ToFunc) { + LLVM_DEBUG(dbgs() << "Invalid trace " << Trace << '\n'); NumInvalidTraces += Count; - LLVM_DEBUG({ - dbgs() << "Invalid trace starting in " << FromFunc->getPrintName() - << formatv(" @ {0:x}", First.To - FromFunc->getAddress()) - << " and ending in " << ToFunc->getPrintName() - << formatv(" @ {0:x}\n", Second.From - ToFunc->getAddress()); - }); return false; } @@ -809,51 +820,37 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc); if (!ParentFunc) ParentFunc = FromFunc; - ParentFunc->SampleCountInBytes += Count * (Second.From - First.To); + ParentFunc->SampleCountInBytes += Count * (To - From); const uint64_t FuncAddress = FromFunc->getAddress(); std::optional FTs = BAT && BAT->isBATFunction(FuncAddress) - ? BAT->getFallthroughsInTrace(FuncAddress, First.To, Second.From) - : getFallthroughsInTrace(*FromFunc, First, Second, Count); + ? BAT->getFallthroughsInTrace(FuncAddress, From - IsReturn, To) + : getFallthroughsInTrace(*FromFunc, Trace, Count, IsReturn); if (!FTs) { - LLVM_DEBUG( - dbgs() << "Invalid trace starting in " << FromFunc->getPrintName() - << " @ " << Twine::utohexstr(First.To - FromFunc->getAddress()) - << " and ending in " << ToFunc->getPrintName() << " @ " - << ToFunc->getPrintName() << " @ " - << Twine::utohexstr(Second.From - ToFunc->getAddress()) << '\n'); + LLVM_DEBUG(dbgs() << "Invalid trace " << Trace << '\n'); NumInvalidTraces += Count; return false; } LLVM_DEBUG(dbgs() << "Processing " << FTs->size() << " fallthroughs for " - << FromFunc->getPrintName() << ":" - << Twine::utohexstr(First.To) << " to " - << Twine::utohexstr(Second.From) << ".\n"); - for (auto [From, To] : *FTs) { - if (BAT) { - From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); - To = BAT->translate(FromFunc->getAddress(), To, /*IsBranchSrc=*/false); - } + << FromFunc->getPrintName() << ":" << Trace << '\n'); + for (const auto &[From, To] : *FTs) doIntraBranch(*ParentFunc, From, To, Count, false); - } return true; } std::optional, 16>> -DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, - const LBREntry &FirstLBR, - const LBREntry &SecondLBR, - uint64_t Count) const { +DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, const Trace &Trace, + uint64_t Count, bool IsReturn) const { SmallVector, 16> Branches; BinaryContext &BC = BF.getBinaryContext(); // Offsets of the trace within this function. - const uint64_t From = FirstLBR.To - BF.getAddress(); - const uint64_t To = SecondLBR.From - BF.getAddress(); + const uint64_t From = Trace.From - BF.getAddress(); + const uint64_t To = Trace.To - BF.getAddress(); if (From > To) return std::nullopt; @@ -880,8 +877,9 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, // Adjust FromBB if the first LBR is a return from the last instruction in // the previous block (that instruction should be a call). - if (From == FromBB->getOffset() && !BF.containsAddress(FirstLBR.From) && - !FromBB->isEntryPoint() && !FromBB->isLandingPad()) { + if (Trace.Branch != Trace::FT_ONLY && !BF.containsAddress(Trace.Branch) && + From == FromBB->getOffset() && + (IsReturn ? From : !(FromBB->isEntryPoint() || FromBB->isLandingPad()))) { const BinaryBasicBlock *PrevBB = BF.getLayout().getBlock(FromBB->getIndex() - 1); if (PrevBB->getSuccessor(FromBB->getLabel())) { @@ -889,10 +887,9 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, if (Instr && BC.MIB->isCall(*Instr)) FromBB = PrevBB; else - LLVM_DEBUG(dbgs() << "invalid incoming LBR (no call): " << FirstLBR - << '\n'); + LLVM_DEBUG(dbgs() << "invalid trace (no call): " << Trace << '\n'); } else { - LLVM_DEBUG(dbgs() << "invalid incoming LBR: " << FirstLBR << '\n'); + LLVM_DEBUG(dbgs() << "invalid trace: " << Trace << '\n'); } } @@ -911,9 +908,7 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, // Check for bad LBRs. if (!BB->getSuccessor(NextBB->getLabel())) { - LLVM_DEBUG(dbgs() << "no fall-through for the trace:\n" - << " " << FirstLBR << '\n' - << " " << SecondLBR << '\n'); + LLVM_DEBUG(dbgs() << "no fall-through for the trace: " << Trace << '\n'); return std::nullopt; } @@ -1002,9 +997,22 @@ ErrorOr DataAggregator::parseLBREntry() { if (std::error_code EC = MispredStrRes.getError()) return EC; StringRef MispredStr = MispredStrRes.get(); - if (MispredStr.size() != 1 || - (MispredStr[0] != 'P' && MispredStr[0] != 'M' && MispredStr[0] != '-')) { - reportError("expected single char for mispred bit"); + // SPE brstack mispredicted flags might be up to two characters long: + // 'PN' or 'MN'. Where 'N' optionally appears. + bool ValidStrSize = opts::ArmSPE + ? MispredStr.size() >= 1 && MispredStr.size() <= 2 + : MispredStr.size() == 1; + bool SpeTakenBitErr = + (opts::ArmSPE && MispredStr.size() == 2 && MispredStr[1] != 'N'); + bool PredictionBitErr = + !ValidStrSize || + (MispredStr[0] != 'P' && MispredStr[0] != 'M' && MispredStr[0] != '-'); + if (SpeTakenBitErr) + reportError("expected 'N' as SPE prediction bit for a not-taken branch"); + if (PredictionBitErr) + reportError("expected 'P', 'M' or '-' char as a prediction bit"); + + if (SpeTakenBitErr || PredictionBitErr) { Diag << "Found: " << MispredStr << "\n"; return make_error_code(llvm::errc::io_error); } @@ -1210,22 +1218,25 @@ ErrorOr DataAggregator::parseLocationOrOffset() { std::error_code DataAggregator::parseAggregatedLBREntry() { enum AggregatedLBREntry : char { INVALID = 0, - EVENT_NAME, // E - TRACE, // T - SAMPLE, // S - BRANCH, // B - FT, // F - FT_EXTERNAL_ORIGIN // f + EVENT_NAME, // E + TRACE, // T + RETURN, // R + SAMPLE, // S + BRANCH, // B + FT, // F + FT_EXTERNAL_ORIGIN, // f + FT_EXTERNAL_RETURN // r } Type = INVALID; - // The number of fields to parse, set based on Type. + /// The number of fields to parse, set based on \p Type. int AddrNum = 0; int CounterNum = 0; - // Storage for parsed fields. + /// Storage for parsed fields. StringRef EventName; std::optional Addr[3]; int64_t Counters[2] = {0}; + /// Parse strings: record type and optionally an event name. while (Type == INVALID || Type == EVENT_NAME) { while (checkAndConsumeFS()) { } @@ -1242,23 +1253,26 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { Type = StringSwitch(Str) .Case("T", TRACE) + .Case("R", RETURN) .Case("S", SAMPLE) .Case("E", EVENT_NAME) .Case("B", BRANCH) .Case("F", FT) .Case("f", FT_EXTERNAL_ORIGIN) + .Case("r", FT_EXTERNAL_RETURN) .Default(INVALID); if (Type == INVALID) { - reportError("expected T, S, E, B, F or f"); + reportError("expected T, R, S, E, B, F, f or r"); return make_error_code(llvm::errc::io_error); } using SSI = StringSwitch; - AddrNum = SSI(Str).Case("T", 3).Case("S", 1).Case("E", 0).Default(2); + AddrNum = SSI(Str).Cases("T", "R", 3).Case("S", 1).Case("E", 0).Default(2); CounterNum = SSI(Str).Case("B", 2).Case("E", 0).Default(1); } + /// Parse locations depending on entry type, recording them in \p Addr array. for (int I = 0; I < AddrNum; ++I) { while (checkAndConsumeFS()) { } @@ -1268,6 +1282,7 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { Addr[I] = AddrOrErr.get(); } + /// Parse counters depending on entry type. for (int I = 0; I < CounterNum; ++I) { while (checkAndConsumeFS()) { } @@ -1278,11 +1293,13 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { Counters[I] = CountOrErr.get(); } + /// Expect end of line here. if (!checkAndConsumeNewLine()) { reportError("expected end of line"); return make_error_code(llvm::errc::io_error); } + /// Record event name into \p EventNames and return. if (Type == EVENT_NAME) { EventNames.insert(EventName); return std::error_code(); @@ -1296,6 +1313,7 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { int64_t Count = Counters[0]; int64_t Mispreds = Counters[1]; + /// Record basic IP sample into \p BasicSamples and return. if (Type == SAMPLE) { BasicSamples[FromOffset] += Count; NumTotalSamples += Count; @@ -1307,30 +1325,39 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { if (ToFunc) ToFunc->setHasProfileAvailable(); - Trace Trace(FromOffset, ToOffset); - // Taken trace - if (Type == TRACE || Type == BRANCH) { - TakenBranchInfo &Info = BranchLBRs[Trace]; - Info.TakenCount += Count; - Info.MispredCount += Mispreds; + /// For fall-through types, adjust locations to match Trace container. + if (Type == FT || Type == FT_EXTERNAL_ORIGIN || Type == FT_EXTERNAL_RETURN) { + Addr[2] = Location(Addr[1]->Offset); // Trace To + Addr[1] = Location(Addr[0]->Offset); // Trace From + // Put a magic value into Trace Branch to differentiate from a full trace: + if (Type == FT) + Addr[0] = Location(Trace::FT_ONLY); + else if (Type == FT_EXTERNAL_ORIGIN) + Addr[0] = Location(Trace::FT_EXTERNAL_ORIGIN); + else if (Type == FT_EXTERNAL_RETURN) + Addr[0] = Location(Trace::FT_EXTERNAL_RETURN); + else + llvm_unreachable("Unexpected fall-through type"); + } - NumTotalSamples += Count; - } - // Construct fallthrough part of the trace - if (Type == TRACE) { - const uint64_t TraceFtEndOffset = Addr[2]->Offset; - Trace.From = ToOffset; - Trace.To = TraceFtEndOffset; - Type = FromFunc == ToFunc ? FT : FT_EXTERNAL_ORIGIN; - } - // Add fallthrough trace - if (Type != BRANCH) { - FTInfo &Info = FallthroughLBRs[Trace]; - (Type == FT ? Info.InternCount : Info.ExternCount) += Count; + /// For branch type, mark Trace To to differentiate from a full trace. + if (Type == BRANCH) + Addr[2] = Location(Trace::BR_ONLY); - NumTraces += Count; + if (Type == RETURN) { + if (!Addr[0]->Offset) + Addr[0]->Offset = Trace::FT_EXTERNAL_RETURN; + else + Returns.emplace(Addr[0]->Offset); } + /// Record a trace. + Trace T{Addr[0]->Offset, Addr[1]->Offset, Addr[2]->Offset}; + TakenBranchInfo TI{(uint64_t)Count, (uint64_t)Mispreds}; + Traces.emplace_back(T, TI); + + NumTotalSamples += Count; + return std::error_code(); } @@ -1341,7 +1368,7 @@ bool DataAggregator::ignoreKernelInterrupt(LBREntry &LBR) const { std::error_code DataAggregator::printLBRHeatMap() { outs() << "PERF2BOLT: parse branch events...\n"; - NamedRegionTimer T("parseBranch", "Parsing branch events", TimerGroupName, + NamedRegionTimer T("buildHeatmap", "Building heatmap", TimerGroupName, TimerGroupDesc, opts::TimeAggregator); if (BC->IsLinuxKernel) { @@ -1377,12 +1404,9 @@ std::error_code DataAggregator::printLBRHeatMap() { // Register basic samples and perf LBR addresses not covered by fallthroughs. for (const auto &[PC, Hits] : BasicSamples) HM.registerAddress(PC, Hits); - for (const auto &LBR : FallthroughLBRs) { - const Trace &Trace = LBR.first; - const FTInfo &Info = LBR.second; - HM.registerAddressRange(Trace.From, Trace.To, - Info.InternCount + Info.ExternCount); - } + for (const auto &[Trace, Info] : Traces) + if (Trace.To != Trace::BR_ONLY) + HM.registerAddressRange(Trace.From, Trace.To, Info.TakenCount); if (HM.getNumInvalidRanges()) outs() << "HEATMAP: invalid traces: " << HM.getNumInvalidRanges() << '\n'; @@ -1428,22 +1452,10 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample, // chronological order) if (NeedsSkylakeFix && NumEntry <= 2) continue; - if (NextLBR) { - // Record fall-through trace. - const uint64_t TraceFrom = LBR.To; - const uint64_t TraceTo = NextLBR->From; - const BinaryFunction *TraceBF = - getBinaryFunctionContainingAddress(TraceFrom); - FTInfo &Info = FallthroughLBRs[Trace(TraceFrom, TraceTo)]; - if (TraceBF && TraceBF->containsAddress(LBR.From)) - ++Info.InternCount; - else - ++Info.ExternCount; - ++NumTraces; - } + uint64_t TraceTo = NextLBR ? NextLBR->From : Trace::BR_ONLY; NextLBR = &LBR; - TakenBranchInfo &Info = BranchLBRs[Trace(LBR.From, LBR.To)]; + TakenBranchInfo &Info = TraceMap[Trace{LBR.From, LBR.To, TraceTo}]; ++Info.TakenCount; Info.MispredCount += LBR.Mispred; } @@ -1518,7 +1530,9 @@ void DataAggregator::printBranchStacksDiagnostics( } std::error_code DataAggregator::parseBranchEvents() { - outs() << "PERF2BOLT: parse branch events...\n"; + std::string BranchEventTypeStr = + opts::ArmSPE ? "SPE branch events in LBR-format" : "branch events"; + outs() << "PERF2BOLT: parse " << BranchEventTypeStr << "...\n"; NamedRegionTimer T("parseBranch", "Parsing branch events", TimerGroupName, TimerGroupDesc, opts::TimeAggregator); @@ -1546,7 +1560,8 @@ std::error_code DataAggregator::parseBranchEvents() { } NumEntries += Sample.LBR.size(); - if (BAT && Sample.LBR.size() == 32 && !NeedsSkylakeFix) { + if (this->BC->isX86() && BAT && Sample.LBR.size() == 32 && + !NeedsSkylakeFix) { errs() << "PERF2BOLT-WARNING: using Intel Skylake bug workaround\n"; NeedsSkylakeFix = true; } @@ -1554,10 +1569,14 @@ std::error_code DataAggregator::parseBranchEvents() { parseLBRSample(Sample, NeedsSkylakeFix); } - for (const Trace &Trace : llvm::make_first_range(BranchLBRs)) - for (const uint64_t Addr : {Trace.From, Trace.To}) + Traces.reserve(TraceMap.size()); + for (const auto &[Trace, Info] : TraceMap) { + Traces.emplace_back(Trace, Info); + for (const uint64_t Addr : {Trace.Branch, Trace.From}) if (BinaryFunction *BF = getBinaryFunctionContainingAddress(Addr)) BF->setHasProfileAvailable(); + } + clear(TraceMap); outs() << "PERF2BOLT: read " << NumSamples << " samples and " << NumEntries << " LBR entries\n"; @@ -1565,10 +1584,18 @@ std::error_code DataAggregator::parseBranchEvents() { if (NumSamples && NumSamplesNoLBR == NumSamples) { // Note: we don't know if perf2bolt is being used to parse memory samples // at this point. In this case, it is OK to parse zero LBRs. - errs() << "PERF2BOLT-WARNING: all recorded samples for this binary lack " - "LBR. Record profile with perf record -j any or run perf2bolt " - "in no-LBR mode with -nl (the performance improvement in -nl " - "mode may be limited)\n"; + if (!opts::ArmSPE) + errs() + << "PERF2BOLT-WARNING: all recorded samples for this binary lack " + "LBR. Record profile with perf record -j any or run perf2bolt " + "in no-LBR mode with -nl (the performance improvement in -nl " + "mode may be limited)\n"; + else + errs() + << "PERF2BOLT-WARNING: All recorded samples for this binary lack " + "SPE brstack entries. Make sure you are running Linux perf 6.14 " + "or later, otherwise you get zero samples. Record the profile " + "with: perf record -e 'arm_spe_0/branch_filter=1/'."; } else { printBranchStacksDiagnostics(NumTotalSamples - NumSamples); } @@ -1582,23 +1609,15 @@ void DataAggregator::processBranchEvents() { NamedRegionTimer T("processBranch", "Processing branch events", TimerGroupName, TimerGroupDesc, opts::TimeAggregator); - for (const auto &AggrLBR : FallthroughLBRs) { - const Trace &Loc = AggrLBR.first; - const FTInfo &Info = AggrLBR.second; - LBREntry First{Loc.From, Loc.From, false}; - LBREntry Second{Loc.To, Loc.To, false}; - if (Info.InternCount) - doTrace(First, Second, Info.InternCount); - if (Info.ExternCount) { - First.From = 0; - doTrace(First, Second, Info.ExternCount); - } - } - - for (const auto &AggrLBR : BranchLBRs) { - const Trace &Loc = AggrLBR.first; - const TakenBranchInfo &Info = AggrLBR.second; - doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount); + Returns.emplace(Trace::FT_EXTERNAL_RETURN); + for (const auto &[Trace, Info] : Traces) { + bool IsReturn = checkReturn(Trace.Branch); + // Ignore returns. + if (!IsReturn && Trace.Branch != Trace::FT_ONLY && + Trace.Branch != Trace::FT_EXTERNAL_ORIGIN) + doBranch(Trace.Branch, Trace.From, Info.TakenCount, Info.MispredCount); + if (Trace.To != Trace::BR_ONLY) + doTrace(Trace, Info.TakenCount, IsReturn); } printBranchSamplesDiagnostics(); } diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index 5a5e044184d0..174721a3a053 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -432,25 +432,33 @@ public: }; Error LinuxKernelRewriter::detectLinuxKernelVersion() { - if (BinaryData *BD = BC.getBinaryDataByName("linux_banner")) { - const BinarySection &Section = BD->getSection(); - const std::string S = - Section.getContents().substr(BD->getOffset(), BD->getSize()).str(); + // Check for global and local linux_banner symbol. + BinaryData *BD = BC.getBinaryDataByName("linux_banner"); + if (!BD) + BD = BC.getBinaryDataByName("linux_banner/1"); - const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---"); - std::smatch Match; - if (std::regex_search(S, Match, Re)) { - const unsigned Major = std::stoi(Match[2].str()); - const unsigned Minor = std::stoi(Match[3].str()); - const unsigned Rev = Match[5].matched ? std::stoi(Match[5].str()) : 0; - LinuxKernelVersion = LKVersion(Major, Minor, Rev); - BC.outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str() - << "\n"; - return Error::success(); - } + if (!BD) + return createStringError(errc::executable_format_error, + "unable to locate linux_banner"); + + const BinarySection &Section = BD->getSection(); + const std::string S = + Section.getContents().substr(BD->getOffset(), BD->getSize()).str(); + + const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---"); + std::smatch Match; + if (std::regex_search(S, Match, Re)) { + const unsigned Major = std::stoi(Match[2].str()); + const unsigned Minor = std::stoi(Match[3].str()); + const unsigned Rev = Match[5].matched ? std::stoi(Match[5].str()) : 0; + LinuxKernelVersion = LKVersion(Major, Minor, Rev); + BC.outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str() + << "\n"; + return Error::success(); } + return createStringError(errc::executable_format_error, - "Linux kernel version is unknown"); + "Linux kernel version is unknown: " + S); } void LinuxKernelRewriter::processLKSections() { diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index e1aa00a3d749..93bd93b6cb98 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -780,14 +780,6 @@ void RewriteInstance::discoverFileObjects() { // For local symbols we want to keep track of associated FILE symbol name for // disambiguation by combined name. - StringRef FileSymbolName; - bool SeenFileName = false; - struct SymbolRefHash { - size_t operator()(SymbolRef const &S) const { - return std::hash{}(S.getRawDataRefImpl().p); - } - }; - std::unordered_map SymbolToFileName; for (const ELFSymbolRef &Symbol : InputFile->symbols()) { Expected NameOrError = Symbol.getName(); if (NameOrError && NameOrError->starts_with("__asan_init")) { @@ -806,21 +798,8 @@ void RewriteInstance::discoverFileObjects() { if (cantFail(Symbol.getFlags()) & SymbolRef::SF_Undefined) continue; - if (cantFail(Symbol.getType()) == SymbolRef::ST_File) { + if (cantFail(Symbol.getType()) == SymbolRef::ST_File) FileSymbols.emplace_back(Symbol); - StringRef Name = - cantFail(std::move(NameOrError), "cannot get symbol name for file"); - // Ignore Clang LTO artificial FILE symbol as it is not always generated, - // and this uncertainty is causing havoc in function name matching. - if (Name == "ld-temp.o") - continue; - FileSymbolName = Name; - SeenFileName = true; - continue; - } - if (!FileSymbolName.empty() && - !(cantFail(Symbol.getFlags()) & SymbolRef::SF_Global)) - SymbolToFileName[Symbol] = FileSymbolName; } // Sort symbols in the file by value. Ignore symbols from non-allocatable @@ -1028,14 +1007,14 @@ void RewriteInstance::discoverFileObjects() { // The field is used for disambiguation of local symbols since there // could be identical function names coming from identical file names // (e.g. from different directories). - std::string AltPrefix; - auto SFI = SymbolToFileName.find(Symbol); - if (SymbolType == SymbolRef::ST_Function && SFI != SymbolToFileName.end()) - AltPrefix = Name + "/" + std::string(SFI->second); + auto SFI = llvm::upper_bound(FileSymbols, ELFSymbolRef(Symbol)); + if (SymbolType == SymbolRef::ST_Function && SFI != FileSymbols.begin()) { + StringRef FileSymbolName = cantFail(SFI[-1].getName()); + if (!FileSymbolName.empty()) + AlternativeName = NR.uniquify(Name + "/" + FileSymbolName.str()); + } UniqueName = NR.uniquify(Name); - if (!AltPrefix.empty()) - AlternativeName = NR.uniquify(AltPrefix); } uint64_t SymbolSize = ELFSymbolRef(Symbol).getSize(); @@ -1294,7 +1273,7 @@ void RewriteInstance::discoverFileObjects() { FDE->getAddressRange()); } - BC->setHasSymbolsWithFileName(SeenFileName); + BC->setHasSymbolsWithFileName(FileSymbols.size()); // Now that all the functions were created - adjust their boundaries. adjustFunctionBoundaries(); @@ -1567,6 +1546,11 @@ void RewriteInstance::registerFragments() { uint64_t ParentAddress{0}; + // Check if containing FILE symbol is BOLT emitted synthetic symbol marking + // local fragments of global parents. + if (cantFail(FSI[-1].getName()) == getBOLTFileSymbolName()) + goto registerParent; + // BOLT split fragment symbols are emitted just before the main function // symbol. for (ELFSymbolRef NextSymbol = Symbol; NextSymbol < StopSymbol; diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index eb1d9d8a1951..e6e0aeba3457 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -14,7 +14,7 @@ #include "AArch64MCSymbolizer.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "MCTargetDesc/AArch64FixupKinds.h" -#include "MCTargetDesc/AArch64MCExpr.h" +#include "MCTargetDesc/AArch64MCAsmInfo.h" #include "MCTargetDesc/AArch64MCTargetDesc.h" #include "Utils/AArch64BaseInfo.h" #include "bolt/Core/BinaryBasicBlock.h" @@ -179,13 +179,10 @@ public: bool equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B, CompFuncTy Comp) const override { - const auto &AArch64ExprA = cast(A); - const auto &AArch64ExprB = cast(B); - if (AArch64ExprA.getKind() != AArch64ExprB.getKind()) + if (A.getSpecifier() != B.getSpecifier()) return false; - return MCPlusBuilder::equals(*AArch64ExprA.getSubExpr(), - *AArch64ExprB.getSubExpr(), Comp); + return MCPlusBuilder::equals(*A.getSubExpr(), *B.getSubExpr(), Comp); } bool shortenInstruction(MCInst &, const MCSubtargetInfo &) const override { @@ -1084,7 +1081,7 @@ public: if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 || RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) { - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx); } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC || RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 || @@ -1092,7 +1089,7 @@ public: RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { // Never emit a GOT reloc, we handled this in // RewriteInstance::readRelocations(). - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx); } else { switch (RelType) { case ELF::R_AARCH64_ADD_ABS_LO12_NC: @@ -1106,18 +1103,18 @@ public: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx); case ELF::R_AARCH64_MOVW_UABS_G3: - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx); case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G2_NC: - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx); case ELF::R_AARCH64_MOVW_UABS_G1: case ELF::R_AARCH64_MOVW_UABS_G1_NC: - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx); case ELF::R_AARCH64_MOVW_UABS_G0: case ELF::R_AARCH64_MOVW_UABS_G0_NC: - return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx); + return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx); default: break; } @@ -1142,7 +1139,7 @@ public: } const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override { - auto *AArchExpr = dyn_cast(Expr); + auto *AArchExpr = dyn_cast(Expr); if (AArchExpr && AArchExpr->getSubExpr()) return getTargetSymbol(AArchExpr->getSubExpr()); @@ -1162,7 +1159,7 @@ public: } int64_t getTargetAddend(const MCExpr *Expr) const override { - auto *AArchExpr = dyn_cast(Expr); + auto *AArchExpr = dyn_cast(Expr); if (AArchExpr && AArchExpr->getSubExpr()) return getTargetAddend(AArchExpr->getSubExpr()); @@ -2030,9 +2027,8 @@ public: MCInst Inst; Inst.setOpcode(AArch64::MOVZXi); Inst.addOperand(MCOperand::createReg(AArch64::X16)); - Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( - MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), - AArch64MCExpr::VK_ABS_G3, *Ctx))); + Inst.addOperand(MCOperand::createExpr( + MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G3, *Ctx))); Inst.addOperand(MCOperand::createImm(0x30)); Seq.emplace_back(Inst); @@ -2040,9 +2036,8 @@ public: Inst.setOpcode(AArch64::MOVKXi); Inst.addOperand(MCOperand::createReg(AArch64::X16)); Inst.addOperand(MCOperand::createReg(AArch64::X16)); - Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( - MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), - AArch64MCExpr::VK_ABS_G2_NC, *Ctx))); + Inst.addOperand(MCOperand::createExpr( + MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G2_NC, *Ctx))); Inst.addOperand(MCOperand::createImm(0x20)); Seq.emplace_back(Inst); @@ -2050,9 +2045,8 @@ public: Inst.setOpcode(AArch64::MOVKXi); Inst.addOperand(MCOperand::createReg(AArch64::X16)); Inst.addOperand(MCOperand::createReg(AArch64::X16)); - Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( - MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), - AArch64MCExpr::VK_ABS_G1_NC, *Ctx))); + Inst.addOperand(MCOperand::createExpr( + MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G1_NC, *Ctx))); Inst.addOperand(MCOperand::createImm(0x10)); Seq.emplace_back(Inst); @@ -2060,9 +2054,8 @@ public: Inst.setOpcode(AArch64::MOVKXi); Inst.addOperand(MCOperand::createReg(AArch64::X16)); Inst.addOperand(MCOperand::createReg(AArch64::X16)); - Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( - MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), - AArch64MCExpr::VK_ABS_G0_NC, *Ctx))); + Inst.addOperand(MCOperand::createExpr( + MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G0_NC, *Ctx))); Inst.addOperand(MCOperand::createImm(0)); Seq.emplace_back(Inst); diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index 18be125d53ae..c7d664ab09d4 100644 --- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "MCTargetDesc/RISCVMCExpr.h" +#include "MCTargetDesc/RISCVMCAsmInfo.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "bolt/Core/MCPlusBuilder.h" #include "llvm/BinaryFormat/ELF.h" @@ -33,8 +33,8 @@ public: bool equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B, CompFuncTy Comp) const override { - const auto &RISCVExprA = cast(A); - const auto &RISCVExprB = cast(B); + const auto &RISCVExprA = cast(A); + const auto &RISCVExprB = cast(B); if (RISCVExprA.getSpecifier() != RISCVExprB.getSpecifier()) return false; @@ -245,7 +245,7 @@ public: MCContext *Ctx) { Inst.setOpcode(Opcode); Inst.clear(); - Inst.addOperand(MCOperand::createExpr(RISCVMCExpr::create( + Inst.addOperand(MCOperand::createExpr(MCSpecifierExpr::create( MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), ELF::R_RISCV_CALL_PLT, *Ctx))); } @@ -342,7 +342,7 @@ public: } const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override { - auto *RISCVExpr = dyn_cast(Expr); + auto *RISCVExpr = dyn_cast(Expr); if (RISCVExpr && RISCVExpr->getSubExpr()) return getTargetSymbol(RISCVExpr->getSubExpr()); @@ -435,19 +435,19 @@ public: case ELF::R_RISCV_TLS_GD_HI20: // The GOT is reused so no need to create GOT relocations case ELF::R_RISCV_PCREL_HI20: - return RISCVMCExpr::create(Expr, ELF::R_RISCV_PCREL_HI20, Ctx); + return MCSpecifierExpr::create(Expr, ELF::R_RISCV_PCREL_HI20, Ctx); case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_PCREL_LO12_S: - return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_PCREL_LO, Ctx); + return MCSpecifierExpr::create(Expr, RISCV::S_PCREL_LO, Ctx); case ELF::R_RISCV_HI20: - return RISCVMCExpr::create(Expr, ELF::R_RISCV_HI20, Ctx); + return MCSpecifierExpr::create(Expr, ELF::R_RISCV_HI20, Ctx); case ELF::R_RISCV_LO12_I: case ELF::R_RISCV_LO12_S: - return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_LO, Ctx); + return MCSpecifierExpr::create(Expr, RISCV::S_LO, Ctx); case ELF::R_RISCV_CALL: - return RISCVMCExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx); + return MCSpecifierExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx); case ELF::R_RISCV_CALL_PLT: - return RISCVMCExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx); + return MCSpecifierExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx); } } @@ -466,10 +466,10 @@ public: return false; const auto *ImmExpr = ImmOp.getExpr(); - if (!isa(ImmExpr)) + if (!isa(ImmExpr)) return false; - switch (cast(ImmExpr)->getSpecifier()) { + switch (cast(ImmExpr)->getSpecifier()) { default: return false; case ELF::R_RISCV_CALL_PLT: diff --git a/bolt/lib/Utils/CMakeLists.txt b/bolt/lib/Utils/CMakeLists.txt index efba6d54449d..94933644ef5e 100644 --- a/bolt/lib/Utils/CMakeLists.txt +++ b/bolt/lib/Utils/CMakeLists.txt @@ -6,12 +6,25 @@ set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc") set(generate_vcs_version_script "${LLVM_CMAKE_DIR}/GenerateVersionFromVCS.cmake") +if(llvm_vc AND LLVM_APPEND_VC_REV) + set(llvm_source_dir ${LLVM_MAIN_SRC_DIR}) +endif() +if(LLVM_VC_REPOSITORY AND LLVM_VC_REVISION) + set(llvm_source_dir ${LLVM_SOURCE_DIR}) + set(llvm_vc_repository ${LLVM_VC_REPOSITORY}) + set(llvm_vc_revision ${LLVM_VC_REVISION}) +endif() +if(bolt_vc AND LLVM_APPEND_VC_REV) + set(bolt_source_dir ${BOLT_SOURCE_DIR}) +endif() + # Create custom target to generate the VC revision include. add_custom_command(OUTPUT "${version_inc}" DEPENDS "${llvm_vc}" "${bolt_vc}" "${generate_vcs_version_script}" COMMAND ${CMAKE_COMMAND} "-DNAMES=BOLT" + "-DLLVM_SOURCE_DIR=${llvm_source_dir}" + "-DBOLT_SOURCE_DIR=${bolt_source_dir}" "-DHEADER_FILE=${version_inc}" - "-DBOLT_SOURCE_DIR=${BOLT_SOURCE_DIR}" "-DLLVM_VC_REPOSITORY=${llvm_vc_repository}" "-DLLVM_VC_REVISION=${llvm_vc_revision}" "-DLLVM_FORCE_VC_REVISION=${LLVM_FORCE_VC_REVISION}" diff --git a/bolt/test/AArch64/r_aarch64_prelxx.s b/bolt/test/AArch64/r_aarch64_prelxx.s index 5cbe2c50b294..39f74301cedf 100644 --- a/bolt/test/AArch64/r_aarch64_prelxx.s +++ b/bolt/test/AArch64/r_aarch64_prelxx.s @@ -5,7 +5,7 @@ // REQUIRES: system-linux // RUN: %clang %cflags -nostartfiles -nostdlib %s -o %t.exe -mlittle-endian \ -// RUN: -Wl,-q -Wl,-z,max-page-size=4 +// RUN: -Wl,-q -Wl,-z,max-page-size=4 -Wl,--no-relax // RUN: llvm-readelf -Wa %t.exe | FileCheck %s -check-prefix=CHECKPREL // CHECKPREL: R_AARCH64_PREL16 {{.*}} .dummy + 0 @@ -36,9 +36,9 @@ .type _start, %function _start: adrp x0, datatable - add x0, x0, :lo12:datable + add x0, x0, :lo12:datatable mov x0, #0 - ret + ret .section .dummy, "a", @progbits dummy: diff --git a/bolt/test/X86/callcont-fallthru.s b/bolt/test/X86/callcont-fallthru.s index 4994cfb541ee..8c05491e7bca 100644 --- a/bolt/test/X86/callcont-fallthru.s +++ b/bolt/test/X86/callcont-fallthru.s @@ -4,29 +4,62 @@ # RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so ## Link against a DSO to ensure PLT entries. # RUN: %clangxx %cxxflags %s %t.so -o %t -Wl,-q -nostdlib -# RUN: link_fdata %s %t %t.pat PREAGGT1 -# RUN: link_fdata %s %t %t.pat2 PREAGGT2 -# RUN-DISABLED: link_fdata %s %t %t.patplt PREAGGPLT +# Trace to a call continuation, not a landing pad/entry point +# RUN: link_fdata %s %t %t.pa-base PREAGG-BASE +# Trace from a return to a landing pad/entry point call continuation +# RUN: link_fdata %s %t %t.pa-ret PREAGG-RET +# Trace from an external location to a landing pad/entry point call continuation +# RUN: link_fdata %s %t %t.pa-ext PREAGG-EXT +# Return trace to a landing pad/entry point call continuation +# RUN: link_fdata %s %t %t.pa-pret PREAGG-PRET +# External return to a landing pad/entry point call continuation +# RUN: link_fdata %s %t %t.pa-eret PREAGG-ERET +# RUN-DISABLED: link_fdata %s %t %t.pa-plt PREAGG-PLT # RUN: llvm-strip --strip-unneeded %t -o %t.strip # RUN: llvm-objcopy --remove-section=.eh_frame %t.strip %t.noeh ## Check pre-aggregated traces attach call continuation fallthrough count -# RUN: llvm-bolt %t.noeh --pa -p %t.pat -o %t.out \ -# RUN: --print-cfg --print-only=main | FileCheck %s +## in the basic case (not an entry point, not a landing pad). +# RUN: llvm-bolt %t.noeh --pa -p %t.pa-base -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-BASE -## Check pre-aggregated traces don't attach call continuation fallthrough count -## to secondary entry point (unstripped) -# RUN: llvm-bolt %t --pa -p %t.pat2 -o %t.out \ -# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK3 -## Check pre-aggregated traces don't attach call continuation fallthrough count -## to landing pad (stripped, LP) -# RUN: llvm-bolt %t.strip --pa -p %t.pat2 -o %t.out \ -# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK3 +## Check pre-aggregated traces from a return attach call continuation +## fallthrough count to secondary entry point (unstripped) +# RUN: llvm-bolt %t --pa -p %t.pa-ret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH +## Check pre-aggregated traces from a return attach call continuation +## fallthrough count to landing pad (stripped, landing pad) +# RUN: llvm-bolt %t.strip --pa -p %t.pa-ret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH + +## Check pre-aggregated traces from external location don't attach call +## continuation fallthrough count to secondary entry point (unstripped) +# RUN: llvm-bolt %t --pa -p %t.pa-ext -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-SKIP +## Check pre-aggregated traces from external location don't attach call +## continuation fallthrough count to landing pad (stripped, landing pad) +# RUN: llvm-bolt %t.strip --pa -p %t.pa-ext -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-SKIP + +## Check pre-aggregated return traces from external location attach call +## continuation fallthrough count to secondary entry point (unstripped) +# RUN: llvm-bolt %t --pa -p %t.pa-pret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH +## Check pre-aggregated return traces from external location attach call +## continuation fallthrough count to landing pad (stripped, landing pad) +# RUN: llvm-bolt %t.strip --pa -p %t.pa-pret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH + +## Same for external return type +# RUN: llvm-bolt %t --pa -p %t.pa-eret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH +# RUN: llvm-bolt %t.strip --pa -p %t.pa-eret -o %t.out \ +# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK-ATTACH ## Check pre-aggregated traces don't report zero-sized PLT fall-through as ## invalid trace -# RUN-DISABLED: llvm-bolt %t.strip --pa -p %t.patplt -o %t.out | FileCheck %s \ +# RUN-DISABLED: llvm-bolt %t.strip --pa -p %t.pa-plt -o %t.out | FileCheck %s \ # RUN-DISABLED: --check-prefix=CHECK-PLT # CHECK-PLT: traces mismatching disassembled function contents: 0 @@ -56,11 +89,11 @@ main: Ltmp0_br: callq puts@PLT ## Check PLT traces are accepted -# PREAGGPLT: T #Ltmp0_br# #puts@plt# #puts@plt# 3 +# PREAGG-PLT: T #Ltmp0_br# #puts@plt# #puts@plt# 3 ## Target is an external-origin call continuation -# PREAGGT1: T X:0 #Ltmp1# #Ltmp4_br# 2 -# CHECK: callq puts@PLT -# CHECK-NEXT: count: 2 +# PREAGG-BASE: T X:0 #Ltmp1# #Ltmp4_br# 2 +# CHECK-BASE: callq puts@PLT +# CHECK-BASE-NEXT: count: 2 Ltmp1: movq -0x10(%rbp), %rax @@ -71,24 +104,22 @@ Ltmp4: cmpl $0x0, -0x14(%rbp) Ltmp4_br: je Ltmp0 -# CHECK2: je .Ltmp0 -# CHECK2-NEXT: count: 3 movl $0xa, -0x18(%rbp) callq foo ## Target is a binary-local call continuation -# PREAGGT1: T #Lfoo_ret# #Ltmp3# #Ltmp3_br# 1 -# CHECK: callq foo -# CHECK-NEXT: count: 1 - -## PLT call continuation fallthrough spanning the call -# CHECK2: callq foo -# CHECK2-NEXT: count: 3 - +# PREAGG-RET: T #Lfoo_ret# #Ltmp3# #Ltmp3_br# 1 ## Target is a secondary entry point (unstripped) or a landing pad (stripped) -# PREAGGT2: T X:0 #Ltmp3# #Ltmp3_br# 2 -# CHECK3: callq foo -# CHECK3-NEXT: count: 0 +# PREAGG-EXT: T X:0 #Ltmp3# #Ltmp3_br# 1 +## Pre-aggregated return trace +# PREAGG-PRET: R X:0 #Ltmp3# #Ltmp3_br# 1 +## External return +# PREAGG-ERET: r #Ltmp3# #Ltmp3_br# 1 + +# CHECK-ATTACH: callq foo +# CHECK-ATTACH-NEXT: count: 1 +# CHECK-SKIP: callq foo +# CHECK-SKIP-NEXT: count: 0 Ltmp3: cmpl $0x0, -0x18(%rbp) diff --git a/bolt/test/X86/linux-version.S b/bolt/test/X86/linux-version.S index e680d0d64a21..a3d7f365304a 100644 --- a/bolt/test/X86/linux-version.S +++ b/bolt/test/X86/linux-version.S @@ -17,6 +17,11 @@ # RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr # RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-C %s +# RUN: %clang -DD -target x86_64-unknown-unknown \ +# RUN: %cflags -nostdlib %s -o %t.exe \ +# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr +# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-D %s + .text .globl foo .type foo, %function @@ -46,6 +51,12 @@ linux_banner: #endif # CHECK-C: BOLT-INFO: Linux kernel version is 6.6 +#ifdef D + .hidden linux_banner + .string "Linux version 6.6.15.2-2-xxx\n" +#endif +# CHECK-D: BOLT-INFO: Linux kernel version is 6.6 + .size linux_banner, . - linux_banner ## Fake Linux Kernel sections. diff --git a/bolt/test/X86/register-fragments-bolt-symbols.s b/bolt/test/X86/register-fragments-bolt-symbols.s index c9f1859c4e8a..20e7345541d9 100644 --- a/bolt/test/X86/register-fragments-bolt-symbols.s +++ b/bolt/test/X86/register-fragments-bolt-symbols.s @@ -29,6 +29,7 @@ # RUN: link_fdata %s %t.bolt %t.preagg PREAGG # PREAGG: B X:0 #chain.cold.0# 1 0 +# PREAGG: B X:0 #dummy# 1 0 # RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \ # RUN: | FileCheck %s --check-prefix=CHECK-REGISTER # RUN: FileCheck --input-file %t.bat.fdata --check-prefix=CHECK-FDATA %s @@ -44,7 +45,13 @@ # CHECK-SYMS: l F .text.cold [[#]] chain.cold.0 # CHECK-SYMS: l F .text [[#]] chain # CHECK-SYMS: l df *ABS* [[#]] bolt-pseudo.o +# CHECK-SYMS: l F .text.cold [[#]] dummy.cold.0 +# CHECK-SYMS: l F .text.cold.1 [[#]] dummy.cold.1 +# CHECK-SYMS: l F .text.cold.2 [[#]] dummy.cold.2 +# CHECK-REGISTER: BOLT-INFO: marking dummy.cold.0/1(*2) as a fragment of dummy +# CHECK-REGISTER: BOLT-INFO: marking dummy.cold.1/1(*2) as a fragment of dummy +# CHECK-REGISTER: BOLT-INFO: marking dummy.cold.2/1(*2) as a fragment of dummy # CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2) # CHECK-FDATA: 0 [unknown] 0 1 chain/chain.s/2 10 0 1 diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s new file mode 100644 index 000000000000..717bf40df3d0 --- /dev/null +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s @@ -0,0 +1,812 @@ +// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe +// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s + +// The detection of compiler-generated explicit pointer checks is tested in +// gs-pauth-address-checks.s, for that reason only test here "dummy-load" and +// "high-bits-notbi" checkers, as the shortest examples of checkers that are +// detected per-instruction and per-BB. + +// PACRET-NOT: authentication oracle found in function + + .text + + .type sym,@function +sym: + ret + .size sym, .-sym + + .globl callee + .type callee,@function +callee: + ret + .size callee, .-callee + + .globl good_ret + .type good_ret,@function +good_ret: +// CHECK-NOT: good_ret + autia x0, x1 + ret x0 + .size good_ret, .-good_ret + + .globl good_call + .type good_call,@function +good_call: +// CHECK-NOT: good_call + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + autia x0, x1 + blr x0 + + ldp x29, x30, [sp], #16 + autiasp + ret + .size good_call, .-good_call + + .globl good_branch + .type good_branch,@function +good_branch: +// CHECK-NOT: good_branch + autia x0, x1 + br x0 + .size good_branch, .-good_branch + + .globl good_load_other_reg + .type good_load_other_reg,@function +good_load_other_reg: +// CHECK-NOT: good_load_other_reg + autia x0, x1 + ldr x2, [x0] + ret + .size good_load_other_reg, .-good_load_other_reg + + .globl good_load_same_reg + .type good_load_same_reg,@function +good_load_same_reg: +// CHECK-NOT: good_load_same_reg + autia x0, x1 + ldr x0, [x0] + ret + .size good_load_same_reg, .-good_load_same_reg + + .globl good_explicit_check + .type good_explicit_check,@function +good_explicit_check: +// CHECK-NOT: good_explicit_check + autia x0, x1 + eor x16, x0, x0, lsl #1 + tbz x16, #62, 1f + brk 0x1234 +1: + ret + .size good_explicit_check, .-good_explicit_check + + .globl bad_unchecked + .type bad_unchecked,@function +bad_unchecked: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unchecked, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + autia x0, x1 + ret + .size bad_unchecked, .-bad_unchecked + + .globl bad_leaked_to_subroutine + .type bad_leaked_to_subroutine,@function +bad_leaked_to_subroutine: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_leaked_to_subroutine, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee +// CHECK-NEXT: This happens in the following basic block: +// CHECK-NEXT: {{[0-9a-f]+}}: paciasp +// CHECK-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]! +// CHECK-NEXT: {{[0-9a-f]+}}: mov x29, sp +// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: {{[0-9a-f]+}}: bl callee +// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0] +// CHECK-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 +// CHECK-NEXT: {{[0-9a-f]+}}: autiasp +// CHECK-NEXT: {{[0-9a-f]+}}: ret + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + autia x0, x1 + bl callee + ldr x2, [x0] + + ldp x29, x30, [sp], #16 + autiasp + ret + .size bad_leaked_to_subroutine, .-bad_leaked_to_subroutine + + .globl bad_unknown_usage_read + .type bad_unknown_usage_read,@function +bad_unknown_usage_read: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_read, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul x3, x0, x1 +// CHECK-NEXT: This happens in the following basic block: +// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: {{[0-9a-f]+}}: mul x3, x0, x1 +// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0] +// CHECK-NEXT: {{[0-9a-f]+}}: ret + autia x0, x1 + // Registers are not accessible to an attacker under Pointer + // Authentication threat model, until spilled to memory. + // Thus, reporting the below MUL instruction is a false positive, since + // the next LDR instruction prevents any possible spilling of x3 unless + // the authentication succeeded. Though, rejecting anything except for + // a closed list of instruction types is the intended behavior of the + // analysis, so this false positive is by design. + mul x3, x0, x1 + ldr x2, [x0] + ret + .size bad_unknown_usage_read, .-bad_unknown_usage_read + + .globl bad_store_to_memory_and_wait + .type bad_store_to_memory_and_wait,@function +bad_store_to_memory_and_wait: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_store_to_memory_and_wait, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: str x0, [x3] + autia x0, x1 + cbz x3, 2f + str x0, [x3] +1: + // The thread performs a time-consuming computation while the result of + // authentication is accessible in memory. + nop +2: + ldr x2, [x0] + ret + .size bad_store_to_memory_and_wait, .-bad_store_to_memory_and_wait + +// FIXME: Known false negative: if no return instruction is reachable from a +// program point (this probably implies an infinite loop), such +// instruction cannot be detected as an authentication oracle. + .globl bad_store_to_memory_and_hang + .type bad_store_to_memory_and_hang,@function +bad_store_to_memory_and_hang: +// CHECK-NOT: bad_store_to_memory_and_hang + autia x0, x1 + cbz x3, 2f + str x0, [x3] +1: + // The thread loops indefinitely while the result of authentication + // is accessible in memory. + b 1b +2: + ldr x2, [x0] + ret + .size bad_store_to_memory_and_hang, .-bad_store_to_memory_and_hang + + .globl bad_unknown_usage_subreg_read + .type bad_unknown_usage_subreg_read,@function +bad_unknown_usage_subreg_read: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_subreg_read, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul w3, w0, w1 +// CHECK-NEXT: This happens in the following basic block: +// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: {{[0-9a-f]+}}: mul w3, w0, w1 +// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0] +// CHECK-NEXT: {{[0-9a-f]+}}: ret + autia x0, x1 + mul w3, w0, w1 + ldr x2, [x0] + ret + .size bad_unknown_usage_subreg_read, .-bad_unknown_usage_subreg_read + + .globl bad_unknown_usage_update + .type bad_unknown_usage_update,@function +bad_unknown_usage_update: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_update, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: movk x0, #0x2a, lsl #16 +// CHECK-NEXT: This happens in the following basic block: +// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: {{[0-9a-f]+}}: movk x0, #0x2a, lsl #16 +// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0] +// CHECK-NEXT: {{[0-9a-f]+}}: ret + autia x0, x1 + movk x0, #42, lsl #16 // does not overwrite x0 completely + ldr x2, [x0] + ret + .size bad_unknown_usage_update, .-bad_unknown_usage_update + + .globl good_overwrite_with_constant + .type good_overwrite_with_constant,@function +good_overwrite_with_constant: +// CHECK-NOT: good_overwrite_with_constant + autia x0, x1 + mov x0, #42 + ret + .size good_overwrite_with_constant, .-good_overwrite_with_constant + +// Overwriting sensitive data by instructions with unmodelled side-effects is +// explicitly rejected, even though this particular MRS is safe. + .globl bad_overwrite_with_side_effects + .type bad_overwrite_with_side_effects,@function +bad_overwrite_with_side_effects: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_overwrite_with_side_effects, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + autia x0, x1 + mrs x0, CTR_EL0 + ret + .size bad_overwrite_with_side_effects, .-bad_overwrite_with_side_effects + +// Here the new value written by MUL to x0 is completely unrelated to the result +// of authentication, so this is a false positive. +// FIXME: Can/should we generalize overwriting by constant to handle such cases? + .globl good_unknown_overwrite + .type good_unknown_overwrite,@function +good_unknown_overwrite: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function good_unknown_overwrite, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + autia x0, x1 + mul x0, x1, x2 + ret + .size good_unknown_overwrite, .-good_unknown_overwrite + +// This is a false positive: when a general-purpose register is written to as +// a 32-bit register, its top 32 bits are zeroed, but according to LLVM +// representation, the instruction only overwrites the Wn register. + .globl good_wreg_overwrite + .type good_wreg_overwrite,@function +good_wreg_overwrite: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function good_wreg_overwrite, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 + autia x0, x1 + mov w0, #42 + ret + .size good_wreg_overwrite, .-good_wreg_overwrite + + .globl good_address_arith + .type good_address_arith,@function +good_address_arith: +// CHECK-NOT: good_address_arith + autia x0, x1 + + add x1, x0, #8 + sub x2, x1, #16 + mov x3, x2 + + ldr x4, [x3] + mov x0, #0 + mov x1, #0 + mov x2, #0 + + ret + .size good_address_arith, .-good_address_arith + + .globl good_ret_multi_bb + .type good_ret_multi_bb,@function +good_ret_multi_bb: +// CHECK-NOT: good_ret_multi_bb + autia x0, x1 + cbz x1, 1f + nop +1: + ret x0 + .size good_ret_multi_bb, .-good_ret_multi_bb + + .globl good_call_multi_bb + .type good_call_multi_bb,@function +good_call_multi_bb: +// CHECK-NOT: good_call_multi_bb + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + autia x0, x1 + cbz x1, 1f + nop +1: + blr x0 + cbz x1, 2f + nop +2: + ldp x29, x30, [sp], #16 + autiasp + ret + .size good_call_multi_bb, .-good_call_multi_bb + + .globl good_branch_multi_bb + .type good_branch_multi_bb,@function +good_branch_multi_bb: +// CHECK-NOT: good_branch_multi_bb + autia x0, x1 + cbz x1, 1f + nop +1: + br x0 + .size good_branch_multi_bb, .-good_branch_multi_bb + + .globl good_load_other_reg_multi_bb + .type good_load_other_reg_multi_bb,@function +good_load_other_reg_multi_bb: +// CHECK-NOT: good_load_other_reg_multi_bb + autia x0, x1 + cbz x1, 1f + nop +1: + ldr x2, [x0] + cbz x1, 2f + nop +2: + ret + .size good_load_other_reg_multi_bb, .-good_load_other_reg_multi_bb + + .globl good_load_same_reg_multi_bb + .type good_load_same_reg_multi_bb,@function +good_load_same_reg_multi_bb: +// CHECK-NOT: good_load_same_reg_multi_bb + autia x0, x1 + cbz x1, 1f + nop +1: + ldr x0, [x0] + cbz x1, 2f + nop +2: + ret + .size good_load_same_reg_multi_bb, .-good_load_same_reg_multi_bb + + .globl good_explicit_check_multi_bb + .type good_explicit_check_multi_bb,@function +good_explicit_check_multi_bb: +// CHECK-NOT: good_explicit_check_multi_bb + autia x0, x1 + cbz x1, 1f + nop +1: + eor x16, x0, x0, lsl #1 + tbz x16, #62, 2f + brk 0x1234 +2: + cbz x1, 3f + nop +3: + ret + .size good_explicit_check_multi_bb, .-good_explicit_check_multi_bb + + .globl bad_unchecked_multi_bb + .type bad_unchecked_multi_bb,@function +bad_unchecked_multi_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unchecked_multi_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + autia x0, x1 + cbz x1, 1f + ldr x2, [x0] +1: + ret + .size bad_unchecked_multi_bb, .-bad_unchecked_multi_bb + + .globl bad_leaked_to_subroutine_multi_bb + .type bad_leaked_to_subroutine_multi_bb,@function +bad_leaked_to_subroutine_multi_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_leaked_to_subroutine_multi_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + autia x0, x1 + cbz x1, 1f + ldr x2, [x0] +1: + bl callee + ldr x2, [x0] + + ldp x29, x30, [sp], #16 + autiasp + ret + .size bad_leaked_to_subroutine_multi_bb, .-bad_leaked_to_subroutine_multi_bb + + .globl bad_unknown_usage_read_multi_bb + .type bad_unknown_usage_read_multi_bb,@function +bad_unknown_usage_read_multi_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_read_multi_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul x3, x0, x1 + autia x0, x1 + cbz x3, 1f + mul x3, x0, x1 +1: + ldr x2, [x0] + ret + .size bad_unknown_usage_read_multi_bb, .-bad_unknown_usage_read_multi_bb + + .globl bad_unknown_usage_subreg_read_multi_bb + .type bad_unknown_usage_subreg_read_multi_bb,@function +bad_unknown_usage_subreg_read_multi_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_subreg_read_multi_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul w3, w0, w1 + autia x0, x1 + cbz x3, 1f + mul w3, w0, w1 +1: + ldr x2, [x0] + ret + .size bad_unknown_usage_subreg_read_multi_bb, .-bad_unknown_usage_subreg_read_multi_bb + + .globl bad_unknown_usage_update_multi_bb + .type bad_unknown_usage_update_multi_bb,@function +bad_unknown_usage_update_multi_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_update_multi_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: movk x0, #0x2a, lsl #16 + autia x0, x1 + cbz x3, 1f + movk x0, #42, lsl #16 // does not overwrite x0 completely +1: + ldr x2, [x0] + ret + .size bad_unknown_usage_update_multi_bb, .-bad_unknown_usage_update_multi_bb + + .globl good_overwrite_with_constant_multi_bb + .type good_overwrite_with_constant_multi_bb,@function +good_overwrite_with_constant_multi_bb: +// CHECK-NOT: good_overwrite_with_constant_multi_bb + autia x0, x1 + cbz x3, 1f +1: + mov x0, #42 + ret + .size good_overwrite_with_constant_multi_bb, .-good_overwrite_with_constant_multi_bb + + .globl good_address_arith_multi_bb + .type good_address_arith_multi_bb,@function +good_address_arith_multi_bb: +// CHECK-NOT: good_address_arith_multi_bb + autia x0, x1 + cbz x3, 1f + + add x1, x0, #8 + sub x2, x1, #16 + mov x0, x2 + + mov x1, #0 + mov x2, #0 +1: + ldr x3, [x0] + ret + .size good_address_arith_multi_bb, .-good_address_arith_multi_bb + +// FIXME: Most *_nocfg test cases contain paciasp+autiasp instructions even if +// LR is not spilled - this is a workaround for RET instructions being +// reported as non-protected, because LR state is reset at every label. + + .globl good_ret_nocfg + .type good_ret_nocfg,@function +good_ret_nocfg: +// CHECK-NOT: good_ret_nocfg + adr x2, 1f + br x2 +1: + autia x0, x1 + + ret x0 + .size good_ret_nocfg, .-good_ret_nocfg + + .globl good_call_nocfg + .type good_call_nocfg,@function +good_call_nocfg: +// CHECK-NOT: good_call_nocfg + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + adr x2, 1f + br x2 +1: + autia x0, x1 + blr x0 + + ldp x29, x30, [sp], #16 + autiasp + ret + .size good_call_nocfg, .-good_call_nocfg + + .globl good_branch_nocfg + .type good_branch_nocfg,@function +good_branch_nocfg: +// CHECK-NOT: good_branch_nocfg + adr x2, 1f + br x2 +1: + autia x0, x1 + br x0 + .size good_branch_nocfg, .-good_branch_nocfg + + .globl good_load_other_reg_nocfg + .type good_load_other_reg_nocfg,@function +good_load_other_reg_nocfg: +// CHECK-NOT: good_load_other_reg_nocfg + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + ldr x2, [x0] + + autiasp + ret + .size good_load_other_reg_nocfg, .-good_load_other_reg_nocfg + + .globl good_load_same_reg_nocfg + .type good_load_same_reg_nocfg,@function +good_load_same_reg_nocfg: +// CHECK-NOT: good_load_same_reg_nocfg + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + ldr x0, [x0] + + autiasp + ret + .size good_load_same_reg_nocfg, .-good_load_same_reg_nocfg + +// FIXME: Multi-instruction checker sequences are not supported without CFG. + + .globl bad_unchecked_nocfg + .type bad_unchecked_nocfg,@function +bad_unchecked_nocfg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unchecked_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + + autiasp + ret + .size bad_unchecked_nocfg, .-bad_unchecked_nocfg + + .globl bad_leaked_to_subroutine_nocfg + .type bad_leaked_to_subroutine_nocfg,@function +bad_leaked_to_subroutine_nocfg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_leaked_to_subroutine_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee # Offset: 24 + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + adr x2, 1f + br x2 +1: + autia x0, x1 + bl callee + ldr x2, [x0] + + ldp x29, x30, [sp], #16 + autiasp + ret + .size bad_leaked_to_subroutine_nocfg, .-bad_leaked_to_subroutine_nocfg + + .globl bad_unknown_usage_read_nocfg + .type bad_unknown_usage_read_nocfg,@function +bad_unknown_usage_read_nocfg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_read_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul x3, x0, x1 + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + mul x3, x0, x1 + ldr x2, [x0] + + autiasp + ret + .size bad_unknown_usage_read_nocfg, .-bad_unknown_usage_read_nocfg + + .globl bad_unknown_usage_subreg_read_nocfg + .type bad_unknown_usage_subreg_read_nocfg,@function +bad_unknown_usage_subreg_read_nocfg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_subreg_read_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul w3, w0, w1 + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + mul w3, w0, w1 + ldr x2, [x0] + + autiasp + ret + .size bad_unknown_usage_subreg_read_nocfg, .-bad_unknown_usage_subreg_read_nocfg + + .globl bad_unknown_usage_update_nocfg + .type bad_unknown_usage_update_nocfg,@function +bad_unknown_usage_update_nocfg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_update_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 +// CHECK-NEXT: The 1 instructions that leak the affected registers are: +// CHECK-NEXT: 1. {{[0-9a-f]+}}: movk x0, #0x2a, lsl #16 + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + movk x0, #42, lsl #16 // does not overwrite x0 completely + ldr x2, [x0] + + autiasp + ret + .size bad_unknown_usage_update_nocfg, .-bad_unknown_usage_update_nocfg + + .globl good_overwrite_with_constant_nocfg + .type good_overwrite_with_constant_nocfg,@function +good_overwrite_with_constant_nocfg: +// CHECK-NOT: good_overwrite_with_constant_nocfg + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + mov x0, #42 + + autiasp + ret + .size good_overwrite_with_constant_nocfg, .-good_overwrite_with_constant_nocfg + + .globl good_address_arith_nocfg + .type good_address_arith_nocfg,@function +good_address_arith_nocfg: +// CHECK-NOT: good_address_arith_nocfg + paciasp + adr x2, 1f + br x2 +1: + autia x0, x1 + add x1, x0, #8 + sub x2, x1, #16 + mov x3, x2 + + ldr x4, [x3] + mov x0, #0 + mov x1, #0 + mov x2, #0 + + autiasp + ret + .size good_address_arith_nocfg, .-good_address_arith_nocfg + + .globl good_explicit_check_unrelated_reg + .type good_explicit_check_unrelated_reg,@function +good_explicit_check_unrelated_reg: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function good_explicit_check_unrelated_reg, basic block {{[^,]+}}, at address + // FIXME: The below instruction is not an authentication oracle + autia x2, x3 // One of possible execution paths after this instruction + // ends at BRK below, thus BRK used as a trap instruction + // should formally "check everything" not to introduce + // false-positive here. + autia x0, x1 + eor x16, x0, x0, lsl #1 + tbz x16, #62, 1f + brk 0x1234 +1: + ldr x4, [x2] // Right before this instruction X2 is checked - this + // should be propagated to the basic block ending with + // TBZ instruction above. + ret + .size good_explicit_check_unrelated_reg, .-good_explicit_check_unrelated_reg + +// The last BB (in layout order) is processed first by the data-flow analysis. +// Its initial state is usually filled in a special way (because it ends with +// `ret` instruction), and then affects the state propagated to the other BBs +// Thus, the case of the last instruction in a function being a jump somewhere +// in the middle is special. + + .globl good_no_ret_from_last_bb + .type good_no_ret_from_last_bb,@function +good_no_ret_from_last_bb: +// CHECK-NOT: good_no_ret_from_last_bb + paciasp + autiasp // authenticates LR + b 2f +1: + ret +2: + b 1b // LR is dereferenced by `ret`, which is executed next + .size good_no_ret_from_last_bb, .-good_no_ret_from_last_bb + + .globl bad_no_ret_from_last_bb + .type bad_no_ret_from_last_bb,@function +bad_no_ret_from_last_bb: +// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_no_ret_from_last_bb, basic block {{[^,]+}}, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// CHECK-NEXT: The 0 instructions that leak the affected registers are: + paciasp + autiasp // authenticates LR + b 2f +1: + ret x0 +2: + b 1b // X0 (but not LR) is dereferenced by `ret x0` + .size bad_no_ret_from_last_bb, .-bad_no_ret_from_last_bb + +// Test that combined auth+something instructions are not reported as +// authentication oracles. + + .globl inst_retaa + .type inst_retaa,@function +inst_retaa: +// CHECK-NOT: inst_retaa + paciasp + retaa + .size inst_retaa, .-inst_retaa + + .globl inst_blraa + .type inst_blraa,@function +inst_blraa: +// CHECK-NOT: inst_blraa + paciasp + stp x29, x30, [sp, #-16]! + mov x29, sp + + blraa x0, x1 + + ldp x29, x30, [sp], #16 + retaa + .size inst_blraa, .-inst_blraa + + .globl inst_braa + .type inst_braa,@function +inst_braa: +// CHECK-NOT: inst_braa + braa x0, x1 + .size inst_braa, .-inst_braa + + .globl inst_ldraa_no_wb + .type inst_ldraa_no_wb,@function +inst_ldraa_no_wb: +// CHECK-NOT: inst_ldraa_no_wb + ldraa x1, [x0] + ret + .size inst_ldraa_no_wb, .-inst_ldraa_no_wb + + .globl inst_ldraa_wb + .type inst_ldraa_wb,@function +inst_ldraa_wb: +// CHECK-NOT: inst_ldraa_wb + ldraa x1, [x0]! + ret + .size inst_ldraa_wb, .-inst_ldraa_wb + + .globl main + .type main,@function +main: + mov x0, 0 + ret + .size main, .-main diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s index 82494d834a15..fbb96a63d41e 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s @@ -113,7 +113,7 @@ simple: // CHECK-EMPTY: // PAUTH-NEXT: Found sign inst: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state // PAUTH-NEXT: Signed reg: LR -// PAUTH-NEXT: TrustedRegs: LR W30 W30_HI +// PAUTH-NEXT: TrustedRegs: LR W30 W30_HI{{[ \t]*$}} // PAUTH-NEXT: Found call inst: 00000000: blr x0 # DataflowSrcSafetyAnalysis: src-state // PAUTH-NEXT: Call destination reg: X0 // PAUTH-NEXT: SafeToDerefRegs: W0 X0 W0_HI{{[ \t]*$}} @@ -220,10 +220,10 @@ nocfg: // CHECK-EMPTY: // PAUTH-NEXT: Found call inst: 00000000: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state // PAUTH-NEXT: Call destination reg: X0 -// PAUTH-NEXT: SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI +// PAUTH-NEXT: SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI{{[ \t]*$}} // CHECK-NEXT: Found RET inst: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: RetReg: LR -// CHECK-NEXT: SafeToDerefRegs: +// CHECK-NEXT: SafeToDerefRegs:{{[ \t]*$}} // CHECK-EMPTY: // CHECK-NEXT: Running detailed src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state) @@ -251,6 +251,116 @@ nocfg: // CHECK-EMPTY: // CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state + .globl auth_oracle + .type auth_oracle,@function +auth_oracle: + autia x0, x1 + ret + .size auth_oracle, .-auth_oracle + +// CHECK-LABEL:Analyzing function auth_oracle, AllocatorId = 1 +// CHECK-NEXT: Binary Function "auth_oracle" { +// CHECK-NEXT: Number : 4 +// CHECK-NEXT: State : CFG constructed +// ... +// CHECK: BB Layout : [[BB0:[0-9a-zA-Z.]+]] +// CHECK-NEXT: } +// CHECK-NEXT: [[BB0]] (2 instructions, align : 1) +// CHECK-NEXT: Entry Point +// CHECK-NEXT: 00000000: autia x0, x1 +// CHECK-NEXT: 00000004: ret +// CHECK-EMPTY: +// CHECK-NEXT: DWARF CFI Instructions: +// CHECK-NEXT: +// CHECK-NEXT: End of Function "auth_oracle" +// CHECK-EMPTY: +// CHECK-NEXT: Running src register safety analysis... +// ... +// CHECK: After src register safety analysis: +// CHECK-NEXT: Binary Function "auth_oracle" { +// ... +// CHECK: End of Function "auth_oracle" +// ... +// PAUTH: Running dst register safety analysis... +// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) +// PAUTH-NEXT: .. result: (dst-state) +// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) +// PAUTH-NEXT: .. result: (dst-state) +// PAUTH-NEXT: After dst register safety analysis: +// PAUTH-NEXT: Binary Function "auth_oracle" { +// PAUTH-NEXT: Number : 4 +// PAUTH-NEXT: State : CFG constructed +// ... +// PAUTH: BB Layout : [[BB0]] +// PAUTH-NEXT: } +// PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) +// PAUTH-NEXT: Entry Point +// PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state +// PAUTH-EMPTY: +// PAUTH-NEXT: DWARF CFI Instructions: +// PAUTH-NEXT: +// PAUTH-NEXT: End of Function "auth_oracle" +// PAUTH-EMPTY: +// PAUTH-NEXT: Found auth inst: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// PAUTH-NEXT: Authenticated reg: X0 +// PAUTH-NEXT: safe output registers: LR W30 W30_HI{{[ \t]*$}} +// PAUTH-EMPTY: +// PAUTH-NEXT: Running detailed dst register safety analysis... +// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) +// PAUTH-NEXT: .. result: (dst-state) +// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) +// PAUTH-NEXT: .. result: (dst-state) +// PAUTH-NEXT: After detailed dst register safety analysis: +// PAUTH-NEXT: Binary Function "auth_oracle" { +// PAUTH-NEXT: Number : 4 +// PAUTH-NEXT: State : CFG constructed +// ... +// PAUTH: BB Layout : [[BB0]] +// PAUTH-NEXT: } +// PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) +// PAUTH-NEXT: Entry Point +// PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state +// PAUTH-EMPTY: +// PAUTH-NEXT: DWARF CFI Instructions: +// PAUTH-NEXT: +// PAUTH-NEXT: End of Function "auth_oracle" +// PAUTH-EMPTY: +// PAUTH-NEXT: Attaching leakage info to: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state + +// Gadget scanner should not crash on CFI instructions, including when debug-printing them. +// Note that the particular debug output is not checked, but BOLT should be +// compiled with assertions enabled to support -debug-only argument. + + .globl cfi_inst_df + .type cfi_inst_df,@function +cfi_inst_df: + .cfi_startproc + sub sp, sp, #16 + .cfi_def_cfa_offset 16 + add sp, sp, #16 + .cfi_def_cfa_offset 0 + ret + .size cfi_inst_df, .-cfi_inst_df + .cfi_endproc + + .globl cfi_inst_nocfg + .type cfi_inst_nocfg,@function +cfi_inst_nocfg: + .cfi_startproc + sub sp, sp, #16 + .cfi_def_cfa_offset 16 + + adr x0, 1f + br x0 +1: + add sp, sp, #16 + .cfi_def_cfa_offset 0 + ret + .size cfi_inst_nocfg, .-cfi_inst_nocfg + .cfi_endproc + // CHECK-LABEL:Analyzing function main, AllocatorId = 1 .globl main .type main,@function diff --git a/bolt/test/link_fdata.py b/bolt/test/link_fdata.py index 5a9752068bb9..898dce8e3fb5 100755 --- a/bolt/test/link_fdata.py +++ b/bolt/test/link_fdata.py @@ -36,9 +36,9 @@ prefix_pat = re.compile(f"^# {args.prefix}: (.*)") fdata_pat = re.compile(r"([01].*) (?P\d+) (?P\d+)") # Pre-aggregated profile: -# {T|S|E|B|F|f} [] [] [] +# {T|R|S|E|B|F|f|r} [] [] [] # : [:] -preagg_pat = re.compile(r"(?P[TSBFf]) (?P.*)") +preagg_pat = re.compile(r"(?P[TRSBFfr]) (?P.*)") # No-LBR profile: # diff --git a/bolt/test/lit.local.cfg b/bolt/test/lit.local.cfg index d5a6849b27a7..8a61d11f5825 100644 --- a/bolt/test/lit.local.cfg +++ b/bolt/test/lit.local.cfg @@ -1,6 +1,11 @@ -host_linux_triple = config.target_triple.split("-")[0] + "-unknown-linux-gnu" +host_triple = config.target_triple + +# Force triple on non-linux hosts to get ELF binaries on all platforms. +if not "linux" in host_triple: + host_triple = host_triple.split("-")[0] + "-unknown-linux-gnu" + common_linker_flags = "-fuse-ld=lld -Wl,--unresolved-symbols=ignore-all -Wl,--build-id=none -pie" -flags = f"--target={host_linux_triple} -fPIE {common_linker_flags}" +flags = f"--target={host_triple} -fPIE {common_linker_flags}" config.substitutions.insert(0, ("%cflags", f"%cflags {flags}")) config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}")) diff --git a/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test b/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test new file mode 100644 index 000000000000..91f5c857fbab --- /dev/null +++ b/bolt/test/perf2bolt/AArch64/perf2bolt-spe.test @@ -0,0 +1,12 @@ +## Check that Arm SPE mode is available on AArch64. + +REQUIRES: system-linux,perf,target=aarch64{{.*}} + +RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.exe + +RUN: perf record -e cycles -q -o %t.perf.data -- %t.exe 2> /dev/null + +RUN: (perf2bolt -p %t.perf.data -o %t.perf.boltdata --spe %t.exe 2> /dev/null; exit 0) | FileCheck %s --check-prefix=CHECK-SPE-LBR + +CHECK-SPE-LBR: PERF2BOLT: parse SPE branch events in LBR-format + diff --git a/bolt/test/perf2bolt/X86/perf2bolt-spe.test b/bolt/test/perf2bolt/X86/perf2bolt-spe.test new file mode 100644 index 000000000000..101bd3789a18 --- /dev/null +++ b/bolt/test/perf2bolt/X86/perf2bolt-spe.test @@ -0,0 +1,9 @@ +## Check that Arm SPE mode is unavailable on X86. + +REQUIRES: system-linux,x86_64-linux + +RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.exe +RUN: touch %t.empty.perf.data +RUN: not perf2bolt -p %t.empty.perf.data -o %t.perf.boltdata --spe --pa %t.exe 2>&1 | FileCheck %s + +CHECK: perf2bolt{{.*}} -spe is available only on AArch64. diff --git a/bolt/tools/driver/llvm-bolt.cpp b/bolt/tools/driver/llvm-bolt.cpp index b9836c2397b6..cf1b31f8c0c6 100644 --- a/bolt/tools/driver/llvm-bolt.cpp +++ b/bolt/tools/driver/llvm-bolt.cpp @@ -237,6 +237,13 @@ int main(int argc, char **argv) { if (Error E = RIOrErr.takeError()) report_error(opts::InputFilename, std::move(E)); RewriteInstance &RI = *RIOrErr.get(); + + if (opts::AggregateOnly && !RI.getBinaryContext().isAArch64() && + opts::ArmSPE) { + errs() << ToolName << ": -spe is available only on AArch64.\n"; + exit(1); + } + if (!opts::PerfData.empty()) { if (!opts::AggregateOnly) { errs() << ToolName diff --git a/bolt/unittests/Profile/CMakeLists.txt b/bolt/unittests/Profile/CMakeLists.txt index e0aa0926b49c..ce01c6c4b949 100644 --- a/bolt/unittests/Profile/CMakeLists.txt +++ b/bolt/unittests/Profile/CMakeLists.txt @@ -1,11 +1,25 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoDWARF + Object + ${LLVM_TARGETS_TO_BUILD} + ) + add_bolt_unittest(ProfileTests DataAggregator.cpp + PerfSpeEvents.cpp DISABLE_LLVM_LINK_LLVM_DYLIB ) target_link_libraries(ProfileTests PRIVATE + LLVMBOLTCore LLVMBOLTProfile + LLVMTargetParser + LLVMTestingSupport ) +foreach (tgt ${BOLT_TARGETS_TO_BUILD}) + string(TOUPPER "${tgt}" upper) + target_compile_definitions(ProfileTests PRIVATE "${upper}_AVAILABLE") +endforeach() diff --git a/bolt/unittests/Profile/PerfSpeEvents.cpp b/bolt/unittests/Profile/PerfSpeEvents.cpp new file mode 100644 index 000000000000..3e3e05395246 --- /dev/null +++ b/bolt/unittests/Profile/PerfSpeEvents.cpp @@ -0,0 +1,164 @@ +//===- bolt/unittests/Profile/PerfSpeEvents.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 +// +//===----------------------------------------------------------------------===// + +#ifdef AARCH64_AVAILABLE + +#include "bolt/Core/BinaryContext.h" +#include "bolt/Profile/DataAggregator.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::bolt; +using namespace llvm::object; +using namespace llvm::ELF; + +namespace opts { +extern cl::opt ReadPerfEvents; +extern cl::opt ArmSPE; +} // namespace opts + +namespace llvm { +namespace bolt { + +/// Perform checks on perf SPE branch events. +struct PerfSpeEventsTestHelper : public testing::Test { + void SetUp() override { + initalizeLLVM(); + prepareElf(); + initializeBOLT(); + } + +protected: + using Trace = DataAggregator::Trace; + using TakenBranchInfo = DataAggregator::TakenBranchInfo; + + void initalizeLLVM() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllDisassemblers(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + } + + void prepareElf() { + memcpy(ElfBuf, "\177ELF", 4); + ELF64LE::Ehdr *EHdr = reinterpret_cast(ElfBuf); + EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64; + EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB; + EHdr->e_machine = llvm::ELF::EM_AARCH64; + MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF"); + ObjFile = cantFail(ObjectFile::createObjectFile(Source)); + } + + void initializeBOLT() { + Relocation::Arch = ObjFile->makeTriple().getArch(); + BC = cantFail(BinaryContext::createBinaryContext( + ObjFile->makeTriple(), std::make_shared(), + ObjFile->getFileName(), nullptr, /*IsPIC*/ false, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); + ASSERT_FALSE(!BC); + } + + char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {}; + std::unique_ptr ObjFile; + std::unique_ptr BC; + + /// Helper function to export lists to show the mismatch. + void reportBrStackEventMismatch( + const std::vector> &Traces, + const std::vector> &ExpectedSamples) { + llvm::errs() << "Traces items: \n"; + for (const auto &[Trace, BI] : Traces) + llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << "," + << Trace.To << ", " << BI.TakenCount << ", " + << BI.MispredCount << "}" << "\n"; + + llvm::errs() << "Expected items: \n"; + for (const auto &[Trace, BI] : ExpectedSamples) + llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << ", " + << Trace.To << ", " << BI.TakenCount << ", " + << BI.MispredCount << "}" << "\n"; + } + + /// Parse and check SPE brstack as LBR. + void parseAndCheckBrstackEvents( + uint64_t PID, + const std::vector> &ExpectedSamples) { + DataAggregator DA(""); + DA.ParsingBuf = opts::ReadPerfEvents; + DA.BC = BC.get(); + DataAggregator::MMapInfo MMap; + DA.BinaryMMapInfo.insert(std::make_pair(PID, MMap)); + + DA.parseBranchEvents(); + + EXPECT_EQ(DA.Traces.size(), ExpectedSamples.size()); + if (DA.Traces.size() != ExpectedSamples.size()) + reportBrStackEventMismatch(DA.Traces, ExpectedSamples); + + const auto TracesBegin = DA.Traces.begin(); + const auto TracesEnd = DA.Traces.end(); + for (const auto &BI : ExpectedSamples) { + auto it = find_if(TracesBegin, TracesEnd, + [&BI](const auto &Tr) { return Tr.first == BI.first; }); + + EXPECT_NE(it, TracesEnd); + EXPECT_EQ(it->second.MispredCount, BI.second.MispredCount); + EXPECT_EQ(it->second.TakenCount, BI.second.TakenCount); + } + } +}; + +} // namespace bolt +} // namespace llvm + +TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) { + // Check perf input with SPE branch events as brstack format. + // Example collection command: + // ``` + // perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY + // ``` + // How Bolt extracts the branch events: + // ``` + // perf script -F pid,brstack --itrace=bl + // ``` + + opts::ArmSPE = true; + opts::ReadPerfEvents = " 1234 0xa001/0xa002/PN/-/-/10/COND/-\n" + " 1234 0xb001/0xb002/P/-/-/4/RET/-\n" + " 1234 0xc456/0xc789/P/-/-/13/-/-\n" + " 1234 0xd123/0xd456/M/-/-/7/RET/-\n" + " 1234 0xe001/0xe002/P/-/-/14/RET/-\n" + " 1234 0xd123/0xd456/M/-/-/7/RET/-\n" + " 1234 0xf001/0xf002/MN/-/-/8/COND/-\n" + " 1234 0xc456/0xc789/M/-/-/13/-/-\n"; + + // ExpectedSamples contains the aggregated information about + // a branch {{Branch From, To}, {TakenCount, MispredCount}}. + // Consider this example trace: {{0xd123, 0xd456, Trace::BR_ONLY}, + // {2,2}}. This entry has a TakenCount = 2, as we have two samples for + // (0xd123, 0xd456) in our input. It also has MispredsCount = 2, + // as 'M' misprediction flag appears in both cases. BR_ONLY means + // the trace only contains branch data. + std::vector> ExpectedSamples = { + {{0xa001, 0xa002, Trace::BR_ONLY}, {1, 0}}, + {{0xb001, 0xb002, Trace::BR_ONLY}, {1, 0}}, + {{0xc456, 0xc789, Trace::BR_ONLY}, {2, 1}}, + {{0xd123, 0xd456, Trace::BR_ONLY}, {2, 2}}, + {{0xe001, 0xe002, Trace::BR_ONLY}, {1, 0}}, + {{0xf001, 0xf002, Trace::BR_ONLY}, {1, 1}}}; + + parseAndCheckBrstackEvents(1234, ExpectedSamples); +} + +#endif diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index 57dd514b90a2..66852931226b 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -54,10 +54,8 @@ static llvm::Error decodeRecord(const Record &R, AccessSpecifier &Field, case AS_none: Field = (AccessSpecifier)R[0]; return llvm::Error::success(); - default: - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "invalid value for AccessSpecifier"); } + llvm_unreachable("invalid value for AccessSpecifier"); } static llvm::Error decodeRecord(const Record &R, TagTypeKind &Field, @@ -94,6 +92,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field, case InfoType::IT_default: case InfoType::IT_enum: case InfoType::IT_typedef: + case InfoType::IT_concept: Field = IT; return llvm::Error::success(); } @@ -110,6 +109,7 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field, case FieldId::F_type: case FieldId::F_child_namespace: case FieldId::F_child_record: + case FieldId::F_concept: case FieldId::F_default: Field = F; return llvm::Error::success(); @@ -393,6 +393,29 @@ static llvm::Error parseRecord(const Record &R, unsigned ID, "invalid field for TemplateParamInfo"); } +static llvm::Error parseRecord(const Record &R, unsigned ID, + llvm::StringRef Blob, ConceptInfo *I) { + switch (ID) { + case CONCEPT_USR: + return decodeRecord(R, I->USR, Blob); + case CONCEPT_NAME: + return decodeRecord(R, I->Name, Blob); + case CONCEPT_IS_TYPE: + return decodeRecord(R, I->IsType, Blob); + case CONCEPT_CONSTRAINT_EXPRESSION: + return decodeRecord(R, I->ConstraintExpression, Blob); + } + llvm_unreachable("invalid field for ConceptInfo"); +} + +static llvm::Error parseRecord(const Record &R, unsigned ID, + llvm::StringRef Blob, ConstraintInfo *I) { + if (ID == CONSTRAINT_EXPRESSION) + return decodeRecord(R, I->ConstraintExpr, Blob); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for ConstraintInfo"); +} + template static llvm::Expected getCommentInfo(T I) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain CommentInfo"); @@ -431,6 +454,10 @@ template <> llvm::Expected getCommentInfo(CommentInfo *I) { return I->Children.back().get(); } +template <> llvm::Expected getCommentInfo(ConceptInfo *I) { + return &I->Description.emplace_back(); +} + // When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on // the parent block to set it. The template specializations define what to do // for each supported parent block. @@ -586,6 +613,17 @@ template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) { } } +template <> +llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) { + if (F == FieldId::F_concept) { + I->ConceptRef = std::move(R); + return llvm::Error::success(); + } + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "ConstraintInfo cannot contain this Reference"); +} + template static void addChild(T I, ChildInfoType &&R) { llvm::errs() << "invalid child type for info"; @@ -602,6 +640,9 @@ template <> void addChild(NamespaceInfo *I, EnumInfo &&R) { template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) { I->Children.Typedefs.emplace_back(std::move(R)); } +template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) { + I->Children.Concepts.emplace_back(std::move(R)); +} // Record children: template <> void addChild(RecordInfo *I, FunctionInfo &&R) { @@ -651,6 +692,9 @@ template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) { template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) { I->Template.emplace(std::move(P)); } +template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) { + I->Template = std::move(P); +} // Template specializations go only into template records. template @@ -664,6 +708,14 @@ void addTemplateSpecialization(TemplateInfo *I, I->Specialization.emplace(std::move(TSI)); } +template static void addConstraint(T I, ConstraintInfo &&C) { + llvm::errs() << "invalid container for constraint info"; + exit(1); +} +template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) { + I->Constraints.emplace_back(std::move(C)); +} + // Read records from bitcode into a given info. template llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) { @@ -718,6 +770,8 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) { } } +// TODO: Create a helper that can receive a function to reduce repetition for +// most blocks. template llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { llvm::TimeTraceScope("Reducing infos", "readSubBlock"); @@ -819,6 +873,20 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { addChild(I, std::move(TI)); return llvm::Error::success(); } + case BI_CONSTRAINT_BLOCK_ID: { + ConstraintInfo CI; + if (auto Err = readBlock(ID, &CI)) + return Err; + addConstraint(I, std::move(CI)); + return llvm::Error::success(); + } + case BI_CONCEPT_BLOCK_ID: { + ConceptInfo CI; + if (auto Err = readBlock(ID, &CI)) + return Err; + addChild(I, std::move(CI)); + return llvm::Error::success(); + } default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid subblock type"); @@ -924,6 +992,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { return createInfo(ID); case BI_TYPEDEF_BLOCK_ID: return createInfo(ID); + case BI_CONCEPT_BLOCK_ID: + return createInfo(ID); case BI_FUNCTION_BLOCK_ID: return createInfo(ID); default: @@ -964,6 +1034,7 @@ ClangDocBitcodeReader::readBitcode() { case BI_RECORD_BLOCK_ID: case BI_ENUM_BLOCK_ID: case BI_TYPEDEF_BLOCK_ID: + case BI_CONCEPT_BLOCK_ID: case BI_FUNCTION_BLOCK_ID: { auto InfoOrErr = readBlockToInfo(ID); if (!InfoOrErr) diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index 708ce09d9e5b..b7308c012786 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -128,7 +128,9 @@ static const llvm::IndexedMap {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}, {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"}, {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"}, - {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}}; + {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}, + {BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"}, + {BI_CONCEPT_BLOCK_ID, "ConceptBlock"}}; assert(Inits.size() == BlockIdCount); for (const auto &Init : Inits) BlockIdNameMap[Init.first] = Init.second; @@ -205,7 +207,13 @@ static const llvm::IndexedMap {TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}}, {TYPEDEF_NAME, {"Name", &genStringAbbrev}}, {TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}}, - {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}}}; + {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}}, + {CONCEPT_USR, {"USR", &genSymbolIdAbbrev}}, + {CONCEPT_NAME, {"Name", &genStringAbbrev}}, + {CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}}, + {CONCEPT_CONSTRAINT_EXPRESSION, + {"ConstraintExpression", &genStringAbbrev}}, + {CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}}}; assert(Inits.size() == RecordIdCount); for (const auto &Init : Inits) { RecordIdNameMap[Init.first] = Init.second; @@ -263,7 +271,13 @@ static const std::vector>> // Template Blocks. {BI_TEMPLATE_BLOCK_ID, {}}, {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}}, - {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}}; + {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}, + // Concept Block + {BI_CONCEPT_BLOCK_ID, + {CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE, + CONCEPT_CONSTRAINT_EXPRESSION}}, + // Constraint Block + {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}}}; // AbbreviationMap @@ -524,6 +538,8 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) { emitBlock(C); for (const auto &C : I.Children.Typedefs) emitBlock(C); + for (const auto &C : I.Children.Concepts) + emitBlock(C); } void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) { @@ -627,12 +643,25 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) { emitBlock(*I.Template); } +void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) { + StreamSubBlockGuard Block(Stream, BI_CONCEPT_BLOCK_ID); + emitRecord(I.USR, CONCEPT_USR); + emitRecord(I.Name, CONCEPT_NAME); + for (const auto &CI : I.Description) + emitBlock(CI); + emitRecord(I.IsType, CONCEPT_IS_TYPE); + emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION); + emitBlock(I.Template); +} + void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) { StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID); for (const auto &P : T.Params) emitBlock(P); if (T.Specialization) emitBlock(*T.Specialization); + for (const auto &C : T.Constraints) + emitBlock(C); } void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) { @@ -647,6 +676,12 @@ void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) { emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS); } +void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) { + StreamSubBlockGuard Block(Stream, BI_CONSTRAINT_BLOCK_ID); + emitRecord(C.ConstraintExpr, CONSTRAINT_EXPRESSION); + emitBlock(C.ConceptRef, FieldId::F_concept); +} + bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { switch (I->IT) { case InfoType::IT_namespace: @@ -664,7 +699,10 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { case InfoType::IT_typedef: emitBlock(*static_cast(I)); break; - default: + case InfoType::IT_concept: + emitBlock(*static_cast(I)); + break; + case InfoType::IT_default: llvm::errs() << "Unexpected info, unable to write.\n"; return true; } diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h index e33a1aece883..4d0c0c07805e 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -66,7 +66,9 @@ enum BlockId { BI_TEMPLATE_BLOCK_ID, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, BI_TEMPLATE_PARAM_BLOCK_ID, + BI_CONSTRAINT_BLOCK_ID, BI_TYPEDEF_BLOCK_ID, + BI_CONCEPT_BLOCK_ID, BI_LAST, BI_FIRST = BI_VERSION_BLOCK_ID }; @@ -135,6 +137,11 @@ enum RecordId { TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING, + CONCEPT_USR, + CONCEPT_NAME, + CONCEPT_IS_TYPE, + CONCEPT_CONSTRAINT_EXPRESSION, + CONSTRAINT_EXPRESSION, RI_LAST, RI_FIRST = VERSION }; @@ -150,7 +157,8 @@ enum class FieldId { F_vparent, F_type, F_child_namespace, - F_child_record + F_child_record, + F_concept }; class ClangDocBitcodeWriter { @@ -179,6 +187,8 @@ public: void emitBlock(const TemplateInfo &T); void emitBlock(const TemplateSpecializationInfo &T); void emitBlock(const TemplateParamInfo &T); + void emitBlock(const ConceptInfo &T); + void emitBlock(const ConstraintInfo &T); void emitBlock(const Reference &B, FieldId F); private: diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index 7293a129177c..935bbfee7a9b 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -985,6 +985,8 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, MainContentNodes = genHTML(*static_cast(I), CDCtx, InfoTitle); break; + case InfoType::IT_concept: + break; case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "unexpected info type"); @@ -1011,6 +1013,8 @@ static std::string getRefType(InfoType IT) { return "enum"; case InfoType::IT_typedef: return "typedef"; + case InfoType::IT_concept: + return "concept"; } llvm_unreachable("Unknown InfoType"); } diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index 69c670b20844..81ba99c21e37 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -585,6 +585,8 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, case InfoType::IT_typedef: OS << "IT_typedef\n"; break; + case InfoType::IT_concept: + break; case InfoType::IT_default: return createStringError(inconvertibleErrorCode(), "unexpected InfoType"); } diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 0f7cbafcf513..8a37621597c6 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -26,6 +26,15 @@ static void serializeInfo(const TypedefInfo &I, json::Object &Obj, std::optional RepositoryUrl); static void serializeInfo(const EnumInfo &I, json::Object &Obj, std::optional RepositoryUrl); +static void serializeInfo(const ConstraintInfo &I, Object &Obj); + +// Convenience lambda to pass to serializeArray. +// If a serializeInfo needs a RepositoryUrl, create a local lambda that captures +// the optional. +static auto SerializeInfoLambda = [](const ConstraintInfo &Info, + Object &Object) { + serializeInfo(Info, Object); +}; static json::Object serializeLocation(const Location &Loc, std::optional RepositoryUrl) { @@ -248,6 +257,27 @@ static void serializeCommonChildren(const ScopeChildren &Children, } } +template +static void serializeArray(const std::vector &Records, Object &Obj, + const std::string &Key, + SerializationFunc SerializeInfo) { + json::Value RecordsArray = Array(); + auto &RecordsArrayRef = *RecordsArray.getAsArray(); + RecordsArrayRef.reserve(Records.size()); + for (const auto &Item : Records) { + json::Value ItemVal = Object(); + auto &ItemObj = *ItemVal.getAsObject(); + SerializeInfo(Item, ItemObj); + RecordsArrayRef.push_back(ItemVal); + } + Obj[Key] = RecordsArray; +} + +static void serializeInfo(const ConstraintInfo &I, Object &Obj) { + serializeReference(I.ConceptRef, Obj); + Obj["Expression"] = I.ConstraintExpr; +} + static void serializeInfo(const TemplateInfo &Template, Object &Obj) { json::Value TemplateVal = Object(); auto &TemplateObj = *TemplateVal.getAsObject(); @@ -277,9 +307,21 @@ static void serializeInfo(const TemplateInfo &Template, Object &Obj) { TemplateObj["Parameters"] = ParamsArray; } + if (!Template.Constraints.empty()) + serializeArray(Template.Constraints, TemplateObj, "Constraints", + SerializeInfoLambda); + Obj["Template"] = TemplateVal; } +static void serializeInfo(const ConceptInfo &I, Object &Obj, + std::optional RepositoryUrl) { + serializeCommonAttributes(I, Obj, RepositoryUrl); + Obj["IsType"] = I.IsType; + Obj["ConstraintExpression"] = I.ConstraintExpression; + serializeInfo(I.Template, Obj); +} + static void serializeInfo(const TypeInfo &I, Object &Obj) { Obj["Name"] = I.Type.Name; Obj["QualName"] = I.Type.QualName; @@ -457,6 +499,10 @@ static void serializeInfo(const NamespaceInfo &I, json::Object &Obj, Obj["Namespaces"] = NamespacesArray; } + auto SerializeInfo = [RepositoryUrl](const auto &Info, Object &Object) { + serializeInfo(Info, Object, RepositoryUrl); + }; + if (!I.Children.Functions.empty()) { json::Value FunctionsArray = Array(); auto &FunctionsArrayRef = *FunctionsArray.getAsArray(); @@ -470,6 +516,9 @@ static void serializeInfo(const NamespaceInfo &I, json::Object &Obj, Obj["Functions"] = FunctionsArray; } + if (!I.Children.Concepts.empty()) + serializeArray(I.Children.Concepts, Obj, "Concepts", SerializeInfo); + serializeCommonChildren(I.Children, Obj, RepositoryUrl); } @@ -520,6 +569,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS, case InfoType::IT_record: serializeInfo(*static_cast(I), Obj, CDCtx.RepositoryUrl); break; + case InfoType::IT_concept: case InfoType::IT_enum: case InfoType::IT_function: case InfoType::IT_typedef: diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp index 2becccf8b07d..6e68e09cfa2a 100644 --- a/clang-tools-extra/clang-doc/MDGenerator.cpp +++ b/clang-tools-extra/clang-doc/MDGenerator.cpp @@ -372,6 +372,9 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) { case InfoType::IT_typedef: Type = "Typedef"; break; + case InfoType::IT_concept: + Type = "Concept"; + break; case InfoType::IT_default: Type = "Other"; } @@ -464,6 +467,8 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, case InfoType::IT_typedef: genMarkdown(CDCtx, *static_cast(I), OS); break; + case InfoType::IT_concept: + break; case InfoType::IT_default: return createStringError(llvm::inconvertibleErrorCode(), "unexpected InfoType"); diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp index 9f640b5325da..6021e17b4696 100644 --- a/clang-tools-extra/clang-doc/Mapper.cpp +++ b/clang-tools-extra/clang-doc/Mapper.cpp @@ -134,6 +134,10 @@ bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl *D) { return mapDecl(D, /*isDefinition=*/true); } +bool MapASTVisitor::VisitConceptDecl(const ConceptDecl *D) { + return mapDecl(D, true); +} + comments::FullComment * MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const { RawComment *Comment = Context.getRawCommentForDeclNoCache(D); diff --git a/clang-tools-extra/clang-doc/Mapper.h b/clang-tools-extra/clang-doc/Mapper.h index 36322ea2bfb7..04dc5450c8ba 100644 --- a/clang-tools-extra/clang-doc/Mapper.h +++ b/clang-tools-extra/clang-doc/Mapper.h @@ -41,6 +41,7 @@ public: bool VisitFunctionDecl(const FunctionDecl *D); bool VisitTypedefDecl(const TypedefDecl *D); bool VisitTypeAliasDecl(const TypeAliasDecl *D); + bool VisitConceptDecl(const ConceptDecl *D); private: template bool mapDecl(const T *D, bool IsDefinition); diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 3ce930c6965d..286aeeea1001 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -143,10 +143,13 @@ mergeInfos(std::vector> &Values) { return reduce(Values); case InfoType::IT_typedef: return reduce(Values); - default: + case InfoType::IT_concept: + return reduce(Values); + case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "unexpected info type"); } + llvm_unreachable("unhandled enumerator"); } bool CommentInfo::operator==(const CommentInfo &Other) const { @@ -287,6 +290,7 @@ void NamespaceInfo::merge(NamespaceInfo &&Other) { reduceChildren(Children.Functions, std::move(Other.Children.Functions)); reduceChildren(Children.Enums, std::move(Other.Children.Enums)); reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs)); + reduceChildren(Children.Concepts, std::move(Other.Children.Concepts)); mergeBase(std::move(Other)); } @@ -351,6 +355,19 @@ void TypedefInfo::merge(TypedefInfo &&Other) { SymbolInfo::merge(std::move(Other)); } +void ConceptInfo::merge(ConceptInfo &&Other) { + assert(mergeable(Other)); + if (!IsType) + IsType = Other.IsType; + if (ConstraintExpression.empty()) + ConstraintExpression = std::move(Other.ConstraintExpression); + if (Template.Constraints.empty()) + Template.Constraints = std::move(Other.Template.Constraints); + if (Template.Params.empty()) + Template.Params = std::move(Other.Template.Params); + SymbolInfo::merge(std::move(Other)); +} + BaseRecordInfo::BaseRecordInfo() : RecordInfo() {} BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, @@ -387,6 +404,9 @@ llvm::SmallString<16> Info::extractName() const { case InfoType::IT_function: return llvm::SmallString<16>("@nonymous_function_" + toHex(llvm::toStringRef(USR))); + case InfoType::IT_concept: + return llvm::SmallString<16>("@nonymous_concept_" + + toHex(llvm::toStringRef(USR))); case InfoType::IT_default: return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR))); } @@ -452,6 +472,7 @@ void ScopeChildren::sort() { llvm::sort(Functions.begin(), Functions.end()); llvm::sort(Enums.begin(), Enums.end()); llvm::sort(Typedefs.begin(), Typedefs.end()); + llvm::sort(Concepts.begin(), Concepts.end()); } } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 75da50064581..b23069f2bd32 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -35,6 +35,7 @@ struct EnumInfo; struct FunctionInfo; struct Info; struct TypedefInfo; +struct ConceptInfo; enum class InfoType { IT_default, @@ -42,7 +43,8 @@ enum class InfoType { IT_record, IT_function, IT_enum, - IT_typedef + IT_typedef, + IT_concept }; enum class CommentKind { @@ -166,6 +168,7 @@ struct ScopeChildren { std::vector Functions; std::vector Enums; std::vector Typedefs; + std::vector Concepts; void sort(); }; @@ -211,6 +214,15 @@ struct TemplateSpecializationInfo { std::vector Params; }; +struct ConstraintInfo { + ConstraintInfo() = default; + ConstraintInfo(SymbolID USR, StringRef Name) + : ConceptRef(USR, Name, InfoType::IT_concept) {} + Reference ConceptRef; + + SmallString<16> ConstraintExpr; +}; + // Records the template information for a struct or function that is a template // or an explicit template specialization. struct TemplateInfo { @@ -219,6 +231,7 @@ struct TemplateInfo { // Set when this is a specialization of another record/function. std::optional Specialization; + std::vector Constraints; }; // Info for field types. @@ -513,6 +526,17 @@ struct EnumInfo : public SymbolInfo { llvm::SmallVector Members; // List of enum members. }; +struct ConceptInfo : public SymbolInfo { + ConceptInfo() : SymbolInfo(InfoType::IT_concept) {} + ConceptInfo(SymbolID USR) : SymbolInfo(InfoType::IT_concept, USR) {} + + void merge(ConceptInfo &&I); + + bool IsType; + TemplateInfo Template; + SmallString<16> ConstraintExpression; +}; + struct Index : public Reference { Index() = default; Index(StringRef Name) : Reference(SymbolID(), Name) {} diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 3cda38115ff7..5f3e5c37fa34 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -21,6 +21,17 @@ namespace clang { namespace doc { namespace serialize { +namespace { +static SmallString<16> exprToString(const clang::Expr *E) { + clang::LangOptions Opts; + clang::PrintingPolicy Policy(Opts); + SmallString<16> Result; + llvm::raw_svector_ostream OS(Result); + E->printPretty(OS, nullptr, Policy); + return Result; +} +} // namespace + SymbolID hashUSR(llvm::StringRef USR) { return llvm::SHA1::hash(arrayRefFromStringRef(USR)); } @@ -388,9 +399,13 @@ std::string serialize(std::unique_ptr &I) { return serialize(*static_cast(I.get())); case InfoType::IT_function: return serialize(*static_cast(I.get())); - default: + case InfoType::IT_concept: + return serialize(*static_cast(I.get())); + case InfoType::IT_typedef: + case InfoType::IT_default: return ""; } + llvm_unreachable("unhandled enumerator"); } static void parseFullComment(const FullComment *C, CommentInfo &CI) { @@ -489,6 +504,10 @@ static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) { Scope.Typedefs.push_back(std::move(Info)); } +static void InsertChild(ScopeChildren &Scope, ConceptInfo Info) { + Scope.Concepts.push_back(std::move(Info)); +} + // Creates a parent of the correct type for the given child and inserts it into // that parent. // @@ -525,9 +544,14 @@ static std::unique_ptr makeAndInsertIntoParent(ChildType Child) { InsertChild(ParentRec->Children, std::forward(Child)); return ParentRec; } - default: - llvm_unreachable("Invalid reference type for parent namespace"); + case InfoType::IT_default: + case InfoType::IT_enum: + case InfoType::IT_function: + case InfoType::IT_typedef: + case InfoType::IT_concept: + break; } + llvm_unreachable("Invalid reference type for parent namespace"); } // There are two uses for this function. @@ -734,6 +758,50 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, I.Loc.emplace_back(Loc); } +static void +handleCompoundConstraints(const Expr *Constraint, + std::vector &ConstraintInfos) { + if (Constraint->getStmtClass() == Stmt::ParenExprClass) { + handleCompoundConstraints(dyn_cast(Constraint)->getSubExpr(), + ConstraintInfos); + } else if (Constraint->getStmtClass() == Stmt::BinaryOperatorClass) { + auto *BinaryOpExpr = dyn_cast(Constraint); + handleCompoundConstraints(BinaryOpExpr->getLHS(), ConstraintInfos); + handleCompoundConstraints(BinaryOpExpr->getRHS(), ConstraintInfos); + } else if (Constraint->getStmtClass() == + Stmt::ConceptSpecializationExprClass) { + auto *Concept = dyn_cast(Constraint); + ConstraintInfo CI(getUSRForDecl(Concept->getNamedConcept()), + Concept->getNamedConcept()->getNameAsString()); + CI.ConstraintExpr = exprToString(Concept); + ConstraintInfos.push_back(CI); + } +} + +static void populateConstraints(TemplateInfo &I, const TemplateDecl *D) { + if (!D || !D->hasAssociatedConstraints()) + return; + + SmallVector AssociatedConstraints; + D->getAssociatedConstraints(AssociatedConstraints); + for (const auto &Constraint : AssociatedConstraints) { + if (!Constraint) + continue; + + // TODO: Investigate if atomic constraints need to be handled specifically. + if (const auto *ConstraintExpr = + dyn_cast_or_null( + Constraint.ConstraintExpr)) { + ConstraintInfo CI(getUSRForDecl(ConstraintExpr->getNamedConcept()), + ConstraintExpr->getNamedConcept()->getNameAsString()); + CI.ConstraintExpr = exprToString(ConstraintExpr); + I.Constraints.push_back(std::move(CI)); + } else { + handleCompoundConstraints(Constraint.ConstraintExpr, I.Constraints); + } + } +} + static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, Location Loc, bool &IsInAnonymousNamespace) { @@ -745,6 +813,8 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, I.IsStatic = D->isStatic(); populateTemplateParameters(I.Template, D); + if (I.Template) + populateConstraints(I.Template.value(), D->getDescribedFunctionTemplate()); // Handle function template specializations. if (const FunctionTemplateSpecializationInfo *FTSI = @@ -897,6 +967,8 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc, RI->Path = getInfoRelativePath(RI->Namespace); populateTemplateParameters(RI->Template, D); + if (RI->Template) + populateConstraints(RI->Template.value(), D->getDescribedTemplate()); // Full and partial specializations. if (auto *CTSD = dyn_cast(D)) { @@ -1068,6 +1140,30 @@ emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc, return {nullptr, makeAndInsertIntoParent(std::move(Enum))}; } +std::pair, std::unique_ptr> +emitInfo(const ConceptDecl *D, const FullComment *FC, const Location &Loc, + bool PublicOnly) { + ConceptInfo Concept; + + bool IsInAnonymousNamespace = false; + populateInfo(Concept, D, FC, IsInAnonymousNamespace); + Concept.IsType = D->isTypeConcept(); + Concept.DefLoc = Loc; + Concept.ConstraintExpression = exprToString(D->getConstraintExpr()); + + if (auto *ConceptParams = D->getTemplateParameters()) { + for (const auto *Param : ConceptParams->asArray()) { + Concept.Template.Params.emplace_back( + getSourceCode(Param, Param->getSourceRange())); + } + } + + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) + return {}; + + return {nullptr, makeAndInsertIntoParent(std::move(Concept))}; +} + } // namespace serialize } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h index 7e6cbb70721e..497b09bb339f 100644 --- a/clang-tools-extra/clang-doc/Serialize.h +++ b/clang-tools-extra/clang-doc/Serialize.h @@ -68,6 +68,10 @@ std::pair, std::unique_ptr> emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc, bool PublicOnly); +std::pair, std::unique_ptr> +emitInfo(const ConceptDecl *D, const FullComment *FC, const Location &Loc, + bool PublicOnly); + // Function to hash a given USR value for storage. // As USRs (Unified Symbol Resolution) could be large, especially for functions // with long type arguments, we use 160-bits SHA1(USR) values to diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp index 897b5d5ae4c9..f95887104698 100644 --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -408,6 +408,8 @@ llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, case InfoType::IT_typedef: InfoYAML << *static_cast(I); break; + case InfoType::IT_concept: + break; case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "unexpected InfoType"); diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp index ea0207619fb2..ada9122b587a 100644 --- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -19,6 +19,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/Refactoring.h" #include "llvm/ADT/STLExtras.h" @@ -50,6 +52,85 @@ static const RecordDecl *findDefinition(StringRef RecordName, return selectFirst("recordDecl", Results); } +static bool declaresMultipleFieldsInStatement(const RecordDecl *Decl) { + SourceLocation LastTypeLoc; + for (const auto &Field : Decl->fields()) { + SourceLocation TypeLoc = + Field->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + if (LastTypeLoc.isValid() && TypeLoc == LastTypeLoc) + return true; + LastTypeLoc = TypeLoc; + } + return false; +} + +static bool declaresMultipleFieldsInMacro(const RecordDecl *Decl, + const SourceManager &SrcMgr) { + SourceLocation LastMacroLoc; + for (const auto &Field : Decl->fields()) { + if (!Field->getLocation().isMacroID()) + continue; + SourceLocation MacroLoc = SrcMgr.getExpansionLoc(Field->getLocation()); + if (LastMacroLoc.isValid() && MacroLoc == LastMacroLoc) + return true; + LastMacroLoc = MacroLoc; + } + return false; +} + +static bool containsPreprocessorDirectives(const RecordDecl *Decl, + const SourceManager &SrcMgr, + const LangOptions &LangOpts) { + std::pair FileAndOffset = + SrcMgr.getDecomposedLoc(Decl->field_begin()->getBeginLoc()); + assert(!Decl->field_empty()); + auto LastField = Decl->field_begin(); + while (std::next(LastField) != Decl->field_end()) + ++LastField; + unsigned EndOffset = SrcMgr.getFileOffset(LastField->getEndLoc()); + StringRef SrcBuffer = SrcMgr.getBufferData(FileAndOffset.first); + Lexer L(SrcMgr.getLocForStartOfFile(FileAndOffset.first), LangOpts, + SrcBuffer.data(), SrcBuffer.data() + FileAndOffset.second, + SrcBuffer.data() + SrcBuffer.size()); + IdentifierTable Identifiers(LangOpts); + clang::Token T; + while (!L.LexFromRawLexer(T) && L.getCurrentBufferOffset() < EndOffset) { + if (T.getKind() == tok::hash) { + L.LexFromRawLexer(T); + if (T.getKind() == tok::raw_identifier) { + clang::IdentifierInfo &II = Identifiers.get(T.getRawIdentifier()); + if (II.getPPKeywordID() != clang::tok::pp_not_keyword) + return true; + } + } + } + return false; +} + +static bool isSafeToRewrite(const RecordDecl *Decl, const ASTContext &Context) { + // All following checks expect at least one field declaration. + if (Decl->field_empty()) + return true; + + // Don't attempt to rewrite if there is a declaration like 'int a, b;'. + if (declaresMultipleFieldsInStatement(Decl)) + return false; + + const SourceManager &SrcMgr = Context.getSourceManager(); + + // Don't attempt to rewrite if a single macro expansion creates multiple + // fields. + if (declaresMultipleFieldsInMacro(Decl, SrcMgr)) + return false; + + // Prevent rewriting if there are preprocessor directives present between the + // start of the first field and the end of last field. + if (containsPreprocessorDirectives(Decl, SrcMgr, Context.getLangOpts())) + return false; + + return true; +} + /// Calculates the new order of fields. /// /// \returns empty vector if the list of fields doesn't match the definition. @@ -86,6 +167,10 @@ getNewFieldsOrder(const RecordDecl *Definition, static void addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context, std::map &Replacements) { + if (Old.getBegin().isMacroID()) + Old = Context.getSourceManager().getExpansionRange(Old).getAsRange(); + if (New.getBegin().isMacroID()) + New = Context.getSourceManager().getExpansionRange(New).getAsRange(); StringRef NewText = Lexer::getSourceText(CharSourceRange::getTokenRange(New), Context.getSourceManager(), Context.getLangOpts()); @@ -341,6 +426,8 @@ public: const RecordDecl *RD = findDefinition(RecordName, Context); if (!RD) return; + if (!isSafeToRewrite(RD, Context)) + return; SmallVector NewFieldsOrder = getNewFieldsOrder(RD, DesiredFieldsOrder); if (NewFieldsOrder.empty()) diff --git a/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp index bedecb60569e..203170d55f69 100644 --- a/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp @@ -702,17 +702,16 @@ void NotNullTerminatedResultCheck::registerMatchers(MatchFinder *Finder) { return hasArgument( CC.LengthPos, allOf( - anyOf( - ignoringImpCasts(integerLiteral().bind(WrongLengthExprName)), - allOf(unless(hasDefinition(SizeOfCharExpr)), - allOf(CC.WithIncrease - ? ignoringImpCasts(hasDefinition(HasIncOp)) - : ignoringImpCasts(allOf( - unless(hasDefinition(HasIncOp)), - anyOf(hasDefinition(binaryOperator().bind( - UnknownLengthName)), - hasDefinition(anything())))), - AnyOfWrongLengthInit))), + anyOf(ignoringImpCasts(integerLiteral().bind(WrongLengthExprName)), + allOf(unless(hasDefinition(SizeOfCharExpr)), + allOf(CC.WithIncrease + ? ignoringImpCasts(hasDefinition(HasIncOp)) + : ignoringImpCasts( + allOf(unless(hasDefinition(HasIncOp)), + hasDefinition(optionally( + binaryOperator().bind( + UnknownLengthName))))), + AnyOfWrongLengthInit))), expr().bind(LengthExprName))); }; diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp index 8ffa44d41fa9..b14587ad7db8 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp @@ -17,8 +17,20 @@ namespace { AST_MATCHER(GotoStmt, isForwardJumping) { return Node.getBeginLoc() < Node.getLabel()->getBeginLoc(); } + +AST_MATCHER(GotoStmt, isInMacro) { + return Node.getBeginLoc().isMacroID() && Node.getEndLoc().isMacroID(); +} } // namespace +AvoidGotoCheck::AvoidGotoCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreMacros(Options.get("IgnoreMacros", false)) {} + +void AvoidGotoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreMacros", IgnoreMacros); +} + void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) { // TODO: This check does not recognize `IndirectGotoStmt` which is a // GNU extension. These must be matched separately and an AST matcher @@ -29,7 +41,10 @@ void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) { auto Loop = mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt); auto NestedLoop = Loop.with(hasAncestor(Loop)); - Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)), + const ast_matchers::internal::Matcher Anything = anything(); + + Finder->addMatcher(gotoStmt(IgnoreMacros ? unless(isInMacro()) : Anything, + anyOf(unless(hasAncestor(NestedLoop)), unless(isForwardJumping()))) .bind("goto"), this); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h index 883ba78855e7..8eae409462c9 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h @@ -20,13 +20,16 @@ namespace clang::tidy::cppcoreguidelines { /// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-goto.html class AvoidGotoCheck : public ClangTidyCheck { public: - AvoidGotoCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + AvoidGotoCheck(StringRef Name, ClangTidyContext *Context); bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const bool IgnoreMacros; }; } // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt index b023f76a2543..2fb4d7f1d734 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -33,6 +33,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule STATIC RvalueReferenceParamNotMovedCheck.cpp SlicingCheck.cpp SpecialMemberFunctionsCheck.cpp + UseEnumClassCheck.cpp VirtualClassDestructorCheck.cpp LINK_LIBS diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index 4dd9b0904f07..4b3b7bf963fd 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -48,6 +48,7 @@ #include "RvalueReferenceParamNotMovedCheck.h" #include "SlicingCheck.h" #include "SpecialMemberFunctionsCheck.h" +#include "UseEnumClassCheck.h" #include "VirtualClassDestructorCheck.h" namespace clang::tidy { @@ -131,6 +132,8 @@ public: CheckFactories.registerCheck("cppcoreguidelines-slicing"); CheckFactories.registerCheck( "cppcoreguidelines-use-default-member-init"); + CheckFactories.registerCheck( + "cppcoreguidelines-use-enum-class"); CheckFactories.registerCheck( "cppcoreguidelines-c-copy-assignment-signature"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp new file mode 100644 index 000000000000..ec7d9237afa3 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp @@ -0,0 +1,42 @@ +//===--- UseEnumClassCheck.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 "UseEnumClassCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::cppcoreguidelines { + +UseEnumClassCheck::UseEnumClassCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreUnscopedEnumsInClasses( + Options.get("IgnoreUnscopedEnumsInClasses", false)) {} + +void UseEnumClassCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreUnscopedEnumsInClasses", + IgnoreUnscopedEnumsInClasses); +} + +void UseEnumClassCheck::registerMatchers(MatchFinder *Finder) { + auto EnumDecl = + IgnoreUnscopedEnumsInClasses + ? enumDecl(unless(isScoped()), unless(hasParent(recordDecl()))) + : enumDecl(unless(isScoped())); + Finder->addMatcher(EnumDecl.bind("unscoped_enum"), this); +} + +void UseEnumClassCheck::check(const MatchFinder::MatchResult &Result) { + const auto *UnscopedEnum = Result.Nodes.getNodeAs("unscoped_enum"); + + diag(UnscopedEnum->getLocation(), + "enum %0 is unscoped, use 'enum class' instead") + << UnscopedEnum; +} + +} // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h new file mode 100644 index 000000000000..dfa4b7e3fda6 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h @@ -0,0 +1,40 @@ +//===--- UseEnumClassCheck.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_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::cppcoreguidelines { + +/// Finds unscoped (non-class) enum declarations and suggests using enum class +/// instead. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/use-enum-class.html +class UseEnumClassCheck : public ClangTidyCheck { +public: + UseEnumClassCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) 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.CPlusPlus11; + } + std::optional getCheckTraversalKind() const override { + return TraversalKind::TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool IgnoreUnscopedEnumsInClasses; +}; + +} // namespace clang::tidy::cppcoreguidelines + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H diff --git a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp index 2b2acfdf5b08..ed39568ea554 100644 --- a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp +++ b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp @@ -24,14 +24,12 @@ void ExceptionBaseclassCheck::registerMatchers(MatchFinder *Finder) { isSameOrDerivedFrom(hasName("::std::exception")))))))))), // This condition is always true, but will bind to the // template value if the thrown type is templated. - anyOf(has(expr( - hasType(substTemplateTypeParmType().bind("templ_type")))), - anything()), + optionally(has( + expr(hasType(substTemplateTypeParmType().bind("templ_type"))))), // Bind to the declaration of the type of the value that - // is thrown. 'anything()' is necessary to always succeed - // in the 'eachOf' because builtin types are not - // 'namedDecl'. - eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything())) + // is thrown. 'optionally' is necessary because builtin types + // are not 'namedDecl'. + optionally(has(expr(hasType(namedDecl().bind("decl")))))) .bind("bad_throw"), this); } diff --git a/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp b/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp index faff1c17fc61..37fbd8c0d725 100644 --- a/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp @@ -38,8 +38,7 @@ void StaticAssertCheck::registerMatchers(MatchFinder *Finder) { binaryOperator( hasAnyOperatorName("&&", "=="), hasEitherOperand(ignoringImpCasts(stringLiteral().bind("assertMSG"))), - anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)), - anything())) + optionally(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)))) .bind("assertExprRoot"), IsAlwaysFalse); auto NonConstexprFunctionCall = @@ -52,12 +51,10 @@ void StaticAssertCheck::registerMatchers(MatchFinder *Finder) { auto NonConstexprCode = expr(anyOf(NonConstexprFunctionCall, NonConstexprVariableReference)); auto AssertCondition = - expr( - anyOf(expr(ignoringParenCasts(anyOf( - AssertExprRoot, unaryOperator(hasUnaryOperand( - ignoringParenCasts(AssertExprRoot)))))), - anything()), - unless(NonConstexprCode), unless(hasDescendant(NonConstexprCode))) + expr(optionally(expr(ignoringParenCasts(anyOf( + AssertExprRoot, unaryOperator(hasUnaryOperand( + ignoringParenCasts(AssertExprRoot))))))), + unless(NonConstexprCode), unless(hasDescendant(NonConstexprCode))) .bind("condition"); auto Condition = anyOf(ignoringParenImpCasts(callExpr( diff --git a/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp index c8e6bf47bb82..339462093a6d 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp @@ -26,13 +26,12 @@ void UseBoolLiteralsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void UseBoolLiteralsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - traverse( - TK_AsIs, - implicitCastExpr( - has(ignoringParenImpCasts(integerLiteral().bind("literal"))), - hasImplicitDestinationType(qualType(booleanType())), - unless(isInTemplateInstantiation()), - anyOf(hasParent(explicitCastExpr().bind("cast")), anything()))), + traverse(TK_AsIs, + implicitCastExpr( + has(ignoringParenImpCasts(integerLiteral().bind("literal"))), + hasImplicitDestinationType(qualType(booleanType())), + unless(isInTemplateInstantiation()), + optionally(hasParent(explicitCastExpr().bind("cast"))))), this); Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp index c02c5dfa8756..eeba5cce80da 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp @@ -39,28 +39,21 @@ intCastExpression(bool IsSigned, // 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). - const auto HasIntegerType = hasType(hasCanonicalType(qualType( + auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType( isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(), - unless(isActualChar()), unless(booleanType()), unless(enumType())))); - - const auto IntTypeExpr = expr(HasIntegerType); + unless(isActualChar()), unless(booleanType()), unless(enumType()))))); const auto ImplicitCastExpr = CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr)) : implicitCastExpr(hasSourceExpression(IntTypeExpr)) .bind(CastBindName); - const auto ExplicitCastExpr = - anyOf(explicitCastExpr(has(ImplicitCastExpr)), - ignoringImpCasts(explicitCastExpr(has(ImplicitCastExpr)))); + const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr)); + const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr)); + const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr)); - // Match function calls or variable references not directly wrapped by an - // implicit cast - const auto CallIntExpr = CastBindName.empty() - ? callExpr(HasIntegerType) - : callExpr(HasIntegerType).bind(CastBindName); - - return expr(anyOf(ImplicitCastExpr, ExplicitCastExpr, CallIntExpr)); + return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr, + FunctionalCastExpr)); } static StringRef parseOpCode(BinaryOperator::Opcode Code) { diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp index a877f9a7ee91..d89c3a69fc84 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -50,7 +50,8 @@ UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()), AllowedTypes( - utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} + utils::options::parseStringList(Options.get("AllowedTypes", ""))), + IgnoreCoroutines(Options.get("IgnoreCoroutines", true)) {} void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) { const auto ExpensiveValueParamDecl = parmVarDecl( @@ -61,12 +62,14 @@ void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) { matchers::matchesAnyListedName(AllowedTypes))))))), decl().bind("param")); Finder->addMatcher( - traverse( - TK_AsIs, - functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()), - unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))), - has(typeLoc(forEach(ExpensiveValueParamDecl))), - decl().bind("functionDecl"))), + traverse(TK_AsIs, + functionDecl( + hasBody(IgnoreCoroutines ? stmt(unless(coroutineBodyStmt())) + : stmt()), + isDefinition(), unless(isImplicit()), + unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))), + has(typeLoc(forEach(ExpensiveValueParamDecl))), + decl().bind("functionDecl"))), this); } @@ -123,6 +126,7 @@ void UnnecessaryValueParamCheck::storeOptions( Options.store(Opts, "IncludeStyle", Inserter.getStyle()); Options.store(Opts, "AllowedTypes", utils::options::serializeStringList(AllowedTypes)); + Options.store(Opts, "IgnoreCoroutines", IgnoreCoroutines); } void UnnecessaryValueParamCheck::onEndOfTranslationUnit() { diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h index 8bfd814d1635..b52043416e76 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h @@ -46,6 +46,7 @@ private: ExprMutationAnalyzer::Memoized MutationAnalyzerCache; utils::IncludeInserter Inserter; const std::vector AllowedTypes; + bool IgnoreCoroutines; }; } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp index 3313bcb39b7f..8e3a2e306dbf 100644 --- a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp @@ -108,6 +108,14 @@ public: return true; } + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + if (CountMemberInitAsStmt) + ++Info.Statements; + + Base::TraverseConstructorInitializer(Init); + return true; + } + struct FunctionInfo { unsigned Lines = 0; unsigned Statements = 0; @@ -120,6 +128,7 @@ public: llvm::BitVector TrackedParent; unsigned StructNesting = 0; unsigned CurrentNestingLevel = 0; + bool CountMemberInitAsStmt; }; } // namespace @@ -135,7 +144,9 @@ FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context) NestingThreshold( Options.get("NestingThreshold", DefaultNestingThreshold)), VariableThreshold( - Options.get("VariableThreshold", DefaultVariableThreshold)) {} + Options.get("VariableThreshold", DefaultVariableThreshold)), + CountMemberInitAsStmt( + Options.get("CountMemberInitAsStmt", DefaultCountMemberInitAsStmt)) {} void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "LineThreshold", LineThreshold); @@ -144,6 +155,7 @@ void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "ParameterThreshold", ParameterThreshold); Options.store(Opts, "NestingThreshold", NestingThreshold); Options.store(Opts, "VariableThreshold", VariableThreshold); + Options.store(Opts, "CountMemberInitAsStmt", CountMemberInitAsStmt); } void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) { @@ -160,6 +172,7 @@ void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) { FunctionASTVisitor Visitor; Visitor.Info.NestingThreshold = NestingThreshold.value_or(-1); + Visitor.CountMemberInitAsStmt = CountMemberInitAsStmt; Visitor.TraverseDecl(const_cast(Func)); auto &FI = Visitor.Info; diff --git a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h index 106c69ff0739..f668ab18fea5 100644 --- a/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h +++ b/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h @@ -47,6 +47,7 @@ private: const std::optional ParameterThreshold; const std::optional NestingThreshold; const std::optional VariableThreshold; + const bool CountMemberInitAsStmt; static constexpr std::optional DefaultLineThreshold = std::nullopt; static constexpr std::optional DefaultStatementThreshold = 800U; @@ -58,6 +59,7 @@ private: std::nullopt; static constexpr std::optional DefaultVariableThreshold = std::nullopt; + static constexpr bool DefaultCountMemberInitAsStmt = true; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index f9fd1d903e23..20c73299915a 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -348,8 +348,8 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { implicitCastExpr().bind("implicitCastFromBool"), unless(hasParent(BitfieldConstruct)), // Check also for nested casts, for example: bool -> int -> float. - anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")), - anything()), + optionally( + hasParent(implicitCastExpr().bind("furtherImplicitCast"))), unless(isInTemplateInstantiation()), unless(IsInCompilerGeneratedFunction))), this); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index 29321f7cd3fa..a703009e2b46 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -494,9 +494,9 @@ static std::vector semanticTokenModifiers() { void ClangdLSPServer::onInitialize(const InitializeParams &Params, Callback Reply) { // Determine character encoding first as it affects constructed ClangdServer. - if (Params.capabilities.offsetEncoding && !Opts.Encoding) { + if (Params.capabilities.PositionEncodings && !Opts.Encoding) { Opts.Encoding = OffsetEncoding::UTF16; // fallback - for (OffsetEncoding Supported : *Params.capabilities.offsetEncoding) + for (OffsetEncoding Supported : *Params.capabilities.PositionEncodings) if (Supported != OffsetEncoding::UnsupportedEncoding) { Opts.Encoding = Supported; break; @@ -686,6 +686,9 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, ServerCaps["executeCommandProvider"] = llvm::json::Object{{"commands", Commands}}; + if (Opts.Encoding) + ServerCaps["positionEncoding"] = *Opts.Encoding; + llvm::json::Object Result{ {{"serverInfo", llvm::json::Object{ @@ -693,6 +696,9 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, {"version", llvm::formatv("{0} {1} {2}", versionString(), featureString(), platformString())}}}, {"capabilities", std::move(ServerCaps)}}}; + + // TODO: offsetEncoding capability is a deprecated clangd extension and should + // be deleted. if (Opts.Encoding) Result["offsetEncoding"] = *Opts.Encoding; Reply(std::move(Result)); diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index c9e8a175b5d7..2c858e28fa24 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -497,10 +497,19 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R, if (auto Cancel = StaleRequestSupport->getBoolean("cancel")) R.CancelsStaleRequests = *Cancel; } + if (auto *PositionEncodings = General->get("positionEncodings")) { + R.PositionEncodings.emplace(); + if (!fromJSON(*PositionEncodings, *R.PositionEncodings, + P.field("general").field("positionEncodings"))) + return false; + } } if (auto *OffsetEncoding = O->get("offsetEncoding")) { - R.offsetEncoding.emplace(); - if (!fromJSON(*OffsetEncoding, *R.offsetEncoding, + R.PositionEncodings.emplace(); + elog("offsetEncoding capability is a deprecated clangd extension that'll " + "go away with clangd 23. Migrate to standard positionEncodings " + "capability introduced by LSP 3.17"); + if (!fromJSON(*OffsetEncoding, *R.PositionEncodings, P.field("offsetEncoding"))) return false; } @@ -536,8 +545,11 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R, } } if (auto *OffsetEncoding = Experimental->get("offsetEncoding")) { - R.offsetEncoding.emplace(); - if (!fromJSON(*OffsetEncoding, *R.offsetEncoding, + R.PositionEncodings.emplace(); + elog("offsetEncoding capability is a deprecated clangd extension that'll " + "go away with clangd 23. Migrate to standard positionEncodings " + "capability introduced by LSP 3.17"); + if (!fromJSON(*OffsetEncoding, *R.PositionEncodings, P.field("offsetEncoding"))) return false; } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 8a7809d6677e..3a6bf155ee15 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -528,8 +528,9 @@ struct ClientCapabilities { /// textDocument.semanticHighlightingCapabilities.semanticHighlighting bool TheiaSemanticHighlighting = false; - /// Supported encodings for LSP character offsets. (clangd extension). - std::optional> offsetEncoding; + /// Supported encodings for LSP character offsets. + /// general.positionEncodings + std::optional> PositionEncodings; /// The content format that should be used for Hover requests. /// textDocument.hover.contentEncoding diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp index d9b73b83e902..c56375b1a98d 100644 --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -1308,7 +1308,7 @@ getMappedRanges(ArrayRef Indexed, ArrayRef Lexed) { return std::nullopt; } // Fast check for the special subset case. - if (std::includes(Indexed.begin(), Indexed.end(), Lexed.begin(), Lexed.end())) + if (llvm::includes(Indexed, Lexed)) return Lexed.vec(); std::vector Best; diff --git a/clang-tools-extra/clangd/test/positionencoding.test b/clang-tools-extra/clangd/test/positionencoding.test new file mode 100644 index 000000000000..eea7a1a596e9 --- /dev/null +++ b/clang-tools-extra/clangd/test/positionencoding.test @@ -0,0 +1,32 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s +# This test verifies that we can negotiate UTF-8 offsets via the positionEncodings capability introduced in LSP 3.17. +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"general":{"positionEncodings":["utf-8","utf-16"]}},"trace":"off"}} +# CHECK: "positionEncoding": "utf-8" +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"/*ö*/int x;\nint y=x;"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":1,"character":6}}} +# /*ö*/int x; +# 01234567890 +# x is character (and utf-16) range [9,10) but byte range [10,11). +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": [ +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 11, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 10, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "uri": "file://{{.*}}/main.cpp" +# CHECK-NEXT: } +# CHECK-NEXT: ] +--- +{"jsonrpc":"2.0","id":10000,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 69f6df46c87c..775278ccf694 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -974,7 +974,7 @@ class Foo final {})cpp"; HI.Name = "abc"; HI.Kind = index::SymbolKind::Variable; HI.NamespaceScope = ""; - HI.Definition = "int abc = ()"; + HI.Definition = "int abc"; HI.Type = "int"; HI.AccessSpecifier = "public"; }}, diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index 1892f87c8e82..b04d6431f89f 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -2311,6 +2311,14 @@ TEST(FindReferences, WithinAST) { $(S::deleteObject)[[de^lete]] S; } }; + )cpp", + // Array designators + R"cpp( + const int $def[[F^oo]] = 0; + int Bar[] = { + [$(Bar)[[F^oo]]...$(Bar)[[Fo^o]] + 1] = 0, + [$(Bar)[[^Foo]] + 2] = 1 + }; )cpp"}; for (const char *Test : Tests) checkFindRefs(Test); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 882ee0015df1..bcd843fc5179 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,6 +136,12 @@ New checks Finds unintended character output from ``unsigned char`` and ``signed char`` to an ``ostream``. +- New :doc:`cppcoreguidelines-use-enum-class + ` check. + + Finds unscoped (non-class) ``enum`` declarations and suggests using + ``enum class`` instead. + - New :doc:`portability-avoid-pragma-once ` check. @@ -191,11 +197,19 @@ Changes in existing checks ` check by fixing a false positive where ``strerror`` was flagged as MT-unsafe. +- Improved :doc:`cppcoreguidelines-avoid-goto + ` check by adding the option + `IgnoreMacros` to ignore ``goto`` labels defined in macros. + - Improved :doc:`google-readability-namespace-comments ` check by adding the option `AllowOmittingNamespaceComments` to accept if a namespace comment is omitted entirely. +- Improved :doc:`hicpp-avoid-goto + ` check by adding the option + `IgnoreMacros` to ignore ``goto`` labels defined in macros. + - Improved :doc:`llvm-namespace-comment ` check by adding the option `AllowOmittingNamespaceComments` to accept if a namespace comment is omitted @@ -237,10 +251,6 @@ Changes in existing checks ` check by avoiding diagnosing designated initializers for ``std::array`` initializations. -- Improved :doc:`modernize-use-integer-sign-comparison - ` check by matching - valid integer expressions not directly wrapped around an implicit cast. - - Improved :doc:`modernize-use-ranges ` check by updating suppress warnings logic for ``nullptr`` in ``std::find``. @@ -269,11 +279,18 @@ Changes in existing checks ` check performance by tolerating fix-it breaking compilation when functions is used as pointers to avoid matching usage of functions within the current compilation unit. + Added an option `IgnoreCoroutines` with the default value `true` to + suppress this check for coroutines where passing by reference may be unsafe. - Improved :doc:`readability-convert-member-functions-to-static ` check by fixing false positives on member functions with an explicit object parameter. +- Improved :doc:`readability-function-size + ` check by adding new option + `CountMemberInitAsStmt` that allows counting class member initializers in + constructors as statements. + - Improved :doc:`readability-math-missing-parentheses ` check by fixing false negatives where math expressions are the operand of assignment operators diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-goto.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-goto.rst index 71b579a4ae99..1f9dc0a1edb3 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-goto.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-goto.rst @@ -50,3 +50,12 @@ Modern C++ needs ``goto`` only to jump out of nested loops. some_operation(); All other uses of ``goto`` are diagnosed in `C++`. + + +Options +------- + +.. option:: IgnoreMacros + + If set to `true`, the check will not warn if a ``goto`` statement is + expanded from a macro. Default is `false`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst new file mode 100644 index 000000000000..9e9f4c99dc24 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst @@ -0,0 +1,35 @@ +.. title:: clang-tidy - cppcoreguidelines-use-enum-class + +cppcoreguidelines-use-enum-class +================================ + +Finds unscoped (non-class) ``enum`` declarations and suggests using +``enum class`` instead. + +This check implements `Enum.3 +`_ +from the C++ Core Guidelines." + +Example: + +.. code-block:: c++ + + enum E {}; // use "enum class E {};" instead + enum class E {}; // OK + + struct S { + enum E {}; // use "enum class E {};" instead + // OK with option IgnoreUnscopedEnumsInClasses + }; + + namespace N { + enum E {}; // use "enum class E {};" instead + } + +Options +------- + +.. option:: IgnoreUnscopedEnumsInClasses + + When `true`, ignores unscoped ``enum`` declarations in classes. + Default is `false`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 5a79d61b1fd7..ccb78ee45e9c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -212,6 +212,7 @@ Clang-Tidy Checks :doc:`cppcoreguidelines-rvalue-reference-param-not-moved `, :doc:`cppcoreguidelines-slicing `, :doc:`cppcoreguidelines-special-member-functions `, + :doc:`cppcoreguidelines-use-enum-class `, :doc:`cppcoreguidelines-virtual-class-destructor `, "Yes" :doc:`darwin-avoid-spinlock `, :doc:`darwin-dispatch-once-nonstatic `, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/enum-size.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/enum-size.rst index f72b8c7eabc2..b7631139a013 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/enum-size.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/enum-size.rst @@ -34,7 +34,7 @@ dependent). .. code-block:: c++ // AFTER - enum Color : std:int8_t { + enum Color : std::int8_t { RED = -1, GREEN = 0, BLUE = 1 diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-value-param.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-value-param.rst index dc86530b95f1..cd25d7d94d99 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-value-param.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-value-param.rst @@ -56,7 +56,7 @@ Will become: Because the fix-it needs to change the signature of the function, it may break builds if the function is used in multiple translation units or some codes -depends on funcion signatures. +depends on function signatures. Options ------- @@ -74,3 +74,10 @@ Options default is empty. If a name in the list contains the sequence `::`, it is matched against the qualified type name (i.e. ``namespace::Type``), otherwise it is matched against only the type name (i.e. ``Type``). + +.. option:: IgnoreCoroutines + + A boolean specifying whether the check should suggest passing parameters by + reference in coroutines. Passing parameters by reference in coroutines may + not be safe, please see :doc:`cppcoreguidelines-avoid-reference-coroutine-parameters <../cppcoreguidelines/avoid-reference-coroutine-parameters>` + for more information. Default is `true`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst index 133bd3e9c8cb..253e7c483cb8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/function-size.rst @@ -43,3 +43,8 @@ Options The default is `none` (ignore the number of variables). Please note that function parameters and variables declared in lambdas, GNU Statement Expressions, and nested class inline functions are not counted. + +.. option:: CountMemberInitAsStmt + + When `true`, count class member initializers in constructors as statements. + Default is `true`. diff --git a/clang-tools-extra/modularize/CoverageChecker.cpp b/clang-tools-extra/modularize/CoverageChecker.cpp index fe6711398ab7..1345a6ef8f48 100644 --- a/clang-tools-extra/modularize/CoverageChecker.cpp +++ b/clang-tools-extra/modularize/CoverageChecker.cpp @@ -329,10 +329,8 @@ bool CoverageChecker::collectFileSystemHeaders() { else { // Otherwise we only look at the sub-trees specified by the // include paths. - for (std::vector::const_iterator I = IncludePaths.begin(), - E = IncludePaths.end(); - I != E; ++I) { - if (!collectFileSystemHeaders(*I)) + for (const std::string &IncludePath : IncludePaths) { + if (!collectFileSystemHeaders(IncludePath)) return false; } } diff --git a/clang-tools-extra/modularize/Modularize.cpp b/clang-tools-extra/modularize/Modularize.cpp index 7f8a19280b11..2a90c5e3f678 100644 --- a/clang-tools-extra/modularize/Modularize.cpp +++ b/clang-tools-extra/modularize/Modularize.cpp @@ -339,8 +339,8 @@ static std::string findInputFile(const CommandLineArguments &CLArgs) { llvm::opt::Visibility VisibilityMask(options::CC1Option); unsigned MissingArgIndex, MissingArgCount; SmallVector Argv; - for (auto I = CLArgs.begin(), E = CLArgs.end(); I != E; ++I) - Argv.push_back(I->c_str()); + for (const std::string &CLArg : CLArgs) + Argv.push_back(CLArg.c_str()); InputArgList Args = getDriverOptTable().ParseArgs( Argv, MissingArgIndex, MissingArgCount, VisibilityMask); std::vector Inputs = Args.getAllArgValues(OPT_INPUT); diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 9ad1731915a8..8a24f21d658d 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -69,8 +69,7 @@ ModularizeUtilities *ModularizeUtilities::createModularizeUtilities( // Load all header lists and dependencies. std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() { // For each input file. - for (auto I = InputFilePaths.begin(), E = InputFilePaths.end(); I != E; ++I) { - llvm::StringRef InputPath = *I; + for (llvm::StringRef InputPath : InputFilePaths) { // If it's a module map. if (InputPath.ends_with(".modulemap")) { // Load the module map. diff --git a/clang-tools-extra/test/clang-doc/json/class-requires.cpp b/clang-tools-extra/test/clang-doc/json/class-requires.cpp new file mode 100644 index 000000000000..2dd25771d6d8 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp @@ -0,0 +1,34 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/MyClass.json + +template +concept Addable = requires(T a, T b) { + { a + b }; +}; + +template +requires Addable +struct MyClass; + +// CHECK: "Name": "MyClass", +// CHECK-NEXT: "Namespace": [ +// CHECK-NEXT: "GlobalNamespace" +// CHECK-NEXT: ], +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Addable", +// CHECK-NEXT: "Name": "Addable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Addable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Parameters": [ +// CHECK-NEXT: "typename T" +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp new file mode 100644 index 000000000000..b49dec5cc78c --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp @@ -0,0 +1,121 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/index.json + +template concept Incrementable = requires (T a) { + a++; +}; + +template concept Decrementable = requires (T a) { + a--; +}; + +template concept PreIncrementable = requires (T a) { + ++a; +}; + +template concept PreDecrementable = requires (T a) { + --a; +}; + +template requires Incrementable && Decrementable void One(); + +template requires (Incrementable && Decrementable) void Two(); + +template requires (Incrementable && Decrementable) || (PreIncrementable && PreDecrementable) void Three(); + +template requires (Incrementable && Decrementable) || PreIncrementable void Four(); + +// CHECK: "Name": "One", +// CHECK: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Decrementable", +// CHECK-NEXT: "Name": "Decrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Decrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "Name": "Two", +// CHECK: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Decrementable", +// CHECK-NEXT: "Name": "Decrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Decrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "Name": "Three", +// CHECK: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Decrementable", +// CHECK-NEXT: "Name": "Decrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Decrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "PreIncrementable", +// CHECK-NEXT: "Name": "PreIncrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "PreIncrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "PreDecrementable", +// CHECK-NEXT: "Name": "PreDecrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "PreDecrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "Name": "Four", +// CHECK: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Decrementable", +// CHECK-NEXT: "Name": "Decrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Decrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "PreIncrementable", +// CHECK-NEXT: "Name": "PreIncrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "PreIncrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp new file mode 100644 index 000000000000..887c9d79146a --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/concept.cpp @@ -0,0 +1,38 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/index.json + +// Requires that T suports post and pre-incrementing. +template +concept Incrementable = requires(T x) { + ++x; + x++; +}; + +// CHECK: { +// CHECK-NEXT: "Concepts": [ +// CHECK-NEXT: { +// CHECK-NEXT: "ConstraintExpression": "requires (T x) { ++x; x++; }", +// CHECK-NEXT: "Description": [ +// CHECK-NEXT: { +// CHECK-NEXT: "FullComment": { +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "ParagraphComment": { +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." +// CHECK: ], +// CHECK-NEXT: "IsType": true, +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Template": { +// CHECK-NEXT: "Parameters": [ +// CHECK-NEXT: "typename T" +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "Name": "", +// CHECK: "USR": "0000000000000000000000000000000000000000" +// CHECK: } diff --git a/clang-tools-extra/test/clang-doc/json/function-requires.cpp b/clang-tools-extra/test/clang-doc/json/function-requires.cpp new file mode 100644 index 000000000000..99eb2bdb898f --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp @@ -0,0 +1,79 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/index.json + +template +concept Incrementable = requires(T x) { + ++x; + x++; +}; + +template void increment(T t) requires Incrementable; + +template Incrementable auto incrementTwo(T t); + +// CHECK: "Functions": [ +// CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, +// CHECK-NEXT: "Name": "increment", +// CHECK-NEXT: "Params": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "t", +// CHECK-NEXT: "Type": "T" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "ReturnType": { +// CHECK-NEXT: "IsBuiltIn": false, +// CHECK-NEXT: "IsTemplate": false, +// CHECK-NEXT: "Name": "void", +// CHECK-NEXT: "QualName": "void", +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NEXT: }, +// CHECK-NEXT: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Parameters": [ +// CHECK-NEXT: "typename T" +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, +// CHECK-NEXT: "Name": "incrementTwo", +// CHECK-NEXT: "Params": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "t", +// CHECK-NEXT: "Type": "T" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "ReturnType": { +// CHECK-NEXT: "IsBuiltIn": false, +// CHECK-NEXT: "IsTemplate": false, +// CHECK-NEXT: "Name": "Incrementable auto", +// CHECK-NEXT: "QualName": "Incrementable auto", +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NEXT: }, +// CHECK-NEXT: "Template": { +// CHECK-NEXT: "Constraints": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Expression": "Incrementable", +// CHECK-NEXT: "Name": "Incrementable", +// CHECK-NEXT: "Path": "", +// CHECK-NEXT: "QualName": "Incrementable", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Parameters": [ +// CHECK-NEXT: "Incrementable T" +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-doc/json/namespace.cpp b/clang-tools-extra/test/clang-doc/json/namespace.cpp index 928864be1feb..248d47351bd3 100644 --- a/clang-tools-extra/test/clang-doc/json/namespace.cpp +++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp @@ -103,5 +103,23 @@ typedef int MyTypedef; // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" -// CHECK-NOT: "Variables": [ +// CHECK-NOT: "Variables": [ +// CHECK-NOT: { +// CHECK-NOT: "IsStatic": true, +// CHECK-NOT: "Location": { +// CHECK-NOT: "Filename": "{{.*}}namespace.cpp", +// CHECK-NOT: "LineNumber": 13 +// CHECK-NOT: }, +// CHECK-NOT: "Name": "Global", +// CHECK-NOT: "Type": { +// COM: FIXME: IsBuiltIn emits as its default value +// CHECK-NOT: "IsBuiltIn": false, +// CHECK-NOT: "IsTemplate": false, +// CHECK-NOT: "Name": "int", +// CHECK-NOT: "QualName": "int", +// CHECK-NOT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NOT: }, +// CHECK-NOT: "USR": "{{[0-9A-F]*}}" +// CHECK-NOT: } +// CHECK-NOT: ] // CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-reorder-fields/MacroExpandsToMultipleFields.cpp b/clang-tools-extra/test/clang-reorder-fields/MacroExpandsToMultipleFields.cpp new file mode 100644 index 000000000000..5bafcd19ea82 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/MacroExpandsToMultipleFields.cpp @@ -0,0 +1,13 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,y,x %s -- | FileCheck %s + +namespace bar { + +#define FIELDS_DECL int x; int y; // CHECK: {{^#define FIELDS_DECL int x; int y;}} + +// The order of fields should not change. +struct Foo { + FIELDS_DECL // CHECK: {{^ FIELDS_DECL}} + int z; // CHECK-NEXT: {{^ int z;}} +}; + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-reorder-fields/MacroExpansionField.cpp b/clang-tools-extra/test/clang-reorder-fields/MacroExpansionField.cpp new file mode 100644 index 000000000000..a4c3cbc1e12f --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/MacroExpansionField.cpp @@ -0,0 +1,24 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,y,x %s -- | FileCheck %s + +namespace bar { + +#define INT_DECL(NAME) int NAME // CHECK: {{^#define INT_DECL\(NAME\) int NAME}} +#define MACRO_DECL int x; // CHECK-NEXT: {{^#define MACRO_DECL int x;}} + +struct Foo { + MACRO_DECL // CHECK: {{^ INT_DECL\(z\);}} + int y; // CHECK-NEXT: {{^ int y;}} + INT_DECL(z); // CHECK-NEXT: {{^ MACRO_DECL}} +}; + +#define FOO 0 // CHECK: {{^#define FOO 0}} +#define BAR 1 // CHECK-NEXT: {{^#define BAR 1}} +#define BAZ 2 // CHECK-NEXT: {{^#define BAZ 2}} + +struct Foo foo = { + FOO, // CHECK: {{^ BAZ,}} + BAR, // CHECK-NEXT: {{^ BAR,}} + BAZ, // CHECK-NEXT: {{^ FOO,}} +}; + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-reorder-fields/MultipleFieldDeclsInStatement.cpp b/clang-tools-extra/test/clang-reorder-fields/MultipleFieldDeclsInStatement.cpp new file mode 100644 index 000000000000..437e7b91e27a --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/MultipleFieldDeclsInStatement.cpp @@ -0,0 +1,11 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,y,x %s -- | FileCheck %s + +namespace bar { + +// The order of fields should not change. +struct Foo { + int x, y; // CHECK: {{^ int x, y;}} + double z; // CHECK-NEXT: {{^ double z;}} +}; + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundDefinition.cpp b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundDefinition.cpp new file mode 100644 index 000000000000..f00b4b0b57bf --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundDefinition.cpp @@ -0,0 +1,15 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order y,x %s -- | FileCheck %s + +namespace bar { + +#define DEFINE_FOO + +// This is okay to reorder. +#ifdef DEFINE_FOO +struct Foo { + int x; // CHECK: {{^ int y;}} + int y; // CHECK-NEXT: {{^ int x;}} +}; +#endif + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundFields.cpp b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundFields.cpp new file mode 100644 index 000000000000..c37546a05afd --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveAroundFields.cpp @@ -0,0 +1,15 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order y,x %s -- | FileCheck %s + +namespace bar { + +#define DEFINE_FIELDS + +// This is okay to reorder. +struct Foo { +#ifdef DEFINE_FIELDS // CHECK: {{^#ifdef DEFINE_FIELDS}} + int x; // CHECK-NEXT: {{^ int y;}} + int y; // CHECK-NEXT: {{^ int x;}} +#endif // CHECK-NEXT: {{^#endif}} +}; + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveInDefinition.cpp b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveInDefinition.cpp new file mode 100644 index 000000000000..fee6b0e637b9 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/PreprocessorDirectiveInDefinition.cpp @@ -0,0 +1,16 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,y,x %s -- | FileCheck %s + +namespace bar { + +#define ADD_Z + +// The order of fields should not change. +struct Foo { + int x; // CHECK: {{^ int x;}} + int y; // CHECK-NEXT: {{^ int y;}} +#ifdef ADD_Z // CHECK-NEXT: {{^#ifdef ADD_Z}} + int z; // CHECK-NEXT: {{^ int z;}} +#endif // CHECK-NEXT: {{^#endif}} +}; + +} // end namespace bar diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-goto.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-goto.cpp index ee236bc44695..908132b7c9a6 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-goto.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-goto.cpp @@ -1,12 +1,13 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-goto %t +// RUN: %check_clang_tidy -check-suffix=,MACRO %s cppcoreguidelines-avoid-goto %t +// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-goto %t -- -config="{CheckOptions: { cppcoreguidelines-avoid-goto.IgnoreMacros: true }}" void noop() {} int main() { noop(); goto jump_to_me; - // CHECK-NOTES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control - // CHECK-NOTES: [[@LINE+3]]:1: note: label defined here + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES: [[@LINE+3]]:1: note: label defined here noop(); jump_to_me:; @@ -14,14 +15,14 @@ jump_to_me:; jump_backwards:; noop(); goto jump_backwards; - // CHECK-NOTES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control - // CHECK-NOTES: [[@LINE-4]]:1: note: label defined here + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES: [[@LINE-4]]:1: note: label defined here goto jump_in_line; ; jump_in_line:; - // CHECK-NOTES: [[@LINE-3]]:3: warning: avoid using 'goto' for flow control - // CHECK-NOTES: [[@LINE-2]]:1: note: label defined here + // CHECK-MESSAGES: [[@LINE-3]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES: [[@LINE-2]]:1: note: label defined here // Test the GNU extension https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html some_label:; @@ -132,8 +133,41 @@ before_the_loop: for (int j = 0; j < 10; ++j) { if (i * j > 80) goto before_the_loop; - // CHECK-NOTES: [[@LINE-1]]:9: warning: avoid using 'goto' for flow control - // CHECK-NOTES: [[@LINE-8]]:1: note: label defined here + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES: [[@LINE-8]]:1: note: label defined here } } } + +#define macro_goto_code \ + noop(); \ + goto jump_to_me; \ + noop(); \ +jump_to_me:; \ + +#define macro_goto_label jump_to_me:; +#define macro_goto_jump goto jump_to_me; + +void inside_macro_all() { + macro_goto_code + // CHECK-MESSAGES-MACRO: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES-MACRO: [[@LINE-2]]:3: note: label defined here +} + +void inside_macro_label() { + noop(); + goto jump_to_me; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES: [[@LINE+2]]:3: note: label defined here + noop(); + macro_goto_label +} + +void inside_macro_goto() { + noop(); + macro_goto_jump + // CHECK-MESSAGES-MACRO: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control + // CHECK-MESSAGES-MACRO: [[@LINE+2]]:3: note: label defined here + noop(); + jump_to_me:; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp new file mode 100644 index 000000000000..f53d787f80ef --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp @@ -0,0 +1,62 @@ +// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=ALL,DEFAULT %s \ +// RUN: cppcoreguidelines-use-enum-class %t -- + +// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=ALL %s \ +// RUN: cppcoreguidelines-use-enum-class %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: cppcoreguidelines-use-enum-class.IgnoreUnscopedEnumsInClasses: true \ +// RUN: }}" -- + +enum E {}; +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead + +enum class EC {}; + +enum struct ES {}; + +struct S { + enum E {}; + // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead + enum class EC {}; +}; + +class C { + enum E {}; + // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead + enum class EC {}; +}; + +template +class TC { + enum E {}; + // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead + enum class EC {}; +}; + +union U { + enum E {}; + // CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead + enum class EC {}; +}; + +namespace { +enum E {}; +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead +enum class EC {}; +} // namespace + +namespace N { +enum E {}; +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead +enum class EC {}; +} // namespace N + +template +static void foo(); + +enum ForwardE : int; +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead + +enum class ForwardEC : int; + +enum struct ForwardES : int; 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 index d93a05ac3805..e0a84ef5aed2 100644 --- 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 @@ -121,81 +121,3 @@ int AllComparisons() { return 0; } - -namespace PR127471 { - int getSignedValue(); - unsigned int getUnsignedValue(); - - void callExprTest() { - - if (getSignedValue() < getUnsignedValue()) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_less(getSignedValue() , getUnsignedValue())) - - int sVar = 0; - if (getUnsignedValue() > sVar) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_greater(getUnsignedValue() , sVar)) - - unsigned int uVar = 0; - if (getSignedValue() > uVar) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_greater(getSignedValue() , uVar)) - - } - - // Add a class with member functions for testing member function calls - class TestClass { - public: - int getSignedValue() { return -5; } - unsigned int getUnsignedValue() { return 5; } - }; - - void memberFunctionTests() { - TestClass obj; - - if (obj.getSignedValue() < obj.getUnsignedValue()) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_less(obj.getSignedValue() , obj.getUnsignedValue())) - } - - void castFunctionTests() { - // C-style casts with function calls - if ((int)getUnsignedValue() < (unsigned int)getSignedValue()) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue())) - - - // Static casts with function calls - if (static_cast(getUnsignedValue()) < static_cast(getSignedValue())) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue())) - } - - // Define tests - #define SIGNED_FUNC getSignedValue() - #define UNSIGNED_FUNC getUnsignedValue() - - void defineTests() { - if (SIGNED_FUNC < UNSIGNED_FUNC) - return; -// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] -// CHECK-FIXES: if (std::cmp_less(SIGNED_FUNC , UNSIGNED_FUNC)) - } - - // Template tests (should not warn) - template - void templateFunctionTest(T1 value) { - if (value() < getUnsignedValue()) - return; - - if (value() < (getSignedValue() || getUnsignedValue())) - return; - } -} // namespace PR127471 diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-coroutine.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-coroutine.cpp new file mode 100644 index 000000000000..0a84dc467647 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-coroutine.cpp @@ -0,0 +1,65 @@ +// RUN: %check_clang_tidy -std=c++20-or-later %s performance-unnecessary-value-param %t -- -fix-errors +// RUN: %check_clang_tidy -std=c++20-or-later %s performance-unnecessary-value-param %t -- \ +// RUN: -config='{CheckOptions: {performance-unnecessary-value-param.IgnoreCoroutines: true}}' -fix-errors +// RUN: %check_clang_tidy -check-suffix=ALLOWED -std=c++20-or-later %s performance-unnecessary-value-param %t -- \ +// RUN: -config='{CheckOptions: {performance-unnecessary-value-param.IgnoreCoroutines: false}}' -fix-errors + +namespace std { + +template struct coroutine_traits { + using promise_type = typename Ret::promise_type; +}; + +template struct coroutine_handle { + static coroutine_handle from_address(void *) noexcept; + static coroutine_handle from_promise(Promise &promise); + constexpr void *address() const noexcept; +}; + +template <> struct coroutine_handle { + template + coroutine_handle(coroutine_handle) noexcept; + static coroutine_handle from_address(void *); + constexpr void *address() const noexcept; +}; + +struct suspend_always { + bool await_ready() noexcept { return false; } + void await_suspend(coroutine_handle<>) noexcept {} + void await_resume() noexcept {} +}; + +struct suspend_never { + bool await_ready() noexcept { return true; } + void await_suspend(coroutine_handle<>) noexcept {} + void await_resume() noexcept {} +}; + +} // namespace std + +struct ReturnObject { + struct promise_type { + ReturnObject get_return_object() { return {}; } + ReturnObject return_void() { return {}; } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() {} + std::suspend_always yield_value(int value) { return {}; } + }; +}; + +struct A { + A(const A&); +}; + +ReturnObject foo_coroutine(const A a) { +// CHECK-MESSAGES-ALLOWED: [[@LINE-1]]:36: warning: the const qualified parameter 'a' +// CHECK-FIXES: ReturnObject foo_coroutine(const A a) { + co_return; +} + +ReturnObject foo_not_coroutine(const A a) { +// CHECK-MESSAGES: [[@LINE-1]]:40: warning: the const qualified parameter 'a' +// CHECK-MESSAGES-ALLOWED: [[@LINE-2]]:40: warning: the const qualified parameter 'a' + return ReturnObject{}; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/function-size-no-member-init-as-stmts.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size-no-member-init-as-stmts.cpp new file mode 100644 index 000000000000..d335988e5e03 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size-no-member-init-as-stmts.cpp @@ -0,0 +1,73 @@ +// RUN: %check_clang_tidy %s readability-function-size %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-function-size.LineThreshold: 0, \ +// RUN: readability-function-size.StatementThreshold: 0, \ +// RUN: readability-function-size.BranchThreshold: 0, \ +// RUN: readability-function-size.ParameterThreshold: 5, \ +// RUN: readability-function-size.NestingThreshold: 2, \ +// RUN: readability-function-size.VariableThreshold: 1, \ +// RUN: readability-function-size.CountMemberInitAsStmt: false \ +// RUN: }}' + +// Bad formatting is intentional, don't run clang-format over the whole file! + +void foo1() { +} + +void foo2() {;} +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foo2' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 1 statements (threshold 0) + +struct A { + A(int c, int d) : a(0), b(c) { ; } + int a; + int b; +}; +// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: function 'A' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-5]]:3: note: 1 statements (threshold 0) + +struct B { + B(int x, int y, int z) : a(x + y * z), b(), c_a(y, z) { + ; + } + int a; + int b; + A c_a; +}; +// CHECK-MESSAGES: :[[@LINE-7]]:3: warning: function 'B' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-8]]:3: note: 2 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-9]]:3: note: 1 statements (threshold 0) + +struct C : A, B { + // 0 statements + C() : A(0, 4), B(1, 2, 3) {} +}; + +template +struct TemplateC { + // 0 statements + TemplateC() : a(3) {} + T a; +}; + +template +struct TemplateD { + template + TemplateD(U&& val) : member(val) { + ; + } + + T member; +}; +// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: function 'TemplateD' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-7]]:3: note: 2 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-8]]:3: note: 1 statements (threshold 0) + +void instantiate() { + TemplateC c; + TemplateD d(5); +} +// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'instantiate' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 2 statements (threshold 0) +// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp index 45b2604b43d0..9364fa3077da 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/function-size.cpp @@ -319,3 +319,60 @@ void variables_16() { // CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0) // CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 statements (threshold 0) // CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1) + +struct A { + A(int c, int d) : a(0), b(c) { ; } + int a; + int b; +}; +// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: function 'A' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-5]]:3: note: 3 statements (threshold 0) + +struct B { + B(int x, int y, int z) : a(x + y * z), b(), c_a(y, z) { + ; + } + int a; + int b; + A c_a; +}; +// CHECK-MESSAGES: :[[@LINE-7]]:3: warning: function 'B' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-8]]:3: note: 2 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-9]]:3: note: 4 statements (threshold 0) + +struct C : A, B { + C() : A(0, 4), B(1, 2, 3) {} +}; +// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: function 'C' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-3]]:3: note: 2 statements (threshold 0) + +template +struct TemplateC { + // 0 statements + TemplateC() : a(3) {} + T a; +}; +// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: function 'TemplateC' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-4]]:3: note: 1 statements (threshold 0) + +template +struct TemplateD { + template + TemplateD(U&& val) : member(val) { + ; + } + + T member; +}; +// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: function 'TemplateD' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-7]]:3: note: 2 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-8]]:3: note: 2 statements (threshold 0) + +void instantiate() { + TemplateC c; + TemplateD d(5); +} +// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'instantiate' exceeds recommended size/complexity thresholds [readability-function-size] +// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0) +// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 2 statements (threshold 0) +// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1) diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp index bbe158ed50e2..a38dfd303660 100644 --- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp @@ -37,7 +37,9 @@ static std::string writeInfo(Info *I) { return writeInfo(*static_cast(I)); case InfoType::IT_typedef: return writeInfo(*static_cast(I)); - default: + case InfoType::IT_concept: + return writeInfo(*static_cast(I)); + case InfoType::IT_default: return ""; } } diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index ab2ac9bc6b9a..94607a8e8473 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -345,9 +345,6 @@ configure_file( # Add appropriate flags for GCC if (LLVM_COMPILER_IS_GCC_COMPATIBLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual") - if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") - endif () # Enable -pedantic for Clang even if it's not enabled for LLVM. if (NOT LLVM_ENABLE_PEDANTIC) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee..548c73af6587 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6992,7 +6992,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: c++ namespace N1 { - namespace N2 + namespace N2 { function(); } } diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 1b8776c5e9ad..7d49f2cc28a1 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -460,8 +460,11 @@ Code Generation Options :option:`-Oz` Like :option:`-Os` (and thus :option:`-O2`), but reduces code size further. - :option:`-Og` Like :option:`-O1`. In future versions, this option might - disable different optimizations in order to improve debuggability. + :option:`-Og` Similar to :option:`-O1`, but with slightly reduced + optimization and better variable visibility. The same optimizations are run + as at :option:`-O1`, but the ``-fextend-variable-liveness`` flag is + also set, which tries to prevent optimizations from reducing the liveness of + user variables, improving their availability when debugging. :option:`-O` Equivalent to :option:`-O1`. diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index 051a25396994..406e1c8e5a2f 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -17,7 +17,7 @@ HIP Support ============= -HIP (Heterogeneous-Compute Interface for Portability) ``_ is +HIP (Heterogeneous-Compute Interface for Portability) ``_ is a C++ Runtime API and Kernel Language. It enables developers to create portable applications for offloading computation to different hardware platforms from a single source code. @@ -41,9 +41,9 @@ backend or the out-of-tree LLVM-SPIRV translator. The SPIR-V is then bundled and .. note:: While Clang does not directly provide HIP support for NVIDIA GPUs and CPUs, these platforms are supported via other means: - - NVIDIA GPUs: HIP support is offered through the HIP project ``_, which provides a header-only library for translating HIP runtime APIs into CUDA runtime APIs. The code is subsequently compiled using NVIDIA's `nvcc`. + - NVIDIA GPUs: HIP support is offered through the HIP project ``_, which provides a header-only library for translating HIP runtime APIs into CUDA runtime APIs. The code is subsequently compiled using NVIDIA's `nvcc`. - - CPUs: HIP support is available through the HIP-CPU runtime library ``_. This header-only library enables CPUs to execute unmodified HIP code. + - CPUs: HIP support is available through the HIP-CPU runtime library ``_. This header-only library enables CPUs to execute unmodified HIP code. Example Usage @@ -328,7 +328,7 @@ The `parallel_unsequenced_policy `__), makes +(e.g. `rocThrust `__), makes it feasible to provide seamless accelerator offload for supported algorithms, when an accelerated version exists. Thus, it becomes possible to easily access the computational resources of an AMD accelerator, via a well specified, @@ -483,7 +483,7 @@ such as GPUs, work. allocation / deallocation functions with accelerator-aware equivalents, based on a pre-established table; the list of functions that can be interposed is available - `here `__; + `here `__; - This is only run when compiling for the host. The second pass is optional. @@ -627,7 +627,7 @@ Linux operating system. Support is synthesised in the following table: The minimum Linux kernel version for running in HMM mode is 6.4. The forwarding header can be obtained from -`its GitHub repository `_. +`its GitHub repository `_. It will be packaged with a future `ROCm `_ release. Because accelerated algorithms are provided via `rocThrust `_, a @@ -636,7 +636,7 @@ transitive dependency on can be obtained either by installing their associated components of the `ROCm `_ stack, or from their respective repositories. The list algorithms that can be offloaded is available -`here `_. +`here `_. HIP Specific Elements --------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b5e6cf088a4b..96477ef6ddc9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -65,8 +65,10 @@ C++ Specific Potentially Breaking Changes standard library already have their own bespoke builtins. - A workaround for libstdc++4.7 has been removed. Note that 4.8.3 remains the oldest supported libstdc++ version. - - Added ``!nonnull/!align`` metadata to load of references for better codegen. +- Checking for int->enum conversions in constant expressions is more strict; + in particular, ``const E x = (E)-1;`` is not treated as a constant if it's + out of range. This impacts old versions of Boost. (#GH143034) ABI Changes in This Version --------------------------- @@ -325,6 +327,9 @@ Non-comprehensive list of changes in this release ``__reference_constructs_from_temporary`` should be used instead. (#GH44056) - Added `__builtin_get_vtable_pointer` to directly load the primary vtable pointer from a polymorphic object. +- Clang no longer rejects reinterpret_cast conversions between indirect + ARC-managed pointers and other pointer types. The prior behavior was overly + strict and inconsistent with the ARC specification. New Compiler Flags ------------------ @@ -339,6 +344,8 @@ New Compiler Flags - New option ``-Wnrvo`` added and disabled by default to warn about missed NRVO opportunities. +- New option ``-ignore-pch`` added to disable precompiled headers. It overrides ``-emit-pch`` and ``-include-pch``. (#GH142409, `PCHDocs `_). + Deprecated Compiler Flags ------------------------- @@ -357,6 +364,12 @@ Modified Compiler Flags - The ``-fchar8_t`` flag is no longer considered in non-C++ languages modes. (#GH55373) +- The ``-fveclib=libmvec`` option now supports AArch64 targets (requires GLIBC 2.40 or newer). + +- The ``-Og`` optimization flag now sets ``-fextend-variable-liveness``, + reducing performance slightly while reducing the number of optimized-out + variables. (#GH118026) + Removed Compiler Flags ------------------------- @@ -622,6 +635,14 @@ Improvements to Clang's diagnostics - Improved the FixIts for unused lambda captures. +- Delayed typo correction was removed from the compiler; immediate typo + correction behavior remains the same. Delayed typo correction facilities were + fragile and unmaintained, and the removal closed the following issues: + #GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308, + #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490, + #GH36703, #GH32903, #GH23312, #GH69874. + + Improvements to Clang's time-trace ---------------------------------- @@ -680,6 +701,8 @@ Bug Fixes in This Version ``#include`` directive. (#GH138094) - Fixed a crash during constant evaluation involving invalid lambda captures (#GH138832) +- Fixed compound literal is not constant expression inside initializer list + (#GH87867) - Fixed a crash when instantiating an invalid dependent friend template specialization. (#GH139052) - Fixed a crash with an invalid member function parameter list with a default @@ -694,6 +717,9 @@ Bug Fixes in This Version - Constant evaluation now correctly runs the destructor of a variable declared in the second clause of a C-style ``for`` loop. (#GH139818) - Fixed a bug with constexpr evaluation for structs containing unions in case of C++ modules. (#GH143168) +- Fixed incorrect token location when emitting diagnostics for tokens expanded from macros. (#GH143216) +- Fixed an infinite recursion when checking constexpr destructors. (#GH141789) +- Fixed a crash when a malformed using declaration appears in a ``constexpr`` function. (#GH144264) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -830,6 +856,7 @@ Bug Fixes to C++ Support - Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255) - Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107) - Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852) +- Fixed a function declaration mismatch that caused inconsistencies between concepts and variable template declarations. (#GH139476) - Clang no longer segfaults when there is a configuration mismatch between modules and their users (http://crbug.com/400353616). - Fix an incorrect deduction when calling an explicit object member function template through an overload set address. - Fixed bug in constant evaluation that would allow using the value of a @@ -1102,6 +1129,9 @@ OpenMP Support - An error is now emitted when OpenMP ``collapse`` and ``ordered`` clauses have an argument larger than what can fit within a 64-bit integer. - Added support for private variable reduction. +- Fixed mapping of arrays of structs containing nested structs with user defined + mappers, by using compiler-generated default mappers for the outer structs for + such maps. Improvements ^^^^^^^^^^^^ diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index 61b6c55d8e6e..2c50778d0f49 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -109,13 +109,13 @@ precedence. Here are a few examples. .. code-block:: bash $ cat ignorelist1.txt - # test.cc will be instrumented. + # test.cc will not be instrumented. src:* src:*/mylib/*=sanitize src:*/mylib/test.cc $ cat ignorelist2.txt - # test.cc will not be instrumented. + # test.cc will be instrumented. src:* src:*/mylib/test.cc src:*/mylib/*=sanitize diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 62844f7e6a2f..284a404026df 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1458,6 +1458,19 @@ will be processed from the PCH file. Otherwise, Clang will report an error. ``test.h`` since ``test.h`` was included directly in the source file and not specified on the command line using ``-include-pch``. +Ignoring a PCH File +^^^^^^^^^^^^^^^^^^^ + +To ignore PCH options, a `-ignore-pch` option is passed to ``clang``: + +.. code-block:: console + + $ clang -x c-header test.h -Xclang -ignore-pch -o test.h.pch + $ clang -include-pch test.h.pch -Xclang -ignore-pch test.c -o test + +This option disables precompiled headers, overrides -emit-pch and -include-pch. +test.h.pch is not generated and not used as a prefix header. + Relocatable PCH Files ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index c3dbfa3ba5f7..f21afc319581 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -506,8 +506,8 @@ class ASTContext : public RefCountedBase { /// if possible. /// /// Not serialized intentionally. - llvm::StringMap PrimaryModuleNameMap; - llvm::DenseMap SameModuleLookupSet; + mutable llvm::StringMap PrimaryModuleNameMap; + mutable llvm::DenseMap SameModuleLookupSet; static constexpr unsigned ConstantArrayTypesLog2InitSize = 8; static constexpr unsigned GeneralTypesLog2InitSize = 9; @@ -647,10 +647,48 @@ public: void setRelocationInfoForCXXRecord(const CXXRecordDecl *, CXXRecordDeclRelocationInfo); + /// Examines a given type, and returns whether the type itself + /// is address discriminated, or any transitively embedded types + /// contain data that is address discriminated. This includes + /// implicitly authenticated values like vtable pointers, as well as + /// explicitly qualified fields. + bool containsAddressDiscriminatedPointerAuth(QualType T) { + if (!isPointerAuthenticationAvailable()) + return false; + return findPointerAuthContent(T) != PointerAuthContent::None; + } + + /// Examines a given type, and returns whether the type itself + /// or any data it transitively contains has a pointer authentication + /// schema that is not safely relocatable. e.g. any data or fields + /// with address discrimination other than any otherwise similar + /// vtable pointers. + bool containsNonRelocatablePointerAuth(QualType T) { + if (!isPointerAuthenticationAvailable()) + return false; + return findPointerAuthContent(T) == + PointerAuthContent::AddressDiscriminatedData; + } + private: llvm::DenseMap RelocatableClasses; + // FIXME: store in RecordDeclBitfields in future? + enum class PointerAuthContent : uint8_t { + None, + AddressDiscriminatedVTable, + AddressDiscriminatedData + }; + + // A simple helper function to short circuit pointer auth checks. + bool isPointerAuthenticationAvailable() const { + return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; + } + PointerAuthContent findPointerAuthContent(QualType T); + llvm::DenseMap + RecordContainsAddressDiscriminatedPointerAuth; + ImportDecl *FirstLocalImport = nullptr; ImportDecl *LastLocalImport = nullptr; @@ -794,7 +832,7 @@ public: llvm::StringRef backupStr(llvm::StringRef S) const { char *Buf = new (*this) char[S.size()]; - std::copy(S.begin(), S.end(), Buf); + llvm::copy(S, Buf); return llvm::StringRef(Buf, S.size()); } @@ -1169,7 +1207,7 @@ public: /// /// FIXME: The signature may be confusing since `clang::Module` means to /// a module fragment or a module unit but not a C++20 module. - bool isInSameModule(const Module *M1, const Module *M2); + bool isInSameModule(const Module *M1, const Module *M2) const; TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl->getMostRecentDecl(); @@ -3701,6 +3739,7 @@ public: /// authentication policy for the specified record. const CXXRecordDecl * baseForVTableAuthentication(const CXXRecordDecl *ThisClass); + bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl, StringRef MangledName); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 4dacb1a77e34..882686f1b70d 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1358,6 +1358,11 @@ public: return const_cast(this)->getInitializingDeclaration(); } + /// Checks whether this declaration has an initializer with side effects, + /// without triggering deserialization if the initializer is not yet + /// deserialized. + bool hasInitWithSideEffects() const; + /// Determine whether this variable's value might be usable in a /// constant expression, according to the relevant language standard. /// This only checks properties of the declaration, and does not check diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 9bdb2024a66c..1f03f9b31df1 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -653,6 +653,10 @@ public: return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } + /// Whether this declaration was a local declaration to a C++20 + /// named module. + bool isModuleLocal() const; + /// Whether this declaration was exported in a lexical context. /// e.g.: /// diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index b6e998a408c0..2e7b69a7d8cc 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -280,7 +280,7 @@ public: /// Produce this as an array ref. ArrayRef asArray() const { - return llvm::ArrayRef(data(), size()); + return getTrailingObjects(size()); } /// Retrieve the number of template arguments in this @@ -288,9 +288,7 @@ public: unsigned size() const { return NumArguments; } /// Retrieve a pointer to the template argument list. - const TemplateArgument *data() const { - return getTrailingObjects(); - } + const TemplateArgument *data() const { return getTrailingObjects(); } }; void *allocateDefaultArgStorageChain(const ASTContext &C); @@ -506,12 +504,10 @@ private: TemplateArgumentsAsWritten(TemplateArgsAsWritten), PointOfInstantiation(POI) { if (MSInfo) - getTrailingObjects()[0] = MSInfo; + getTrailingObjects()[0] = MSInfo; } - size_t numTrailingObjects(OverloadToken) const { - return Function.getInt(); - } + size_t numTrailingObjects() const { return Function.getInt(); } public: friend TrailingObjects; @@ -598,9 +594,7 @@ public: /// function and the function template, and should always be /// TSK_ExplicitSpecialization whenever we have MemberSpecializationInfo. MemberSpecializationInfo *getMemberSpecializationInfo() const { - return numTrailingObjects(OverloadToken()) - ? getTrailingObjects()[0] - : nullptr; + return numTrailingObjects() ? getTrailingObjects()[0] : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 863127d69fd7..f01950bf00f6 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -243,8 +243,7 @@ public: return static_cast(getDependence() & ExprDependence::UnexpandedPack); } - /// Whether this expression contains subexpressions which had errors, e.g. a - /// TypoExpr. + /// Whether this expression contains subexpressions which had errors. bool containsErrors() const { return static_cast(getDependence() & ExprDependence::Error); } @@ -1858,8 +1857,7 @@ class StringLiteral final /// Build a string literal. StringLiteral(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, - bool Pascal, QualType Ty, const SourceLocation *Loc, - unsigned NumConcatenated); + bool Pascal, QualType Ty, ArrayRef Locs); /// Build an empty string literal. StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length, @@ -1877,18 +1875,10 @@ class StringLiteral final public: /// This is the "fully general" constructor that allows representation of - /// strings formed from multiple concatenated tokens. + /// strings formed from one or more concatenated tokens. static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, - const SourceLocation *Loc, - unsigned NumConcatenated); - - /// Simple constructor for string literals made from one token. - static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, - StringLiteralKind Kind, bool Pascal, QualType Ty, - SourceLocation Loc) { - return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1); - } + ArrayRef Locs); /// Construct an empty string literal. static StringLiteral *CreateEmpty(const ASTContext &Ctx, @@ -6988,36 +6978,6 @@ public: } }; -/// TypoExpr - Internal placeholder for expressions where typo correction -/// still needs to be performed and/or an error diagnostic emitted. -class TypoExpr : public Expr { - // The location for the typo name. - SourceLocation TypoLoc; - -public: - TypoExpr(QualType T, SourceLocation TypoLoc) - : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary), TypoLoc(TypoLoc) { - assert(T->isDependentType() && "TypoExpr given a non-dependent type"); - setDependence(ExprDependence::TypeValueInstantiation | - ExprDependence::Error); - } - - 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()); - } - - SourceLocation getBeginLoc() const LLVM_READONLY { return TypoLoc; } - SourceLocation getEndLoc() const LLVM_READONLY { return TypoLoc; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == TypoExprClass; - } - -}; - /// This class represents BOTH the OpenMP Array Section and OpenACC 'subarray', /// with a boolean differentiator. /// OpenMP 5.0 [2.1.5, Array Sections]. @@ -7418,17 +7378,14 @@ public: ArrayRef SubExprs); static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs); - ArrayRef subExpressions() { - auto *B = getTrailingObjects(); - return llvm::ArrayRef(B, B + NumExprs); - } + ArrayRef subExpressions() { return getTrailingObjects(NumExprs); } ArrayRef subExpressions() const { return const_cast(this)->subExpressions(); } child_range children() { - Stmt **B = reinterpret_cast(getTrailingObjects()); + Stmt **B = reinterpret_cast(getTrailingObjects()); return child_range(B, B + NumExprs); } diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index f45e3af7602c..e91d5132da10 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -51,6 +51,7 @@ class RecordDecl; class Selector; class Stmt; class TagDecl; +class VarDecl; /// Abstract interface for external sources of AST nodes. /// @@ -195,6 +196,10 @@ public: /// module. virtual bool wasThisDeclarationADefinition(const FunctionDecl *FD); + virtual bool hasInitializerWithSideEffects(const VarDecl *VD) const { + return false; + } + /// Finds all declarations lexically contained within the given /// DeclContext, after applying an optional filter predicate. /// @@ -429,6 +434,17 @@ public: return GetPtr(); } + /// Retrieve the pointer to the AST node that this lazy pointer points to, + /// if it can be done without triggering deserialization. + /// + /// \returns a pointer to the AST node, or null if not yet deserialized. + T *getWithoutDeserializing() const { + if (isOffset()) { + return nullptr; + } + return GetPtr(); + } + /// Retrieve the address of the AST node pointer. Deserializes the pointee if /// necessary. T **getAddressOfPointer(ExternalASTSource *Source) const { diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 67fbdfeb0702..a778c7cc3dc9 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -307,7 +307,7 @@ public: } ArrayRef getArchitectures() const { - return getTrailingObjects(NumArchs); + return getTrailingObjects(NumArchs); } static OpenACCDeviceTypeClause * diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 6fd16bc0f03b..3ceaea10bd02 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -302,8 +302,7 @@ protected: void setVarRefs(ArrayRef VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), - static_cast(this)->template getTrailingObjects()); + llvm::copy(VL, getVarRefs().begin()); } public: @@ -388,9 +387,7 @@ public: assert( DK.size() == NumKinds && "Number of directive kinds is not the same as the preallocated buffer"); - std::copy(DK.begin(), DK.end(), - static_cast(this) - ->template getTrailingObjects()); + llvm::copy(DK, getDirectiveKinds().begin()); } SourceLocation getLParenLoc() { return LParenLoc; } @@ -980,20 +977,14 @@ public: /// Returns the tile size expressions. MutableArrayRef getSizesRefs() { - return static_cast(this) - ->template getTrailingObjects(NumSizes); - } - ArrayRef getSizesRefs() const { - return static_cast(this) - ->template getTrailingObjects(NumSizes); + return getTrailingObjects(NumSizes); } + ArrayRef getSizesRefs() const { return getTrailingObjects(NumSizes); } /// Sets the tile size expressions. void setSizesRefs(ArrayRef VL) { assert(VL.size() == NumSizes); - std::copy(VL.begin(), VL.end(), - static_cast(this) - ->template getTrailingObjects()); + llvm::copy(VL, getSizesRefs().begin()); } child_range children() { @@ -1043,8 +1034,7 @@ class OMPPermutationClause final /// Sets the permutation index expressions. void setArgRefs(ArrayRef VL) { assert(VL.size() == NumLoops && "Expecting one expression per loop"); - llvm::copy(VL, static_cast(this) - ->template getTrailingObjects()); + llvm::copy(VL, getTrailingObjects()); } /// Build an empty clause. @@ -1083,14 +1073,8 @@ public: /// Returns the permutation index expressions. ///@{ - MutableArrayRef getArgsRefs() { - return static_cast(this) - ->template getTrailingObjects(NumLoops); - } - ArrayRef getArgsRefs() const { - return static_cast(this) - ->template getTrailingObjects(NumLoops); - } + MutableArrayRef getArgsRefs() { return getTrailingObjects(NumLoops); } + ArrayRef getArgsRefs() const { return getTrailingObjects(NumLoops); } ///@} child_range children() { @@ -5933,7 +5917,7 @@ protected: void setUniqueDecls(ArrayRef UDs) { assert(UDs.size() == NumUniqueDeclarations && "Unexpected amount of unique declarations."); - std::copy(UDs.begin(), UDs.end(), getUniqueDeclsRef().begin()); + llvm::copy(UDs, getUniqueDeclsRef().begin()); } /// Get the number of lists per declaration that are in the trailing @@ -5955,7 +5939,7 @@ protected: void setDeclNumLists(ArrayRef DNLs) { assert(DNLs.size() == NumUniqueDeclarations && "Unexpected amount of list numbers."); - std::copy(DNLs.begin(), DNLs.end(), getDeclNumListsRef().begin()); + llvm::copy(DNLs, getDeclNumListsRef().begin()); } /// Get the cumulative component lists sizes that are in the trailing @@ -5981,7 +5965,7 @@ protected: void setComponentListSizes(ArrayRef CLSs) { assert(CLSs.size() == NumComponentLists && "Unexpected amount of component lists."); - std::copy(CLSs.begin(), CLSs.end(), getComponentListSizesRef().begin()); + llvm::copy(CLSs, getComponentListSizesRef().begin()); } /// Get the components that are in the trailing objects of the class. @@ -6005,7 +5989,7 @@ protected: "Unexpected amount of component lists."); assert(CLSs.size() == NumComponentLists && "Unexpected amount of list sizes."); - std::copy(Components.begin(), Components.end(), getComponentsRef().begin()); + llvm::copy(Components, getComponentsRef().begin()); } /// Fill the clause information from the list of declarations and @@ -6079,7 +6063,7 @@ protected: ++CLSI; // Append components after the current components iterator. - CI = std::copy(C.begin(), C.end(), CI); + CI = llvm::copy(C, CI); } } } @@ -6123,7 +6107,7 @@ protected: "Unexpected number of user-defined mappers."); assert(SupportsMapper && "Must be a clause that is possible to have user-defined mappers"); - std::copy(DMDs.begin(), DMDs.end(), getUDMapperRefs().begin()); + llvm::copy(DMDs, getUDMapperRefs().begin()); } public: @@ -9239,9 +9223,7 @@ class OMPAffinityClause final SourceLocation(), N) {} /// Sets the affinity modifier for the clause, if any. - void setModifier(Expr *E) { - getTrailingObjects()[varlist_size()] = E; - } + void setModifier(Expr *E) { getTrailingObjects()[varlist_size()] = E; } /// Sets the location of ':' symbol. void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } @@ -9268,10 +9250,8 @@ public: static OMPAffinityClause *CreateEmpty(const ASTContext &C, unsigned N); /// Gets affinity modifier. - Expr *getModifier() { return getTrailingObjects()[varlist_size()]; } - Expr *getModifier() const { - return getTrailingObjects()[varlist_size()]; - } + Expr *getModifier() { return getTrailingObjects()[varlist_size()]; } + Expr *getModifier() const { return getTrailingObjects()[varlist_size()]; } /// Gets the location of ':' symbol. SourceLocation getColonLoc() const { return ColonLoc; } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 0fcc4b1bd03f..00a1e505be31 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3011,7 +3011,6 @@ DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, { } }) DEF_TRAVERSE_STMT(OpaqueValueExpr, {}) -DEF_TRAVERSE_STMT(TypoExpr, {}) DEF_TRAVERSE_STMT(RecoveryExpr, {}) DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {}) diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 387c4a2eda5c..cccfea4c4311 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -2212,7 +2212,7 @@ class AttributedStmt final : ValueStmt(AttributedStmtClass), SubStmt(SubStmt) { AttributedStmtBits.NumAttrs = Attrs.size(); AttributedStmtBits.AttrLoc = Loc; - std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr()); + llvm::copy(Attrs, getAttrArrayPtr()); } explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs) diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index c8f8b968b1c8..9ad3d8e00d98 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -736,7 +736,7 @@ class OpenACCUpdateConstruct final OpenACCDirectiveKind::Update, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); - setClauseList(getTrailingObjects(NumClauses)); + setClauseList(getTrailingObjects(NumClauses)); } OpenACCUpdateConstruct(SourceLocation Start, SourceLocation DirectiveLoc, diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 736bcabbad1f..e2fd2114026f 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -5787,10 +5787,13 @@ class OMPReverseDirective final : public OMPLoopTransformationDirective { TransformedStmtOffset, }; - explicit OMPReverseDirective(SourceLocation StartLoc, SourceLocation EndLoc) + explicit OMPReverseDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumLoops) : OMPLoopTransformationDirective(OMPReverseDirectiveClass, llvm::omp::OMPD_reverse, StartLoc, - EndLoc, 1) {} + EndLoc, NumLoops) { + setNumGeneratedLoops(NumLoops); + } void setPreInits(Stmt *PreInits) { Data->getChildren()[PreInitsOffset] = PreInits; @@ -5806,19 +5809,23 @@ public: /// \param C Context of the AST. /// \param StartLoc Location of the introducer (e.g. the 'omp' token). /// \param EndLoc Location of the directive's end (e.g. the tok::eod). + /// \param NumLoops Number of affected loops /// \param AssociatedStmt The outermost associated loop. /// \param TransformedStmt The loop nest after tiling, or nullptr in /// dependent contexts. /// \param PreInits Helper preinits statements for the loop nest. - static OMPReverseDirective * - Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, - Stmt *AssociatedStmt, Stmt *TransformedStmt, Stmt *PreInits); + static OMPReverseDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt, unsigned NumLoops, + Stmt *TransformedStmt, Stmt *PreInits); /// Build an empty '#pragma omp reverse' AST node for deserialization. /// /// \param C Context of the AST. - /// \param NumClauses Number of clauses to allocate. - static OMPReverseDirective *CreateEmpty(const ASTContext &C); + /// \param NumLoops Number of associated loops to allocate + static OMPReverseDirective *CreateEmpty(const ASTContext &C, + unsigned NumLoops); /// Gets/sets the associated loops after the transformation, i.e. after /// de-sugaring. @@ -5857,7 +5864,7 @@ class OMPInterchangeDirective final : public OMPLoopTransformationDirective { : OMPLoopTransformationDirective(OMPInterchangeDirectiveClass, llvm::omp::OMPD_interchange, StartLoc, EndLoc, NumLoops) { - setNumGeneratedLoops(3 * NumLoops); + setNumGeneratedLoops(NumLoops); } void setPreInits(Stmt *PreInits) { diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index b76771b6c58c..2ea0a5e0bfd7 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -6077,9 +6077,7 @@ public: ArrayRef Expansions); private: - const QualType *getExpansionsPtr() const { - return getTrailingObjects(); - } + const QualType *getExpansionsPtr() const { return getTrailingObjects(); } static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr, ArrayRef Expansions = {}); @@ -6524,7 +6522,7 @@ public: uint32_t getSize() const { return Size; } uint32_t getAlignment() const { return Alignment; } ArrayRef getOperands() const { - return getTrailingObjects(NumOperands); + return getTrailingObjects(NumOperands); } bool isSugared() const { return false; } diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 9cab73c3151d..0a012ebf3196 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -755,7 +755,7 @@ let Class = TemplateSpecializationType in { } def : Creator<[{ - return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType); + return ctx.getTemplateSpecializationType(templateName, args, {}, UnderlyingType); }]>; } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ebd5cb4eba3c..c3a7151ec69d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4682,6 +4682,7 @@ def OMPDeclareVariant : InheritableAttr { OMPTraitInfoArgument<"TraitInfos">, VariadicExprArgument<"AdjustArgsNothing">, VariadicExprArgument<"AdjustArgsNeedDevicePtr">, + VariadicExprArgument<"AdjustArgsNeedDeviceAddr">, VariadicOMPInteropInfoArgument<"AppendArgs">, ]; let AdditionalMembers = [{ @@ -5074,6 +5075,14 @@ def HLSLVkExtBuiltinInput : InheritableAttr { let Documentation = [HLSLVkExtBuiltinInputDocs]; } +def HLSLVkConstantId : InheritableAttr { + let Spellings = [CXX11<"vk", "constant_id">]; + let Args = [IntArgument<"Id">]; + let Subjects = SubjectList<[ExternalGlobalVar]>; + let LangOpts = [HLSL]; + let Documentation = [VkConstantIdDocs]; +} + def RandomizeLayout : InheritableAttr { let Spellings = [GCC<"randomize_layout">]; let Subjects = SubjectList<[Record]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 047f51ffa59e..43442f177ab7 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2934,7 +2934,7 @@ https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html https://riscv.org/specifications/privileged-isa/ The RISC-V Instruction Set Manual Volume II: Privileged Architecture Version 1.10. -https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.7 +https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.13.0 https://sifive.cdn.prismic.io/sifive/d1984d2b-c9b9-4c91-8de0-d68a5e64fa0f_sifive-interrupt-cookbook-v1p2.pdf }]; } @@ -8252,6 +8252,21 @@ and https://microsoft.github.io/hlsl-specs/proposals/0013-wave-size-range.html }]; } +def VkConstantIdDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``vk::constant_id`` attribute specifies the id for a SPIR-V specialization +constant. The attribute applies to const global scalar variables. The variable must be initialized with a C++11 constexpr. +In SPIR-V, the +variable will be replaced with an `OpSpecConstant` with the given id. +The syntax is: + +.. code-block:: text + + ``[[vk::constant_id()]] const T Name = `` +}]; +} + def RootSignatureDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index a6d421f0080f..954d4441aa07 100644 --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H #define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H +#include "clang/Basic/AttributeScopeInfo.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TokenKinds.h" @@ -64,6 +65,7 @@ public: /// The attribute is a C++2c annotation. AS_Annotation, }; + enum Kind { #define PARSED_ATTR(NAME) AT_##NAME, #include "clang/Basic/AttrParsedAttrList.inc" @@ -82,9 +84,9 @@ public: private: const IdentifierInfo *AttrName = nullptr; - const IdentifierInfo *ScopeName = nullptr; + AttributeScopeInfo AttrScope; SourceRange AttrRange; - const SourceLocation ScopeLoc; + // Corresponds to the Kind enum. LLVM_PREFERRED_TYPE(Kind) unsigned AttrKind : 16; @@ -151,11 +153,10 @@ public: }; AttributeCommonInfo(const IdentifierInfo *AttrName, - const IdentifierInfo *ScopeName, SourceRange AttrRange, - SourceLocation ScopeLoc, Kind AttrKind, Form FormUsed) - : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange), - ScopeLoc(ScopeLoc), AttrKind(AttrKind), - SyntaxUsed(FormUsed.getSyntax()), + AttributeScopeInfo AttrScope, SourceRange AttrRange, + Kind AttrKind, Form FormUsed) + : AttrName(AttrName), AttrScope(AttrScope), AttrRange(AttrRange), + AttrKind(AttrKind), SyntaxUsed(FormUsed.getSyntax()), SpellingIndex(FormUsed.getSpellingIndex()), IsAlignas(FormUsed.isAlignas()), IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) { @@ -163,21 +164,20 @@ public: "Invalid syntax!"); } - AttributeCommonInfo(const IdentifierInfo *AttrName, - const IdentifierInfo *ScopeName, SourceRange AttrRange, - SourceLocation ScopeLoc, Form FormUsed) + AttributeCommonInfo(const IdentifierInfo *AttrName, AttributeScopeInfo Scope, + SourceRange AttrRange, Form FormUsed) : AttributeCommonInfo( - AttrName, ScopeName, AttrRange, ScopeLoc, - getParsedKind(AttrName, ScopeName, FormUsed.getSyntax()), + AttrName, Scope, AttrRange, + getParsedKind(AttrName, Scope.getName(), FormUsed.getSyntax()), FormUsed) {} AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange, Form FormUsed) - : AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(), + : AttributeCommonInfo(AttrName, AttributeScopeInfo(), AttrRange, FormUsed) {} AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed) - : AttributeCommonInfo(nullptr, nullptr, AttrRange, SourceLocation(), K, + : AttributeCommonInfo(nullptr, AttributeScopeInfo(), AttrRange, K, FormUsed) {} AttributeCommonInfo(AttributeCommonInfo &&) = default; @@ -195,17 +195,27 @@ public: SourceRange getRange() const { return AttrRange; } void setRange(SourceRange R) { AttrRange = R; } - bool hasScope() const { return ScopeName; } - const IdentifierInfo *getScopeName() const { return ScopeName; } - SourceLocation getScopeLoc() const { return ScopeLoc; } + bool hasScope() const { return AttrScope.isValid(); } + bool isExplicitScope() const { return AttrScope.isExplicit(); } + + const IdentifierInfo *getScopeName() const { return AttrScope.getName(); } + SourceLocation getScopeLoc() const { return AttrScope.getNameLoc(); } /// Gets the normalized full name, which consists of both scope and name and /// with surrounding underscores removed as appropriate (e.g. /// __gnu__::__attr__ will be normalized to gnu::attr). std::string getNormalizedFullName() const; - std::optional - getCorrectedFullName(const TargetInfo &Target, - const LangOptions &LangOpts) const; + std::string getNormalizedFullName(StringRef ScopeName, + StringRef AttrName) const; + StringRef getNormalizedScopeName() const; + StringRef getNormalizedAttrName(StringRef ScopeName) const; + + std::optional tryGetCorrectedScopeName(StringRef ScopeName) const; + std::optional + tryGetCorrectedAttrName(StringRef ScopeName, StringRef AttrName, + const TargetInfo &Target, + const LangOptions &LangOpts) const; + SourceRange getNormalizedRange() const; bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } diff --git a/clang/include/clang/Basic/AttributeScopeInfo.h b/clang/include/clang/Basic/AttributeScopeInfo.h new file mode 100644 index 000000000000..cca4df7c11b0 --- /dev/null +++ b/clang/include/clang/Basic/AttributeScopeInfo.h @@ -0,0 +1,48 @@ +//==- AttributeScopeInfo.h - Base info about an Attribute Scope --*- 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 the AttributeScopeInfo type, which represents information +// about the scope of an attribute. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H +#define LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class IdentifierInfo; + +class AttributeScopeInfo { +public: + AttributeScopeInfo() = default; + + AttributeScopeInfo(const IdentifierInfo *Name, SourceLocation NameLoc) + : Name(Name), NameLoc(NameLoc) {} + + AttributeScopeInfo(const IdentifierInfo *Name, SourceLocation NameLoc, + SourceLocation CommonScopeLoc) + : Name(Name), NameLoc(NameLoc), CommonScopeLoc(CommonScopeLoc) {} + + const IdentifierInfo *getName() const { return Name; } + SourceLocation getNameLoc() const { return NameLoc; } + + bool isValid() const { return Name != nullptr; } + bool isExplicit() const { return CommonScopeLoc.isInvalid(); } + +private: + const IdentifierInfo *Name = nullptr; + SourceLocation NameLoc; + SourceLocation CommonScopeLoc; +}; + +} // namespace clang + +#endif // LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 68cd3d790e78..d65b3a5d2f44 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5065,6 +5065,19 @@ def HLSLGroupMemoryBarrierWithGroupSync: LangBuiltin<"HLSL_LANG"> { let Prototype = "void()"; } +class HLSLScalarTemplate + : Template<["bool", "char", "short", "int", "long long int", + "unsigned short", "unsigned int", "unsigned long long int", + "__fp16", "float", "double"], + ["_bool", "_char", "_short", "_int", "_longlong", "_ushort", + "_uint", "_ulonglong", "_half", "_float", "_double"]>; + +def HLSLGetSpirvSpecConstant : LangBuiltin<"HLSL_LANG">, HLSLScalarTemplate { + let Spellings = ["__builtin_get_spirv_spec_constant"]; + let Attributes = [NoThrow, Const, Pure]; + let Prototype = "T(unsigned int, T)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 802b4be42419..edb3a17ac07c 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -636,5 +636,11 @@ TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUi", "nc", "bitop3-insts") TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf16_f32, "V2yV2yfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts") TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_f16_f32, "V2hV2hfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts") +//===----------------------------------------------------------------------===// +// GFX1250+ only builtins. +//===----------------------------------------------------------------------===// + +TARGET_BUILTIN(__builtin_amdgcn_s_setprio_inc_wg, "vIs", "n", "setprio-inc-wg-inst") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index bb7d54bbb793..099500754a0e 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -1134,6 +1134,18 @@ UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2np, "vW512*VVi15i15i3", true, "mma,paired-vector-memops") UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2nn, "vW512*VVi15i15i3", true, "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_dmxvi8gerx4, "vW1024*W256V", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmdmxvi8gerx4, "vW1024*W256Vi255i15i15", false, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_dmxvi8gerx4pp, "vW1024*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmdmxvi8gerx4pp, "vW1024*W256Vi255i15i15", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_dmxvi8gerx4spp, "vW1024*W256V", true, + "mma,paired-vector-memops") +UNALIASED_CUSTOM_BUILTIN(mma_pmdmxvi8gerx4spp, "vW1024*W256Vi255i15i15", true, + "mma,paired-vector-memops") // FIXME: Obviously incomplete. diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index fa9474d63ae4..e5566a540dc6 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -223,9 +223,11 @@ AFFECTING_VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is CODEGENOPT(AtomicProfileUpdate , 1, 0) ///< Set -fprofile-update=atomic CODEGENOPT(ContinuousProfileSync, 1, 0) ///< Enable continuous instrumentation profiling /// Choose profile instrumenation kind or no instrumentation. -ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 4, ProfileNone) + +ENUM_CODEGENOPT(ProfileInstr, llvm::driver::ProfileInstrKind, 4, llvm::driver::ProfileInstrKind::ProfileNone) + /// Choose profile kind for PGO use compilation. -ENUM_CODEGENOPT(ProfileUse, ProfileInstrKind, 2, ProfileNone) +ENUM_CODEGENOPT(ProfileUse, llvm::driver::ProfileInstrKind, 2, llvm::driver::ProfileInstrKind::ProfileNone) /// Partition functions into N groups and select only functions in group i to be /// instrumented. Selected group numbers can be 0 to N-1 inclusive. VALUE_CODEGENOPT(ProfileTotalFunctionGroups, 32, 1) @@ -481,8 +483,10 @@ CODEGENOPT(StaticClosure, 1, 0) /// Assume that UAVs/SRVs may alias CODEGENOPT(ResMayAlias, 1, 0) -/// Enables unwind v2 (epilog) information for x64 Windows. -CODEGENOPT(WinX64EHUnwindV2, 1, 0) +/// Controls how unwind v2 (epilog) information should be generated for x64 +/// Windows. +ENUM_CODEGENOPT(WinX64EHUnwindV2, llvm::WinX64EHUnwindV2Mode, + 2, llvm::WinX64EHUnwindV2Mode::Disabled) /// FIXME: Make DebugOptions its own top-level .def file. #include "DebugOptions.def" diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index a77232c281f7..7ba21fca6dd6 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -80,16 +80,6 @@ public: SRCK_InRegs // Small structs in registers (-freg-struct-return). }; - enum ProfileInstrKind { - ProfileNone, // Profile instrumentation is turned off. - ProfileClangInstr, // Clang instrumentation to generate execution counts - // to use with PGO. - ProfileIRInstr, // IR level PGO instrumentation in LLVM. - ProfileCSIRInstr, // IR level PGO context sensitive instrumentation in LLVM. - ProfileIRSampleColdCov, // IR level sample pgo based cold function coverage - // instrumentation in LLVM. - }; - enum EmbedBitcodeKind { Embed_Off, // No embedded bitcode. Embed_All, // Embed both bitcode and commandline in the output. @@ -522,35 +512,41 @@ public: /// Check if Clang profile instrumenation is on. bool hasProfileClangInstr() const { - return getProfileInstr() == ProfileClangInstr; + return getProfileInstr() == + llvm::driver::ProfileInstrKind::ProfileClangInstr; } /// Check if IR level profile instrumentation is on. bool hasProfileIRInstr() const { - return getProfileInstr() == ProfileIRInstr; + return getProfileInstr() == llvm::driver::ProfileInstrKind::ProfileIRInstr; } /// Check if CS IR level profile instrumentation is on. bool hasProfileCSIRInstr() const { - return getProfileInstr() == ProfileCSIRInstr; + return getProfileInstr() == + llvm::driver::ProfileInstrKind::ProfileCSIRInstr; } /// Check if any form of instrumentation is on. - bool hasProfileInstr() const { return getProfileInstr() != ProfileNone; } + bool hasProfileInstr() const { + return getProfileInstr() != llvm::driver::ProfileInstrKind::ProfileNone; + } /// Check if Clang profile use is on. bool hasProfileClangUse() const { - return getProfileUse() == ProfileClangInstr; + return getProfileUse() == llvm::driver::ProfileInstrKind::ProfileClangInstr; } /// Check if IR level profile use is on. bool hasProfileIRUse() const { - return getProfileUse() == ProfileIRInstr || - getProfileUse() == ProfileCSIRInstr; + return getProfileUse() == llvm::driver::ProfileInstrKind::ProfileIRInstr || + getProfileUse() == llvm::driver::ProfileInstrKind::ProfileCSIRInstr; } /// Check if CSIR profile use is on. - bool hasProfileCSIRUse() const { return getProfileUse() == ProfileCSIRInstr; } + bool hasProfileCSIRUse() const { + return getProfileUse() == llvm::driver::ProfileInstrKind::ProfileCSIRInstr; + } /// Check if type and variable info should be emitted. bool hasReducedDebugInfo() const { diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index e9c54c3c487c..7ae4ef7df138 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -18,6 +18,7 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/UnsignedOrNone.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FunctionExtras.h" @@ -49,6 +50,7 @@ class FileSystem; namespace clang { class DeclContext; +class Diagnostic; class DiagnosticBuilder; class DiagnosticConsumer; class IdentifierInfo; @@ -228,6 +230,8 @@ public: class DiagnosticsEngine : public RefCountedBase { public: /// The level of the diagnostic, after it has been through mapping. + // FIXME: Make this an alias for DiagnosticIDs::Level as soon as + // we can use 'using enum'. enum Level { Ignored = DiagnosticIDs::Ignored, Note = DiagnosticIDs::Note, @@ -420,10 +424,13 @@ private: bool empty() const { return Files.empty(); } /// Clear out this map. - void clear() { + void clear(bool Soft) { + // Just clear the cache when in soft mode. Files.clear(); - FirstDiagState = CurDiagState = nullptr; - CurDiagStateLoc = SourceLocation(); + if (!Soft) { + FirstDiagState = CurDiagState = nullptr; + CurDiagStateLoc = SourceLocation(); + } } /// Produce a debugging dump of the diagnostic state. @@ -532,7 +539,7 @@ private: /// /// This is used to emit continuation diagnostics with the same level as the /// diagnostic that they follow. - DiagnosticIDs::Level LastDiagLevel; + Level LastDiagLevel; /// Number of warnings reported unsigned NumWarnings; @@ -777,18 +784,16 @@ public: /// the middle of another diagnostic. /// /// This can be used by clients who suppress diagnostics themselves. - void setLastDiagnosticIgnored(bool Ignored) { - if (LastDiagLevel == DiagnosticIDs::Fatal) + void setLastDiagnosticIgnored(bool IsIgnored) { + if (LastDiagLevel == Fatal) FatalErrorOccurred = true; - LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning; + LastDiagLevel = IsIgnored ? Ignored : Warning; } /// Determine whether the previous diagnostic was ignored. This can /// be used by clients that want to determine whether notes attached to a /// diagnostic will be suppressed. - bool isLastDiagnosticIgnored() const { - return LastDiagLevel == DiagnosticIDs::Ignored; - } + bool isLastDiagnosticIgnored() const { return LastDiagLevel == Ignored; } /// Controls whether otherwise-unmapped extension diagnostics are /// mapped onto ignore/warning/error. @@ -918,6 +923,10 @@ public: /// Reset the state of the diagnostic object to its initial configuration. /// \param[in] soft - if true, doesn't reset the diagnostic mappings and state void Reset(bool soft = false); + /// We keep a cache of FileIDs for diagnostics mapped by pragmas. These might + /// get invalidated when diagnostics engine is shared across different + /// compilations. Provide users with a way to reset that. + void ResetPragmas(); //===--------------------------------------------------------------------===// // DiagnosticsEngine classification and reporting interfaces. @@ -1024,9 +1033,10 @@ private: /// Used to report a diagnostic that is finally fully formed. /// /// \returns true if the diagnostic was emitted, false if it was suppressed. - bool ProcessDiag(const DiagnosticBuilder &DiagBuilder) { - return Diags->ProcessDiag(*this, DiagBuilder); - } + bool ProcessDiag(const DiagnosticBuilder &DiagBuilder); + + /// Forward a diagnostic to the DiagnosticConsumer. + void Report(Level DiagLevel, const Diagnostic &Info); /// @name Diagnostic Emission /// @{ diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 20fb47237c56..29f6480ba935 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -206,6 +206,8 @@ def err_drv_cannot_open_randomize_layout_seed_file : Error< "cannot read randomize layout seed file '%0'">; def err_drv_invalid_version_number : Error< "invalid version number in '%0'">; +def err_drv_invalid_version_number_inferred + : Error<"invalid version number '%0' inferred from '%1'">; def err_drv_missing_version_number : Error<"missing version number in '%0'">; def err_drv_kcfi_arity_unsupported_target : Error< "target '%0' is unsupported by -fsanitize-kcfi-arity">; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index f1854010e56b..b8744a25f10c 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -806,32 +806,39 @@ def UniqueObjectDuplication : DiagGroup<"unique-object-duplication"> { Warns when objects which are supposed to be globally unique might get duplicated when built into a shared library. -If an object with hidden visibility is built into a shared library, each instance +This can occur to objects which are hidden from the dynamic linker, due to +having hidden visibility (on posix) or lacking a dllimport/dllexport attribute +(on windows). If such an object is built into a shared library, each instance of the library will get its own copy. This can cause very subtle bugs if there was only supposed to be one copy of the object in question: singletons aren't single, changes to one object won't affect the others, the object's initializer will run once per copy, etc. Specifically, this warning fires when it detects an object which: -1. Is defined as ``inline`` in a header file (so it might get compiled into multiple libaries), and -2. Has external linkage (otherwise it's supposed to be duplicated), and -3. Has hidden visibility. + +#. Is defined as ``inline`` in a header file (so it might get compiled into multiple libaries), and +#. Has external linkage (otherwise it's supposed to be duplicated), and +#. Has hidden visibility (posix) or lacks a dllimport/dllexport attribute (windows). As well as one of the following: -1. The object is mutable, or -2. The object's initializer definitely has side effects. + +#. The object is mutable, or +#. The object's initializer definitely has side effects. The warning can be resolved by removing one of the conditions above. In rough order of preference, this may be done by: -1. Marking the object ``const`` (if possible) -2. Moving the object's definition to a source file -3. Giving the object non-hidden visibility, e.g. using ``__attribute((visibility("default")))``. + +#. Marking the object ``const`` (if possible) +#. Moving the object's definition to a source file +#. Making the object visible using ``__attribute((visibility("default")))``, + ``__declspec(dllimport)``, or ``__declspec(dllexport)``. + +When annotating an object with ``__declspec(dllimport)`` or ``__declspec(dllexport)``, +take care to ensure that the object is only exported from one dll, and is imported +everywhere else. Note that for (2), all levels of a pointer variable must be constant; ``const int*`` will trigger the warning because the pointer itself is mutable. - -This warning is not yet implemented for Windows, since Windows uses -import/export rules instead of visibility. }]; } diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index a5b8477cb4f2..3e8d27aa24a5 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -485,18 +485,6 @@ private: Class getDiagClass(unsigned DiagID) const; - /// Used to report a diagnostic that is finally fully formed. - /// - /// \returns \c true if the diagnostic was emitted, \c false if it was - /// suppressed. - bool ProcessDiag(DiagnosticsEngine &Diag, - const DiagnosticBuilder &DiagBuilder) const; - - /// Used to emit a diagnostic that is finally fully formed, - /// ignoring suppression. - void EmitDiag(DiagnosticsEngine &Diag, const DiagnosticBuilder &DiagBuilder, - Level DiagLevel) const; - /// Whether the diagnostic may leave the AST in a state where some /// invariants can break. bool isUnrecoverable(unsigned DiagID) const; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 0f2ef8b688a7..457c3515fa4f 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1581,8 +1581,10 @@ def err_omp_unexpected_append_op : Error< "unexpected operation specified in 'append_args' clause, expected 'interop'">; def err_omp_unexpected_execution_modifier : Error< "unexpected 'execution' modifier in non-executable context">; -def err_omp_unknown_adjust_args_op : Error< - "incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'">; +def err_omp_unknown_adjust_args_op + : Error< + "incorrect 'adjust_args' type, expected 'need_device_ptr'%select{|, " + "'need_device_addr',}0 or 'nothing'">; def err_omp_declare_variant_wrong_clause : Error< "expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause " "on 'omp declare variant' directive">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7782e35e0d05..c7c054398782 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1781,7 +1781,7 @@ def note_unsatisfied_trait_reason "%HasArcLifetime{has an ARC lifetime qualifier}|" "%VLA{is a variably-modified type}|" "%VBase{has a virtual base %1}|" - "%NotScalarOrClass{not %select{a|an array of objects of}1 scalar or " + "%NotScalarOrClass{is not %select{a|an array of objects of}1 scalar or " "class type}|" "%NTRBase{has a non-trivially-relocatable base %1}|" "%NTRField{has a non-trivially-relocatable member %1 of type %2}|" @@ -6351,14 +6351,19 @@ def warn_static_local_in_extern_inline : Warning< def note_convert_inline_to_static : Note< "use 'static' to give inline function %0 internal linkage">; -def warn_possible_object_duplication_mutable : Warning< - "%0 may be duplicated when built into a shared library: " - "it is mutable, has hidden visibility, and external linkage">, - InGroup, DefaultIgnore; -def warn_possible_object_duplication_init : Warning< - "initialization of %0 may run twice when built into a shared library: " - "it has hidden visibility and external linkage">, - InGroup, DefaultIgnore; +def warn_possible_object_duplication_mutable + : Warning<"%0 may be duplicated when built into a shared library: " + "it is mutable, with external linkage and " + "%select{hidden visibility|no import/export annotation}1">, + InGroup, + DefaultIgnore; +def warn_possible_object_duplication_init + : Warning<"initialization of %0 may run twice when built into a shared " + "library: " + "it has external linkage and " + "%select{hidden visibility|no import/export annotation}1">, + InGroup, + DefaultIgnore; def ext_redefinition_of_typedef : ExtWarn< "redefinition of typedef %0 is a C11 feature">, @@ -13016,6 +13021,10 @@ def err_spirv_enum_not_int : Error< def err_spirv_enum_not_valid : Error< "invalid value for %select{storage class}0 argument">; +def err_specialization_const + : Error<"variable with 'vk::constant_id' attribute must be a const " + "int/float/enum/bool and be initialized with a literal">; + // errors of expect.with.probability def err_probability_not_constant_float : Error< "probability argument to __builtin_expect_with_probability must be constant " @@ -13139,6 +13148,11 @@ def err_invalid_hlsl_resource_type: Error< def err_hlsl_spirv_only: Error<"%0 is only available for the SPIR-V target">; def err_hlsl_vk_literal_must_contain_constant: Error<"the argument to vk::Literal must be a vk::integral_constant">; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Basic/OffloadArch.h b/clang/include/clang/Basic/OffloadArch.h index 99b1024b9d0d..4dda3ec2216f 100644 --- a/clang/include/clang/Basic/OffloadArch.h +++ b/clang/include/clang/Basic/OffloadArch.h @@ -98,6 +98,7 @@ enum class OffloadArch { GFX12_GENERIC, GFX1200, GFX1201, + GFX1250, AMDGCNSPIRV, Generic, // A processor model named 'generic' if the target backend defines a // public one. diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index b0de65df7e39..2b1dc1e0121b 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -214,6 +214,7 @@ OPENMP_ORIGINAL_SHARING_MODIFIER(default) // Adjust-op kinds for the 'adjust_args' clause. OPENMP_ADJUST_ARGS_KIND(nothing) OPENMP_ADJUST_ARGS_KIND(need_device_ptr) +OPENMP_ADJUST_ARGS_KIND(need_device_addr) // Binding kinds for the 'bind' clause. OPENMP_BIND_KIND(teams) diff --git a/clang/include/clang/Basic/PPCTypes.def b/clang/include/clang/Basic/PPCTypes.def index 9e2cb2aedc9f..fc4155ca98b2 100644 --- a/clang/include/clang/Basic/PPCTypes.def +++ b/clang/include/clang/Basic/PPCTypes.def @@ -30,6 +30,7 @@ #endif +PPC_VECTOR_MMA_TYPE(__dmr1024, DMR1024, 1024) PPC_VECTOR_MMA_TYPE(__vector_quad, VectorQuad, 512) PPC_VECTOR_VSX_TYPE(__vector_pair, VectorPair, 256) diff --git a/clang/include/clang/Basic/ProfileList.h b/clang/include/clang/Basic/ProfileList.h index b4217e49c18a..5338ef3992ad 100644 --- a/clang/include/clang/Basic/ProfileList.h +++ b/clang/include/clang/Basic/ProfileList.h @@ -49,17 +49,16 @@ public: ~ProfileList(); bool isEmpty() const { return Empty; } - ExclusionType getDefault(CodeGenOptions::ProfileInstrKind Kind) const; + ExclusionType getDefault(llvm::driver::ProfileInstrKind Kind) const; std::optional isFunctionExcluded(StringRef FunctionName, - CodeGenOptions::ProfileInstrKind Kind) const; + llvm::driver::ProfileInstrKind Kind) const; std::optional isLocationExcluded(SourceLocation Loc, - CodeGenOptions::ProfileInstrKind Kind) const; + llvm::driver::ProfileInstrKind Kind) const; std::optional - isFileExcluded(StringRef FileName, - CodeGenOptions::ProfileInstrKind Kind) const; + isFileExcluded(StringRef FileName, llvm::driver::ProfileInstrKind Kind) const; }; } // namespace clang diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 5f288afe6823..6bced6fad426 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -225,7 +225,6 @@ def ShuffleVectorExpr : StmtNode; def ConvertVectorExpr : StmtNode; def BlockExpr : StmtNode; def OpaqueValueExpr : StmtNode; -def TypoExpr : StmtNode; def RecoveryExpr : StmtNode; def BuiltinBitCastExpr : StmtNode; def EmbedExpr : StmtNode; diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index 3e22bfb330af..c6fd8a1a45fd 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -2397,7 +2397,7 @@ let RequiredFeatures = ["zvfbfmin"] in { } defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csilfd", [["vv", "v", "vv(Log2EEW:4)Uv"]]>; -let RequiredFeatures = ["zvfh"] in +let RequiredFeatures = ["zvfhmin"] in defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "x", [["vv", "v", "vv(Log2EEW:4)Uv"]]>; // unsigned type diff --git a/clang/include/clang/Basic/riscv_vector_common.td b/clang/include/clang/Basic/riscv_vector_common.td index c6753978274a..e3d589699645 100644 --- a/clang/include/clang/Basic/riscv_vector_common.td +++ b/clang/include/clang/Basic/riscv_vector_common.td @@ -593,7 +593,7 @@ let UnMaskedPolicyScheme = HasPolicyOperand, multiclass RVVSlideUpBuiltinSet { defm "" : RVVOutBuiltinSet; - let RequiredFeatures = ["zvfh"] in + let RequiredFeatures = ["zvfhmin"] in defm "" : RVVOutBuiltinSet; defm "" : RVVOutBuiltinSet; - let RequiredFeatures = ["zvfh"] in + let RequiredFeatures = ["zvfhmin"] in defm "" : RVVOutBuiltinSet; defm "" : RVVOutBuiltinSet(loc, val, dst, align); } + [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, + mlir::Location loc, + mlir::StringRef name, + mlir::Type type, + cir::GlobalLinkageKind linkage) { + mlir::OpBuilder::InsertionGuard guard(*this); + setInsertionPointToStart(mlirModule.getBody()); + return create(loc, name, type, linkage); + } + cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy, mlir::Value base, llvm::StringRef name, unsigned index) { @@ -213,22 +227,26 @@ public: //===--------------------------------------------------------------------===// cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, - mlir::Type returnType, mlir::ValueRange operands) { - return create(loc, callee, returnType, operands); + mlir::Type returnType, mlir::ValueRange operands, + cir::SideEffect sideEffect = cir::SideEffect::All) { + return create(loc, callee, returnType, operands, sideEffect); } cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee, - mlir::ValueRange operands) { + mlir::ValueRange operands, + cir::SideEffect sideEffect = cir::SideEffect::All) { return createCallOp(loc, mlir::SymbolRefAttr::get(callee), - callee.getFunctionType().getReturnType(), operands); + callee.getFunctionType().getReturnType(), operands, + sideEffect); } cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, - mlir::ValueRange operands) { + mlir::ValueRange operands, + cir::SideEffect sideEffect) { return create(loc, indirectTarget, funcType.getReturnType(), - operands); + operands, sideEffect); } //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index d22d265e8242..9e01dde379d7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -42,6 +42,11 @@ class CIR_TypedAttr traits = []> let assemblyFormat = [{}]; } +class CIR_I32EnumAttr cases> + : I32EnumAttr { + let cppNamespace = "::cir"; +} + class CIRUnitAttr traits = []> : CIR_Attr { let returnType = "bool"; @@ -307,9 +312,9 @@ def ConstComplexAttr : CIR_Attr<"ConstComplex", "const_complex", ); let builders = [ - AttrBuilderWithInferredContext<(ins "cir::ComplexType":$type, - "mlir::TypedAttr":$real, + AttrBuilderWithInferredContext<(ins "mlir::TypedAttr":$real, "mlir::TypedAttr":$imag), [{ + auto type = cir::ComplexType::get(real.getType()); return $_get(type.getContext(), type, real, imag); }]>, ]; diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 565c0676773e..852d3aa13114 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1858,6 +1858,36 @@ def FuncOp : CIR_Op<"func", [ // CallOp //===----------------------------------------------------------------------===// +def CIR_SideEffect : CIR_I32EnumAttr< + "SideEffect", "allowed side effects of a function", [ + I32EnumAttrCase<"All", 1, "all">, + I32EnumAttrCase<"Pure", 2, "pure">, + I32EnumAttrCase<"Const", 3, "const"> + ]> { + let description = [{ + The side effect attribute specifies the possible side effects of the callee + of a call operation. This is an enumeration attribute and all possible + enumerators are: + + - all: The callee can have any side effects. This is the default if no side + effects are explicitly listed. + - pure: The callee may read data from memory, but it cannot write data to + memory. This has the same effect as the GNU C/C++ attribute + `__attribute__((pure))`. + - const: The callee may not read or write data from memory. This has the + same effect as the GNU C/C++ attribute `__attribute__((const))`. + + Examples: + + ```mlir + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(pure) + %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(const) + ``` + }]; + let cppNamespace = "::cir"; +} + class CIR_CallOpBase extra_traits = []> : Op extra_traits = []> // will add in the future. dag commonArgs = (ins OptionalAttr:$callee, - Variadic:$args); + Variadic:$args, + DefaultValuedAttr:$side_effect); } def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> { @@ -1942,20 +1973,26 @@ def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> { let builders = [ // Build a call op for a direct call OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType, - "mlir::ValueRange":$operands), [{ + "mlir::ValueRange":$operands, + CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{ assert(callee && "callee attribute is required for direct call"); $_state.addOperands(operands); $_state.addAttribute("callee", callee); + $_state.addAttribute("side_effect", + SideEffectAttr::get($_builder.getContext(), sideEffect)); if (resType && !isa(resType)) $_state.addTypes(resType); }]>, // Build a call op for an indirect call OpBuilder<(ins "mlir::Value":$calleePtr, "mlir::Type":$resType, - "mlir::ValueRange":$operands), [{ + "mlir::ValueRange":$operands, + CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{ $_state.addOperands(calleePtr); $_state.addOperands(operands); if (resType && !isa(resType)) $_state.addTypes(resType); + $_state.addAttribute("side_effect", + SideEffectAttr::get($_builder.getContext(), sideEffect)); }]>, ]; } @@ -2059,6 +2096,7 @@ def VecCreateOp : CIR_Op<"vec.create", [Pure]> { }]; let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -2154,6 +2192,8 @@ def VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> { `(` $kind `,` $lhs `,` $rhs `)` `:` qualified(type($lhs)) `,` qualified(type($result)) attr-dict }]; + + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -2277,6 +2317,38 @@ def VecTernaryOp : CIR_Op<"vec.ternary", let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// VecSplatOp +//===----------------------------------------------------------------------===// + +def VecSplatOp : CIR_Op<"vec.splat", [Pure, + TypesMatchWith<"type of 'value' matches element type of 'result'", "result", + "value", "cast($_self).getElementType()">]> { + + let summary = "Convert a scalar into a vector"; + let description = [{ + The `cir.vec.splat` operation creates a vector value from a scalar value. + All elements of the vector have the same value, that of the given scalar. + + It's a separate operation from `cir.vec.create` because more + efficient LLVM IR can be generated for it, and because some optimization and + analysis passes can benefit from knowing that all elements of the vector + have the same value. + + ```mlir + %value = cir.const #cir.int<3> : !s32i + %value_vec = cir.vec.splat %value : !s32i, !cir.vector<4 x !s32i> + ``` + }]; + + let arguments = (ins CIR_VectorElementType:$value); + let results = (outs CIR_VectorType:$result); + + let assemblyFormat = [{ + $value `:` type($value) `,` qualified(type($result)) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // BaseClassAddrOp //===----------------------------------------------------------------------===// @@ -2320,4 +2392,58 @@ def BaseClassAddrOp : CIR_Op<"base_class_addr"> { }]; } +//===----------------------------------------------------------------------===// +// ComplexCreateOp +//===----------------------------------------------------------------------===// + +def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { + let summary = "Create a complex value from its real and imaginary parts"; + let description = [{ + The `cir.complex.create` operation takes two operands that represent the + real and imaginary part of a complex number, and yields the complex number. + + ```mlir + %0 = cir.const #cir.fp<1.000000e+00> : !cir.double + %1 = cir.const #cir.fp<2.000000e+00> : !cir.double + %2 = cir.complex.create %0, %1 : !cir.double -> !cir.complex + ``` + }]; + + let results = (outs CIR_ComplexType:$result); + let arguments = (ins + CIR_AnyIntOrFloatType:$real, + CIR_AnyIntOrFloatType:$imag + ); + + let assemblyFormat = [{ + $real `,` $imag + `:` qualified(type($real)) `->` qualified(type($result)) attr-dict + }]; + + let hasVerifier = 1; + let hasFolder = 1; +} + +//===----------------------------------------------------------------------===// +// Assume Operations +//===----------------------------------------------------------------------===// + +def AssumeOp : CIR_Op<"assume"> { + let summary = "Tell the optimizer that a boolean value is true"; + let description = [{ + The `cir.assume` operation takes a single boolean prediate as its only + argument and does not have any results. The operation tells the optimizer + that the predicate is always true. + + This operation corresponds to the `__assume` and the `__builtin_assume` + builtin functions. + }]; + + let arguments = (ins CIR_BoolType:$predicate); + + let assemblyFormat = [{ + $predicate `:` type($predicate) attr-dict + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index fb9697607513..41d7d725a09e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -600,7 +600,8 @@ def CIRRecordType : Type< def CIR_AnyType : AnyTypeOf<[ CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_IntType, - CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType + CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType, + CIR_ComplexType ]>; #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td index 80d78b11c2ba..203e42f7c575 100644 --- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td +++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td @@ -34,6 +34,8 @@ let cppNamespace = "::cir" in { "Return the number of operands, accounts for indirect call or " "exception info", "unsigned", "getNumArgOperands", (ins)>, + InterfaceMethod<"Return the side effects of the call operation", + "cir::SideEffect", "getSideEffect", (ins)>, ]; } diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index f89d386378e5..e0b2959f374f 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -81,9 +81,9 @@ struct MissingFeatures { static bool opFuncCPUAndFeaturesAttributes() { return false; } static bool opFuncSection() { return false; } static bool opFuncSetComdat() { return false; } + static bool opFuncAttributesForDefinition() { return false; } // CallOp handling - static bool opCallBuiltinFunc() { return false; } static bool opCallPseudoDtor() { return false; } static bool opCallAggregateArgs() { return false; } static bool opCallPaddingArgs() { return false; } @@ -95,7 +95,6 @@ struct MissingFeatures { static bool opCallReturn() { return false; } static bool opCallArgEvaluationOrder() { return false; } static bool opCallCallConv() { return false; } - static bool opCallSideEffect() { return false; } static bool opCallNoPrototypeFunc() { return false; } static bool opCallMustTail() { return false; } static bool opCallVirtual() { return false; } @@ -150,6 +149,8 @@ struct MissingFeatures { static bool cxxabiUseARMGuardVarABI() { return false; } static bool cxxabiAppleARM64CXXABI() { return false; } static bool cxxabiStructorImplicitParam() { return false; } + static bool isDiscreteBitFieldABI() { return false; } + static bool isBigEndian() { return false; } // Address class static bool addressOffset() { return false; } @@ -172,6 +173,11 @@ struct MissingFeatures { static bool astVarDeclInterface() { return false; } static bool stackSaveOp() { return false; } static bool aggValueSlot() { return false; } + static bool aggValueSlotMayOverlap() { return false; } + static bool aggValueSlotVolatile() { return false; } + static bool aggValueSlotDestructedFlag() { return false; } + static bool aggValueSlotAlias() { return false; } + static bool aggValueSlotGC() { return false; } static bool generateDebugInfo() { return false; } static bool pointerOverflowSanitizer() { return false; } static bool fpConstraints() { return false; } @@ -225,6 +231,17 @@ struct MissingFeatures { static bool isMemcpyEquivalentSpecialMember() { return false; } static bool isTrivialCtorOrDtor() { return false; } static bool implicitConstructorArgs() { return false; } + static bool intrinsics() { return false; } + static bool attributeNoBuiltin() { return false; } + static bool thunks() { return false; } + static bool runCleanupsScope() { return false; } + static bool lowerAggregateLoadStore() { return false; } + static bool dataLayoutTypeAllocSize() { return false; } + static bool asmLabelAttr() { return false; } + static bool builtinCall() { return false; } + static bool builtinCallF128() { return false; } + static bool builtinCallMathErrno() { return false; } + static bool nonFineGrainedBitfields() { return false; } // Missing types static bool dataMemberType() { return false; } @@ -240,7 +257,6 @@ struct MissingFeatures { // Future CIR operations static bool awaitOp() { return false; } static bool callOp() { return false; } - static bool complexCreateOp() { return false; } static bool complexImagOp() { return false; } static bool complexRealOp() { return false; } static bool ifOp() { return false; } diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 040ee025afaa..50be51769f1a 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -828,10 +828,8 @@ public: ID.AddInteger(paramInfo.getOpaqueValue()); } resultType.Profile(ID); - for (ArrayRef::iterator - i = argTypes.begin(), e = argTypes.end(); i != e; ++i) { - i->Profile(ID); - } + for (const CanQualType &argType : argTypes) + argType.Profile(ID); } }; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 00efe22a6992..e28fcf393fdf 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -579,7 +579,8 @@ multiclass BoolWOption> { + BothFlags suffix = BothFlags<[]>, + list flag_prefix = ["-"]> { defvar flag1 = FlagDefExpanded.Result, prefix, NAME, spelling_base>; @@ -600,12 +601,12 @@ multiclass BoolOptionWithoutMarshalling, Flags, + def flag1.RecordName : Flag, Flags, Visibility, HelpText, ImpliedByAnyOf {} - def flag2.RecordName : Flag<["-"], flag2.Spelling>, Flags, + def flag2.RecordName : Flag, Flags, Visibility, HelpText, ImpliedByAnyOf @@ -1774,7 +1775,7 @@ def fmcdc_max_test_vectors_EQ : Joined<["-"], "fmcdc-max-test-vectors=">, HelpText<"Maximum number of test vectors in MC/DC coverage">, MarshallingInfoInt, "0x7FFFFFFE">; def fprofile_generate : Flag<["-"], "fprofile-generate">, - Group, Visibility<[ClangOption, CLOption]>, + Group, Visibility<[ClangOption, CLOption, FlangOption, FC1Option]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">; def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, Group, Visibility<[ClangOption, CLOption]>, @@ -1791,7 +1792,7 @@ def fprofile_use : Flag<["-"], "fprofile-use">, Group, Visibility<[ClangOption, CLOption]>, Alias; def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group, - Visibility<[ClangOption, CLOption]>, + Visibility<[ClangOption, CLOption, FlangOption, FC1Option]>, MetaVarName<"">, HelpText<"Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from /default.profdata. Otherwise, it reads from file .">; def fno_profile_instr_generate : Flag<["-"], "fno-profile-instr-generate">, @@ -2169,11 +2170,14 @@ defm assume_nothrow_exception_dtor: BoolFOption<"assume-nothrow-exception-dtor", LangOpts<"AssumeNothrowExceptionDtor">, DefaultFalse, PosFlag, NegFlag>; -defm winx64_eh_unwindv2 : BoolFOption<"winx64-eh-unwindv2", - CodeGenOpts<"WinX64EHUnwindV2">, DefaultFalse, - PosFlag, - NegFlag, - BothFlags<[], [ClangOption], " unwind v2 (epilog) information for x64 Windows">>; +def winx64_eh_unwindv2 + : Joined<["-"], "fwinx64-eh-unwindv2=">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Generate unwind v2 (epilog) information for x64 Windows">, + Values<"disabled,best-effort,required">, + NormalizedValues<["Disabled", "BestEffort", "Required"]>, + NormalizedValuesScope<"llvm::WinX64EHUnwindV2Mode">, + MarshallingInfoEnum, "Disabled">; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group, Visibility<[ClangOption, CLOption]>, HelpText<"Allows control over excess precision on targets where native " @@ -3350,6 +3354,9 @@ defm pch_codegen: OptInCC1FFlag<"pch-codegen", "Generate ", "Do not generate ", "code for uses of this PCH that assumes an explicit object file will be built for the PCH">; defm pch_debuginfo: OptInCC1FFlag<"pch-debuginfo", "Generate ", "Do not generate ", "debug info for types in an object file built from this PCH and do not generate them elsewhere">; +def ignore_pch : Flag<["-"], "ignore-pch">, Group, + Visibility<[ClangOption]>, + HelpText<"Disable precompiled headers, overrides -emit-pch and -include-pch">; def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group, Visibility<[ClangOption, CC1Option, CLOption]>, @@ -3475,8 +3482,9 @@ def fveclib : Joined<["-"], "fveclib=">, Group, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Use the given vector functions library">, HelpTextForVariants<[ClangOption, CC1Option], - "Use the given vector functions library. " - "Note: -fveclib={ArmPL,SLEEF} implies -fno-math-errno">, + "Use the given vector functions library.\n" + " Note: -fveclib={ArmPL,SLEEF,libmvec} implies -fno-math-errno.\n" + " Note: -fveclib=libmvec on AArch64 requires GLIBC 2.40 or newer.">, Values<"Accelerate,libmvec,MASSV,SVML,SLEEF,Darwin_libsystem_m,ArmPL,AMDLIBM,none">, NormalizedValuesScope<"llvm::driver::VectorLibrary">, NormalizedValues<["Accelerate", "LIBMVEC", "MASSV", "SVML", "SLEEF", @@ -5090,9 +5098,10 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group, Visibility<[ClangOption, FlangOption]>, HelpText<"Specify the size in bits of an RVV vector register">, DocBrief; def mfix_cortex_a53_835769 : Flag<["-"], "mfix-cortex-a53-835769">, Group, - HelpText<"Workaround Cortex-A53 erratum 835769 (AArch64 only)">; + HelpText<"Work around Cortex-A53 erratum 835769 (AArch64 only)">; def mno_fix_cortex_a53_835769 : Flag<["-"], "mno-fix-cortex-a53-835769">, Group, - HelpText<"Don't workaround Cortex-A53 erratum 835769 (AArch64 only)">; + HelpText<"Don't work around Cortex-A53 erratum 835769 (AArch64 only)">; +def mfix_cortex_a53_843419 : Flag<["-"], "mfix-cortex-a53-843419">, + Group, + HelpText<"Work around Cortex-A53 erratum 843419 (AArch64 only)">; +def mno_fix_cortex_a53_843419 : Flag<["-"], "mno-fix-cortex-a53-843419">, + Group, + HelpText<"Don't work around Cortex-A53 erratum 843419 (AArch64 only)">; def mmark_bti_property : Flag<["-"], "mmark-bti-property">, Group, HelpText<"Add .note.gnu.property with BTI to assembly files (AArch64 only)">; @@ -5776,12 +5791,17 @@ def nobuiltininc : Flag<["-"], "nobuiltininc">, Group, HelpText<"Disable builtin #include directories only">, MarshallingInfoNegativeFlag>; -def nogpuinc : Flag<["-"], "nogpuinc">, Group, - HelpText<"Do not add include paths for CUDA/HIP and" - " do not include the default CUDA/HIP wrapper headers">; +defm offload_inc: BoolOptionWithoutMarshalling<"", "offload-inc", + PosFlag, + NegFlag, + BothFlags<[]>, ["--"]>, Group; +def : Flag<["-"], "nogpuinc">, Alias; + def nohipwrapperinc : Flag<["-"], "nohipwrapperinc">, Group, HelpText<"Do not include the default HIP wrapper headers and include paths">; -def : Flag<["-"], "nocudainc">, Alias; +def : Flag<["-"], "nocudainc">, Alias; def no_offloadlib : Flag<["--"], "no-offloadlib">, MarshallingInfoFlag>, @@ -7795,7 +7815,7 @@ def fpatchable_function_entry_section_EQ MarshallingInfoString>; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation">, Values<"none,clang,llvm,csllvm,sample-coldcov">, - NormalizedValuesScope<"CodeGenOptions">, + NormalizedValuesScope<"llvm::driver::ProfileInstrKind">, NormalizedValues<["ProfileNone", "ProfileClangInstr", "ProfileIRInstr", "ProfileCSIRInstr", "ProfileIRSampleColdCov"]>, MarshallingInfoEnum, "ProfileNone">; def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">, @@ -9005,7 +9025,9 @@ def _SLASH_volatile_Group : OptionGroup<"">, Group; def _SLASH_d2epilogunwind : CLFlag<"d2epilogunwind">, - HelpText<"Enable unwind v2 (epilog) information for x64 Windows">; + HelpText<"Best effort generate unwind v2 (epilog) information for x64 Windows">; +def _SLASH_d2epilogunwindrequirev2 : CLFlag<"d2epilogunwindrequirev2">, + HelpText<"Require generation of unwind v2 (epilog) information for x64 Windows">; def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">; def _SLASH_EP : CLFlag<"EP">, HelpText<"Disable linemarker output and preprocess to stdout">; diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 127b1d08919d..2a5cf5fb50db 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5275,7 +5275,7 @@ struct FormatStyle { /// Remove all empty lines at the beginning and the end of namespace body. /// \code /// namespace N1 { - /// namespace N2 + /// namespace N2 { /// function(); /// } /// } diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index 297acf96557d..1a8381ee0243 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -143,6 +143,9 @@ class Lexer : public PreprocessorLexer { /// True if this is the first time we're lexing the input file. bool IsFirstTimeLexingFile; + /// True if current lexing token is the first pp-token. + bool IsFirstPPToken; + // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n', // it also points to '\n.' const char *NewLinePtr; diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 78be2bd64d61..47830b428c8a 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -350,6 +350,9 @@ private: /// Whether the last token we lexed was an '@'. bool LastTokenWasAt = false; + /// First pp-token in current translation unit. + std::optional FirstPPToken; + /// A position within a C++20 import-seq. class StdCXXImportSeq { public: @@ -1766,6 +1769,20 @@ public: std::optional LexEmbedParameters(Token &Current, bool ForHasEmbed); + /// Whether the preprocessor already seen the first pp-token in main file. + bool hasSeenMainFileFirstPPToken() const { return FirstPPToken.has_value(); } + + /// Record first pp-token and check if it has a Token::FirstPPToken flag. + void HandleMainFileFirstPPToken(const Token &Tok) { + if (!hasSeenMainFileFirstPPToken() && Tok.isFirstPPToken() && + SourceMgr.isWrittenInMainFile(Tok.getLocation())) + FirstPPToken = Tok; + } + + Token getMainFileFirstPPToken() const { + assert(FirstPPToken && "First main file pp-token doesn't exists"); + return *FirstPPToken; + } bool LexAfterModuleImport(Token &Result); void CollectPpImportSuffix(SmallVectorImpl &Toks); diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 4f29fb7d1141..d4dfd7b44d9a 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -86,9 +86,12 @@ public: // macro stringizing or charizing operator. CommaAfterElided = 0x200, // The comma following this token was elided (MS). IsEditorPlaceholder = 0x400, // This identifier is a placeholder. - IsReinjected = 0x800, // A phase 4 token that was produced before and - // re-added, e.g. via EnterTokenStream. Annotation - // tokens are *not* reinjected. + + IsReinjected = 0x800, // A phase 4 token that was produced before and + // re-added, e.g. via EnterTokenStream. Annotation + // tokens are *not* reinjected. + FirstPPToken = 0x1000, // This token is the first pp token in the + // translation unit. }; tok::TokenKind getKind() const { return Kind; } @@ -318,6 +321,9 @@ public: /// represented as characters between '<#' and '#>' in the source code. The /// lexer uses identifier tokens to represent placeholders. bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } + + /// Returns true if this token is the first pp-token. + bool isFirstPPToken() const { return getFlag(FirstPPToken); } }; /// Information about the conditional stack (\#if directives) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0c925e23683a..e571f34f13db 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -293,9 +293,7 @@ public: return ConsumeToken(); } - SourceLocation getEndOfPreviousToken() { - return PP.getLocForEndOfToken(PrevTokLocation); - } + SourceLocation getEndOfPreviousToken() const; /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) @@ -3645,7 +3643,7 @@ private: /// keyword. bool isClassCompatibleKeyword(Token Tok) const; - void ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs); + void ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs); ///@} @@ -4216,8 +4214,7 @@ private: bool ParseExpressionList(SmallVectorImpl &Exprs, llvm::function_ref ExpressionStarts = llvm::function_ref(), - bool FailImmediatelyOnInvalidExpr = false, - bool EarlyTypoCorrection = false); + bool FailImmediatelyOnInvalidExpr = false); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 391c2177d75e..7c66c26a17a1 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -94,6 +94,8 @@ public: bool wasThisDeclarationADefinition(const FunctionDecl *FD) override; + bool hasInitializerWithSideEffects(const VarDecl *VD) const override; + /// Find all declarations with the given name in the /// given context. bool FindExternalVisibleDeclsByName(const DeclContext *DC, diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 9e050ab9a620..6b3c5a173417 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -204,10 +204,9 @@ private: /// Constructor for attributes with expression arguments. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, Form formUsed, - SourceLocation ellipsisLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), + AttributeScopeInfo scope, ArgsUnion *args, unsigned numArgs, + Form formUsed, SourceLocation ellipsisLoc) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), @@ -219,14 +218,14 @@ private: /// Constructor for availability attributes. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Parm, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Parm, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *messageExpr, Form formUsed, SourceLocation strict, const Expr *replacementExpr, const IdentifierLoc *environmentLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(1), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), HasProcessingCache(false), IsPragmaClangAttribute(false), UnavailableLoc(unavailable), MessageExpr(messageExpr), @@ -240,14 +239,13 @@ private: /// Constructor for objc_bridge_related attributes. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Parm1, IdentifierLoc *Parm2, IdentifierLoc *Parm3, - Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(3), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierLoc *Parm1, + IdentifierLoc *Parm2, IdentifierLoc *Parm3, Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(3), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { ArgsUnion *Args = getArgsBuffer(); Args[0] = Parm1; Args[1] = Parm2; @@ -256,14 +254,14 @@ private: /// Constructor for type_tag_for_datatype attribute. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *ArgKind, ParsedType matchingCType, - bool layoutCompatible, bool mustBeNull, Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(1), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierLoc *ArgKind, + ParsedType matchingCType, bool layoutCompatible, bool mustBeNull, + Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(1), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { ArgsUnion PVal(ArgKind); memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); @@ -274,9 +272,9 @@ private: /// Constructor for attributes with a single type argument. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, Form formUsed, SourceLocation ellipsisLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), + AttributeScopeInfo scope, ParsedType typeArg, Form formUsed, + SourceLocation ellipsisLoc) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), EllipsisLoc(ellipsisLoc), NumArgs(0), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true), @@ -287,13 +285,13 @@ private: /// Constructor for microsoft __declspec(property) attribute. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(0), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(0), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId); } @@ -735,21 +733,21 @@ public: void takeFrom(ParsedAttributesView &List, AttributePool &Pool); ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form, + AttributeScopeInfo scope, ArgsUnion *args, + unsigned numArgs, ParsedAttr::Form form, SourceLocation ellipsisLoc = SourceLocation()) { void *memory = allocate( ParsedAttr::totalSizeToAlloc(numArgs, 0, 0, 0, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - args, numArgs, form, ellipsisLoc)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, args, + numArgs, form, ellipsisLoc)); } ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Param, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, @@ -757,58 +755,54 @@ public: const Expr *ReplacementExpr, IdentifierLoc *EnvironmentLoc) { void *memory = allocate(AttributeFactory::AvailabilityAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - Param, introduced, deprecated, obsoleted, - unavailable, MessageExpr, form, strict, - ReplacementExpr, EnvironmentLoc)); + return add(new (memory) + ParsedAttr(attrName, attrRange, scope, Param, introduced, + deprecated, obsoleted, unavailable, MessageExpr, + form, strict, ReplacementExpr, EnvironmentLoc)); } ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param1, IdentifierLoc *Param2, - IdentifierLoc *Param3, ParsedAttr::Form form) { + AttributeScopeInfo scope, IdentifierLoc *Param1, + IdentifierLoc *Param2, IdentifierLoc *Param3, + ParsedAttr::Form form) { void *memory = allocate( ParsedAttr::totalSizeToAlloc(3, 0, 0, 0, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - Param1, Param2, Param3, form)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, Param1, + Param2, Param3, form)); } - ParsedAttr * - createTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *argumentKind, - ParsedType matchingCType, bool layoutCompatible, - bool mustBeNull, ParsedAttr::Form form) { + ParsedAttr *createTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, AttributeScopeInfo scope, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, ParsedAttr::Form form) { void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - argumentKind, matchingCType, - layoutCompatible, mustBeNull, form)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, argumentKind, + matchingCType, layoutCompatible, + mustBeNull, form)); } ParsedAttr *createTypeAttribute(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, - SourceLocation scopeLoc, ParsedType typeArg, + AttributeScopeInfo scope, ParsedType typeArg, ParsedAttr::Form formUsed, SourceLocation ellipsisLoc) { void *memory = allocate( ParsedAttr::totalSizeToAlloc(0, 0, 0, 1, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - typeArg, formUsed, ellipsisLoc)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, typeArg, + formUsed, ellipsisLoc)); } ParsedAttr * createPropertyAttribute(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, - ParsedAttr::Form formUsed) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, ParsedAttr::Form formUsed) { void *memory = allocate(AttributeFactory::PropertyAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - getterId, setterId, formUsed)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, getterId, + setterId, formUsed)); } }; @@ -982,19 +976,19 @@ public: /// Add attribute with expression arguments. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form, + AttributeScopeInfo scope, ArgsUnion *args, + unsigned numArgs, ParsedAttr::Form form, SourceLocation ellipsisLoc = SourceLocation()) { - ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, - args, numArgs, form, ellipsisLoc); + ParsedAttr *attr = pool.create(attrName, attrRange, scope, args, numArgs, + form, ellipsisLoc); addAtEnd(attr); return attr; } /// Add availability attribute. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Param, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, @@ -1002,33 +996,31 @@ public: const Expr *ReplacementExpr, IdentifierLoc *EnvironmentLoc) { ParsedAttr *attr = - pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced, - deprecated, obsoleted, unavailable, MessageExpr, form, - strict, ReplacementExpr, EnvironmentLoc); + pool.create(attrName, attrRange, scope, Param, introduced, deprecated, + obsoleted, unavailable, MessageExpr, form, strict, + ReplacementExpr, EnvironmentLoc); addAtEnd(attr); return attr; } /// Add objc_bridge_related attribute. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param1, IdentifierLoc *Param2, - IdentifierLoc *Param3, ParsedAttr::Form form) { - ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, - Param1, Param2, Param3, form); + AttributeScopeInfo scope, IdentifierLoc *Param1, + IdentifierLoc *Param2, IdentifierLoc *Param3, + ParsedAttr::Form form) { + ParsedAttr *attr = + pool.create(attrName, attrRange, scope, Param1, Param2, Param3, form); addAtEnd(attr); return attr; } /// Add type_tag_for_datatype attribute. - ParsedAttr * - addNewTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *argumentKind, - ParsedType matchingCType, bool layoutCompatible, - bool mustBeNull, ParsedAttr::Form form) { + ParsedAttr *addNewTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, AttributeScopeInfo scope, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, ParsedAttr::Form form) { ParsedAttr *attr = pool.createTypeTagForDatatype( - attrName, attrRange, scopeName, scopeLoc, argumentKind, matchingCType, + attrName, attrRange, scope, argumentKind, matchingCType, layoutCompatible, mustBeNull, form); addAtEnd(attr); return attr; @@ -1036,12 +1028,11 @@ public: /// Add an attribute with a single type argument. ParsedAttr *addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, ParsedAttr::Form formUsed, + AttributeScopeInfo scope, ParsedType typeArg, + ParsedAttr::Form formUsed, SourceLocation ellipsisLoc = SourceLocation()) { - ParsedAttr *attr = - pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc, - typeArg, formUsed, ellipsisLoc); + ParsedAttr *attr = pool.createTypeAttribute(attrName, attrRange, scope, + typeArg, formUsed, ellipsisLoc); addAtEnd(attr); return attr; } @@ -1049,11 +1040,10 @@ public: /// Add microsoft __delspec(property) attribute. ParsedAttr * addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, - ParsedAttr::Form formUsed) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, ParsedAttr::Form formUsed) { ParsedAttr *attr = pool.createPropertyAttribute( - attrName, attrRange, scopeName, scopeLoc, getterId, setterId, formUsed); + attrName, attrRange, scope, getterId, setterId, formUsed); addAtEnd(attr); return attr; } diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index ad12a3d73413..07b9e1bc10f5 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -427,6 +427,17 @@ public: return false; } + /// isInObjcMethodScope - Return true if this scope is, or is contained, in an + /// C function body. + bool isInCFunctionScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + if (S->isFunctionScope()) + return true; + } + + return false; + } + /// isInObjcMethodScope - Return true if this scope is, or is contained in, an /// Objective-C method body. Note that this method is not constant time. bool isInObjcMethodScope() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 62ff29bbacbd..9b9f483a9e70 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6755,10 +6755,6 @@ public: /// this expression evaluation context. unsigned NumCleanupObjects; - /// The number of typos encountered during this expression evaluation - /// context (i.e. the number of TypoExprs created). - unsigned NumTypos; - MaybeODRUseExprSet SavedMaybeODRUseExprs; /// The lambdas that are present within this context, if it @@ -6859,7 +6855,7 @@ public: Decl *ManglingContextDecl, ExpressionKind ExprContext) : Context(Context), ParentCleanup(ParentCleanup), - NumCleanupObjects(NumCleanupObjects), NumTypos(0), + NumCleanupObjects(NumCleanupObjects), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), InDiscardedStatement(false), InImmediateFunctionContext(false), InImmediateEscalatingFunctionContext(false) {} @@ -7197,8 +7193,7 @@ public: CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef Args = {}, - DeclContext *LookupCtx = nullptr, - TypoExpr **Out = nullptr); + DeclContext *LookupCtx = nullptr); /// If \p D cannot be odr-used in the current expression evaluation context, /// return a reason explaining why. Otherwise, return NOUR_None. @@ -8805,40 +8800,6 @@ public: ExprResult CheckUnevaluatedOperand(Expr *E); - /// Process any TypoExprs in the given Expr and its children, - /// generating diagnostics as appropriate and returning a new Expr if there - /// were typos that were all successfully corrected and ExprError if one or - /// more typos could not be corrected. - /// - /// \param E The Expr to check for TypoExprs. - /// - /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its - /// initializer. - /// - /// \param RecoverUncorrectedTypos If true, when typo correction fails, it - /// will rebuild the given Expr with all TypoExprs degraded to RecoveryExprs. - /// - /// \param Filter A function applied to a newly rebuilt Expr to determine if - /// it is an acceptable/usable result from a single combination of typo - /// corrections. As long as the filter returns ExprError, different - /// combinations of corrections will be tried until all are exhausted. - ExprResult CorrectDelayedTyposInExpr( - Expr *E, VarDecl *InitDecl = nullptr, - bool RecoverUncorrectedTypos = false, - llvm::function_ref Filter = - [](Expr *E) -> ExprResult { return E; }); - - ExprResult CorrectDelayedTyposInExpr( - ExprResult ER, VarDecl *InitDecl = nullptr, - bool RecoverUncorrectedTypos = false, - llvm::function_ref Filter = - [](Expr *E) -> ExprResult { return E; }) { - return ER.isInvalid() - ? ER - : CorrectDelayedTyposInExpr(ER.get(), InitDecl, - RecoverUncorrectedTypos, Filter); - } - IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo); @@ -9339,12 +9300,6 @@ public: /// for C++ records. llvm::FoldingSet SpecialMemberCache; - /// Holds TypoExprs that are created from `createDelayedTypo`. This is used by - /// `TransformTypos` in order to keep track of any TypoExprs that are created - /// recursively during typo correction and wipe them away if the correction - /// fails. - llvm::SmallVector TypoExprs; - enum class AcceptableKind { Visible, Reachable }; // Members have to be NamespaceDecl* or TranslationUnitDecl*. @@ -9434,10 +9389,6 @@ public: bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); - typedef std::function TypoDiagnosticGenerator; - typedef std::function - TypoRecoveryCallback; - RedeclarationKind forRedeclarationInCurContext() const; /// Look up a name, looking for a single declaration. Return @@ -9791,51 +9742,6 @@ public: const ObjCObjectPointerType *OPT = nullptr, bool RecordFailure = true); - /// Try to "correct" a typo in the source code by finding - /// visible declarations whose names are similar to the name that was - /// present in the source code. - /// - /// \param TypoName the \c DeclarationNameInfo structure that contains - /// the name that was present in the source code along with its location. - /// - /// \param LookupKind the name-lookup criteria used to search for the name. - /// - /// \param S the scope in which name lookup occurs. - /// - /// \param SS the nested-name-specifier that precedes the name we're - /// looking for, if present. - /// - /// \param CCC A CorrectionCandidateCallback object that provides further - /// validation of typo correction candidates. It also provides flags for - /// determining the set of keywords permitted. - /// - /// \param TDG A TypoDiagnosticGenerator functor that will be used to print - /// diagnostics when the actual typo correction is attempted. - /// - /// \param TRC A TypoRecoveryCallback functor that will be used to build an - /// Expr from a typo correction candidate. - /// - /// \param MemberContext if non-NULL, the context in which to look for - /// a member access expression. - /// - /// \param EnteringContext whether we're entering the context described by - /// the nested-name-specifier SS. - /// - /// \param OPT when non-NULL, the search for visible declarations will - /// also walk the protocols in the qualified interfaces of \p OPT. - /// - /// \returns a new \c TypoExpr that will later be replaced in the AST with an - /// Expr representing the result of performing typo correction, or nullptr if - /// typo correction is not possible. If nullptr is returned, no diagnostics - /// will be emitted and it is the responsibility of the caller to emit any - /// that are needed. - TypoExpr *CorrectTypoDelayed( - const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, - TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, - CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, - bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); - /// Kinds of missing import. Note, the values of these enumerators correspond /// to %select values in diagnostics. enum class MissingImportKind { @@ -9854,20 +9760,6 @@ public: SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover); - struct TypoExprState { - std::unique_ptr Consumer; - TypoDiagnosticGenerator DiagHandler; - TypoRecoveryCallback RecoveryHandler; - TypoExprState(); - TypoExprState(TypoExprState &&other) noexcept; - TypoExprState &operator=(TypoExprState &&other) noexcept; - }; - - const TypoExprState &getTypoExprState(TypoExpr *TE) const; - - /// Clears the state of the given TypoExpr. - void clearDelayedTypo(TypoExpr *TE); - /// Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); @@ -9890,23 +9782,15 @@ private: /// Determine if we could use all the declarations in the module. bool isUsableModule(const Module *M); - /// Helper for CorrectTypo and CorrectTypoDelayed used to create and - /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction - /// should be skipped entirely. + /// Helper for CorrectTypo used to create and populate a new + /// TypoCorrectionConsumer. Returns nullptr if typo correction should be + /// skipped entirely. std::unique_ptr makeTypoCorrectionConsumer( const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery); - /// The set of unhandled TypoExprs and their associated state. - llvm::MapVector DelayedTypos; - - /// Creates a new TypoExpr AST node. - TypoExpr *createDelayedTypo(std::unique_ptr TCC, - TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC, SourceLocation TypoLoc); - /// Cache for module units which is usable for current module. llvm::DenseSet UsableModuleUnitsCache; @@ -9996,7 +9880,8 @@ public: DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, ModuleIdPath Partition, - ModuleImportState &ImportState); + ModuleImportState &ImportState, + bool IntroducerIsFirstPPToken); /// The parser has processed a global-module-fragment declaration that begins /// the definition of the global module fragment of the current module unit. diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index ba5f06f93dc3..7d7eae4db532 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -98,6 +98,8 @@ public: HLSLWaveSizeAttr *mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL, int Min, int Max, int Preferred, int SpelledArgsCount); + HLSLVkConstantIdAttr * + mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, int Id); HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType); HLSLParamModifierAttr * @@ -119,9 +121,25 @@ public: bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + /// Computes the unique Root Signature identifier from the given signature, + /// then lookup if there is a previousy created Root Signature decl. + /// + /// Returns the identifier and if it was found + std::pair + ActOnStartRootSignatureDecl(StringRef Signature); + + /// Creates the Root Signature decl of the parsed Root Signature elements + /// onto the AST and push it onto current Scope + void ActOnFinishRootSignatureDecl( + SourceLocation Loc, IdentifierInfo *DeclIdent, + SmallVector &Elements); + + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); + void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); @@ -158,7 +176,7 @@ public: QualType getInoutParameterType(QualType Ty); bool transformInitList(const InitializedEntity &Entity, InitListExpr *Init); - + bool handleInitialization(VarDecl *VDecl, Expr *&Init); void deduceAddressSpace(VarDecl *Decl); private: diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 95874077050a..4d0da1102bb5 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -314,20 +314,6 @@ private: bool SearchNamespaces; }; -inline Sema::TypoExprState::TypoExprState() {} - -inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept { - *this = std::move(other); -} - -inline Sema::TypoExprState &Sema::TypoExprState:: -operator=(Sema::TypoExprState &&other) noexcept { - Consumer = std::move(other.Consumer); - DiagHandler = std::move(other.DiagHandler); - RecoveryHandler = std::move(other.RecoveryHandler); - return *this; -} - } // end namespace clang #endif diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index b629c6d29140..ed08ff0acf89 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -812,7 +812,8 @@ public: CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, - BinaryOperatorKind Opc = BO_PtrMemD); + BinaryOperatorKind Opc = BO_PtrMemD, + bool IsReinterpretCast = false); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 6498390fe96f..7b169f56b680 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -283,7 +283,7 @@ public: /// mapper' construct. QualType ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, TypeResult ParsedType); - /// Called on start of '#pragma omp declare mapper'. + /// Called for '#pragma omp declare mapper'. DeclGroupPtrTy ActOnOpenMPDeclareMapperDirective( Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, @@ -849,6 +849,7 @@ public: FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef AdjustArgsNothing, ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AdjustArgsNeedDeviceAddr, ArrayRef AppendArgs, SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, SourceRange SR); diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index ba676fd8698e..7a4b7d21bb20 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -373,6 +373,24 @@ struct LazySpecializationInfoLookupTable; } // namespace serialization +struct VisibleLookupBlockOffsets { + uint64_t VisibleOffset = 0; + uint64_t ModuleLocalOffset = 0; + uint64_t TULocalOffset = 0; + + operator bool() const { + return VisibleOffset || ModuleLocalOffset || TULocalOffset; + } +}; + +struct LookupBlockOffsets : VisibleLookupBlockOffsets { + uint64_t LexicalOffset = 0; + + operator bool() const { + return VisibleLookupBlockOffsets::operator bool() || LexicalOffset; + } +}; + /// Reads an AST files chain containing the contents of a translation /// unit. /// @@ -535,13 +553,6 @@ private: /// in the chain. DeclUpdateOffsetsMap DeclUpdateOffsets; - struct LookupBlockOffsets { - uint64_t LexicalOffset; - uint64_t VisibleOffset; - uint64_t ModuleLocalOffset; - uint64_t TULocalOffset; - }; - using DelayedNamespaceOffsetMapTy = llvm::DenseMap; @@ -1444,6 +1455,12 @@ private: const StringRef &operator*() && = delete; }; + /// VarDecls with initializers containing side effects must be emitted, + /// but DeclMustBeEmitted is not allowed to deserialize the intializer. + /// FIXME: Lower memory usage by removing VarDecls once the initializer + /// is deserialized. + llvm::SmallPtrSet InitSideEffectVars; + public: /// Get the buffer for resolving paths. SmallString<0> &getPathBuf() { return PathBuf; } @@ -2395,6 +2412,8 @@ public: bool wasThisDeclarationADefinition(const FunctionDecl *FD) override; + bool hasInitializerWithSideEffects(const VarDecl *VD) const override; + /// Retrieve a selector from the given module with its local ID /// number. Selector getLocalSelector(ModuleFile &M, unsigned LocalID); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index f4e8ba872c0d..5a02603742d0 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -19,6 +19,7 @@ #include "clang/AST/AbstractBasicWriter.h" #include "clang/AST/OpenACCClause.h" #include "clang/AST/OpenMPClause.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Serialization/SourceLocationEncoding.h" @@ -117,6 +118,13 @@ public: Record->push_back(BitOffset); } + void AddLookupOffsets(const LookupBlockOffsets &Offsets) { + AddOffset(Offsets.LexicalOffset); + AddOffset(Offsets.VisibleOffset); + AddOffset(Offsets.ModuleLocalOffset); + AddOffset(Offsets.TULocalOffset); + } + /// Add the given statement or expression to the queue of /// statements to emit. /// diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index cf4ae610ea51..97679ace8b61 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -75,6 +75,9 @@ class StoredDeclsList; class SwitchCase; class Token; +struct VisibleLookupBlockOffsets; +struct LookupBlockOffsets; + namespace serialization { enum class DeclUpdateKind; } // namespace serialization @@ -606,9 +609,7 @@ private: uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, const DeclContext *DC); void WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC, - uint64_t &VisibleBlockOffset, - uint64_t &ModuleLocalBlockOffset, - uint64_t &TULocalBlockOffset); + VisibleLookupBlockOffsets &Offsets); void WriteTypeDeclOffsets(); void WriteFileDeclIDsMap(); void WriteComments(ASTContext &Context); @@ -777,6 +778,9 @@ public: return (I == DeclIDs.end() || I->second >= clang::NUM_PREDEF_DECL_IDS); }; + void AddLookupOffsets(const LookupBlockOffsets &Offsets, + RecordDataImpl &Record); + /// Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordDataImpl &Record); // Emit a reference to a declaration if the declaration was emitted. @@ -899,6 +903,10 @@ public: return WritingModule && WritingModule->isNamedModule(); } + bool isWritingStdCXXHeaderUnit() const { + return WritingModule && WritingModule->isHeaderUnit(); + } + bool isGeneratingReducedBMI() const { return GeneratingReducedBMI; } bool getDoneWritingDeclsAndTypes() const { return DoneWritingDeclsAndTypes; } diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 2a96df80d100..2234143004b6 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -294,10 +294,12 @@ def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">, "Either the comparison is useless or there is division by zero.">, Documentation; -def DynamicTypeChecker : Checker<"DynamicTypeChecker">, - HelpText<"Check for cases where the dynamic and the static type of an object " - "are unrelated.">, - Documentation; +def DynamicTypeChecker + : Checker<"DynamicTypeChecker">, + HelpText<"Check for cases where the dynamic and the static type of an " + "object are unrelated.">, + Dependencies<[DynamicTypePropagation]>, + Documentation; def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">, HelpText<"Check that addresses to stack memory do not escape the function">, @@ -326,39 +328,34 @@ def StdVariantChecker : Checker<"StdVariant">, let ParentPackage = Nullability in { -def NullabilityBase : Checker<"NullabilityBase">, - HelpText<"Stores information during the analysis about nullability.">, - Documentation, - Hidden; + def NullPassedToNonnullChecker + : Checker<"NullPassedToNonnull">, + HelpText<"Warns when a null pointer is passed to a pointer which has a " + "_Nonnull type.">, + Documentation; -def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">, - HelpText<"Warns when a null pointer is passed to a pointer which has a " - "_Nonnull type.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullReturnedFromNonnullChecker + : Checker<"NullReturnedFromNonnull">, + HelpText<"Warns when a null pointer is returned from a function that " + "has _Nonnull return type.">, + Documentation; -def NullReturnedFromNonnullChecker : Checker<"NullReturnedFromNonnull">, - HelpText<"Warns when a null pointer is returned from a function that has " - "_Nonnull return type.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullableDereferencedChecker + : Checker<"NullableDereferenced">, + HelpText<"Warns when a nullable pointer is dereferenced.">, + Documentation; -def NullableDereferencedChecker : Checker<"NullableDereferenced">, - HelpText<"Warns when a nullable pointer is dereferenced.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullablePassedToNonnullChecker + : Checker<"NullablePassedToNonnull">, + HelpText<"Warns when a nullable pointer is passed to a pointer which " + "has a _Nonnull type.">, + Documentation; -def NullablePassedToNonnullChecker : Checker<"NullablePassedToNonnull">, - HelpText<"Warns when a nullable pointer is passed to a pointer which has a " - "_Nonnull type.">, - Dependencies<[NullabilityBase]>, - Documentation; - -def NullableReturnedFromNonnullChecker : Checker<"NullableReturnedFromNonnull">, - HelpText<"Warns when a nullable pointer is returned from a function that has " - "_Nonnull return type.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullableReturnedFromNonnullChecker + : Checker<"NullableReturnedFromNonnull">, + HelpText<"Warns when a nullable pointer is returned from a function " + "that has _Nonnull return type.">, + Documentation; } // end "nullability" diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h index 580b49a38dc7..70a7953918ac 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h @@ -18,6 +18,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/Support/SMTAPI.h" +#include + namespace clang { namespace ento { @@ -570,23 +572,35 @@ public: // TODO: Refactor to put elsewhere static inline QualType getAPSIntType(ASTContext &Ctx, const llvm::APSInt &Int) { - return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned()); + const QualType Ty = + Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned()); + if (!Ty.isNull()) + return Ty; + // If Ty is Null, could be because the original type was a _BitInt. + // Get the size of the _BitInt type (expressed in bits) and round it up to + // the next power of 2 that is at least the bit size of 'char' (usually 8). + unsigned CharTypeSize = Ctx.getTypeSize(Ctx.CharTy); + unsigned Pow2DestWidth = + std::max(llvm::bit_ceil(Int.getBitWidth()), CharTypeSize); + return Ctx.getIntTypeForBitwidth(Pow2DestWidth, Int.isSigned()); } // Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1. static inline std::pair fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) { llvm::APSInt NewInt; + unsigned APSIntBitwidth = Int.getBitWidth(); + QualType Ty = getAPSIntType(Ctx, Int); // FIXME: This should be a cast from a 1-bit integer type to a boolean type, // but the former is not available in Clang. Instead, extend the APSInt // directly. - if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) { - NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy)); - } else - NewInt = Int; - - return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt)); + if (APSIntBitwidth == 1 && Ty.isNull()) + return {Int.extend(Ctx.getTypeSize(Ctx.BoolTy)), + getAPSIntType(Ctx, NewInt)}; + if (llvm::isPowerOf2_32(APSIntBitwidth) || Ty.isNull()) + return {Int, Ty}; + return {Int.extend(Ctx.getTypeSize(Ty)), Ty}; } // Perform implicit type conversion on binary symbolic expressions. diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index a20a89a4c2b7..da83220babea 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -23,6 +23,8 @@ namespace clang { namespace tooling { namespace dependencies { +class DependencyScanningService; + using DependencyDirectivesTy = SmallVector; @@ -349,7 +351,7 @@ public: static const char ID; DependencyScanningWorkerFilesystem( - DependencyScanningFilesystemSharedCache &SharedCache, + DependencyScanningService &Service, IntrusiveRefCntPtr FS); llvm::ErrorOr status(const Twine &Path) override; @@ -435,10 +437,7 @@ private: /// Returns entry associated with the unique ID in the shared cache or nullptr /// if none is found. const CachedFileSystemEntry * - findSharedEntryByUID(llvm::vfs::Status Stat) const { - return SharedCache.getShardForUID(Stat.getUniqueID()) - .findEntryByUID(Stat.getUniqueID()); - } + findSharedEntryByUID(llvm::vfs::Status Stat) const; /// Associates the given entry with the filename in the local cache and /// returns it. @@ -452,20 +451,14 @@ private: /// some. Otherwise, constructs new one with the given error code, associates /// it with the filename and returns the result. const CachedFileSystemEntry & - getOrEmplaceSharedEntryForFilename(StringRef Filename, std::error_code EC) { - return SharedCache.getShardForFilename(Filename) - .getOrEmplaceEntryForFilename(Filename, EC); - } + getOrEmplaceSharedEntryForFilename(StringRef Filename, std::error_code EC); /// Returns entry associated with the filename in the shared cache if there is /// some. Otherwise, associates the given entry with the filename and returns /// it. const CachedFileSystemEntry & getOrInsertSharedEntryForFilename(StringRef Filename, - const CachedFileSystemEntry &Entry) { - return SharedCache.getShardForFilename(Filename) - .getOrInsertEntryForFilename(Filename, Entry); - } + const CachedFileSystemEntry &Entry); void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override { @@ -478,8 +471,9 @@ private: /// VFS. bool shouldBypass(StringRef Path) const; - /// The global cache shared between worker threads. - DependencyScanningFilesystemSharedCache &SharedCache; + /// The service associated with this VFS. + DependencyScanningService &Service; + /// The local cache is used by the worker thread to cache file system queries /// locally instead of querying the global cache every time. DependencyScanningFilesystemLocalCache LocalCache; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h index 4e97c7bc9f36..ceaf3c2279e7 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -87,7 +87,8 @@ public: ScanningOptimizations OptimizeArgs = ScanningOptimizations::Default, bool EagerLoadModules = false, bool TraceVFS = false, std::time_t BuildSessionTimestamp = - llvm::sys::toTimeT(std::chrono::system_clock::now())); + llvm::sys::toTimeT(std::chrono::system_clock::now()), + bool CacheNegativeStats = true); ScanningMode getMode() const { return Mode; } @@ -99,6 +100,8 @@ public: bool shouldTraceVFS() const { return TraceVFS; } + bool shouldCacheNegativeStats() const { return CacheNegativeStats; } + DependencyScanningFilesystemSharedCache &getSharedCache() { return SharedCache; } @@ -116,6 +119,7 @@ private: const bool EagerLoadModules; /// Whether to trace VFS accesses. const bool TraceVFS; + const bool CacheNegativeStats; /// The global file system cache. DependencyScanningFilesystemSharedCache SharedCache; /// The global module cache entries. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 62ca6f912b46..902cea1f98ee 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1178,7 +1178,7 @@ void ASTContext::setCurrentNamedModule(Module *M) { CurrentCXXNamedModule = M; } -bool ASTContext::isInSameModule(const Module *M1, const Module *M2) { +bool ASTContext::isInSameModule(const Module *M1, const Module *M2) const { if (!M1 != !M2) return false; @@ -1711,6 +1711,73 @@ void ASTContext::setRelocationInfoForCXXRecord( RelocatableClasses.insert({D, Info}); } +static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication( + ASTContext &Context, const CXXRecordDecl *Class) { + if (!Class->isPolymorphic()) + return false; + const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class); + using AuthAttr = VTablePointerAuthenticationAttr; + const AuthAttr *ExplicitAuth = BaseType->getAttr(); + if (!ExplicitAuth) + return Context.getLangOpts().PointerAuthVTPtrAddressDiscrimination; + AuthAttr::AddressDiscriminationMode AddressDiscrimination = + ExplicitAuth->getAddressDiscrimination(); + if (AddressDiscrimination == AuthAttr::DefaultAddressDiscrimination) + return Context.getLangOpts().PointerAuthVTPtrAddressDiscrimination; + return AddressDiscrimination == AuthAttr::AddressDiscrimination; +} + +ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) { + assert(isPointerAuthenticationAvailable()); + + T = T.getCanonicalType(); + if (T.hasAddressDiscriminatedPointerAuth()) + return PointerAuthContent::AddressDiscriminatedData; + const RecordDecl *RD = T->getAsRecordDecl(); + if (!RD) + return PointerAuthContent::None; + + if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD); + Existing != RecordContainsAddressDiscriminatedPointerAuth.end()) + return Existing->second; + + PointerAuthContent Result = PointerAuthContent::None; + + auto SaveResultAndReturn = [&]() -> PointerAuthContent { + auto [ResultIter, DidAdd] = + RecordContainsAddressDiscriminatedPointerAuth.try_emplace(RD, Result); + (void)ResultIter; + (void)DidAdd; + assert(DidAdd); + return Result; + }; + auto ShouldContinueAfterUpdate = [&](PointerAuthContent NewResult) { + static_assert(PointerAuthContent::None < + PointerAuthContent::AddressDiscriminatedVTable); + static_assert(PointerAuthContent::AddressDiscriminatedVTable < + PointerAuthContent::AddressDiscriminatedData); + if (NewResult > Result) + Result = NewResult; + return Result != PointerAuthContent::AddressDiscriminatedData; + }; + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { + if (primaryBaseHaseAddressDiscriminatedVTableAuthentication(*this, CXXRD) && + !ShouldContinueAfterUpdate( + PointerAuthContent::AddressDiscriminatedVTable)) + return SaveResultAndReturn(); + for (auto Base : CXXRD->bases()) { + if (!ShouldContinueAfterUpdate(findPointerAuthContent(Base.getType()))) + return SaveResultAndReturn(); + } + } + for (auto *FieldDecl : RD->fields()) { + if (!ShouldContinueAfterUpdate( + findPointerAuthContent(FieldDecl->getType()))) + return SaveResultAndReturn(); + } + return SaveResultAndReturn(); +} + void ASTContext::addedLocalImportDecl(ImportDecl *Import) { assert(!Import->getNextLocalImport() && "Import declaration already in the chain"); @@ -3469,6 +3536,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, case BuiltinType::BFloat16: case BuiltinType::VectorQuad: case BuiltinType::VectorPair: + case BuiltinType::DMR1024: OS << "?"; return; @@ -7469,6 +7537,12 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { cast(Y->getDeclContext()->getRedeclContext()))) return false; + // If either X or Y are local to the owning module, they are only possible to + // be the same entity if they are in the same module. + if (X->isModuleLocal() || Y->isModuleLocal()) + if (!isInSameModule(X->getOwningModule(), Y->getOwningModule())) + return false; + // Two typedefs refer to the same entity if they have the same underlying // type. if (const auto *TypedefX = dyn_cast(X)) @@ -13080,9 +13154,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return true; // Variables that have initialization with side-effects are required. - if (VD->getInit() && VD->getInit()->HasSideEffects(*this) && - // We can get a value-dependent initializer during error recovery. - (VD->getInit()->isValueDependent() || !VD->evaluateValue())) + if (VD->hasInitWithSideEffects()) return true; // Likewise, variables with tuple-like bindings are required if their @@ -14303,7 +14375,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName(), /*IgnoreDeduced=*/true), - As, /*CanonicalArgs=*/std::nullopt, X->getCanonicalTypeInternal()); + As, /*CanonicalArgs=*/{}, X->getCanonicalTypeInternal()); } case Type::Decltype: { const auto *DX = cast(X); @@ -14549,7 +14621,7 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, TY->template_arguments())) return QualType(); return Ctx.getTemplateSpecializationType(CTN, As, - /*CanonicalArgs=*/std::nullopt, + /*CanonicalArgs=*/{}, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 68be6355857c..80a3ee7b1bae 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -132,7 +132,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, /*CanonicalArgs=*/std::nullopt, QT); + TST->getTemplateName(), Args, /*CanonicalArgs=*/{}, QT); } break; } @@ -1145,7 +1145,7 @@ class TemplateDiff { Ty = Context.getTemplateSpecializationType( TemplateName(CTSD->getSpecializedTemplate()), - CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt, + CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/{}, Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs(); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 8f688023af82..9fdca92b0d6b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1683,7 +1683,7 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( if (!ToUnderlyingOrErr) return ToUnderlyingOrErr.takeError(); return Importer.getToContext().getTemplateSpecializationType( - *ToTemplateOrErr, ToTemplateArgs, std::nullopt, *ToUnderlyingOrErr); + *ToTemplateOrErr, ToTemplateArgs, {}, *ToUnderlyingOrErr); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -4189,7 +4189,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); auto **Memory = new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers]; - std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory); + llvm::copy(CtorInitializers, Memory); auto *ToCtor = cast(ToFunction); ToCtor->setCtorInitializers(Memory); ToCtor->setNumCtorInitializers(NumInitializers); @@ -4518,7 +4518,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { } SmallVector ToTPLists(D->NumTPLists); - auto **FromTPLists = D->getTrailingObjects(); + auto **FromTPLists = D->getTrailingObjects(); for (unsigned I = 0; I < D->NumTPLists; I++) { if (auto ListOrErr = import(FromTPLists[I])) ToTPLists[I] = *ListOrErr; @@ -7761,9 +7761,9 @@ ExpectedStmt ASTNodeImporter::VisitStringLiteral(StringLiteral *E) { E->tokloc_begin(), E->tokloc_end(), ToLocations.begin())) return std::move(Err); - return StringLiteral::Create( - Importer.getToContext(), E->getBytes(), E->getKind(), E->isPascal(), - *ToTypeOrErr, ToLocations.data(), ToLocations.size()); + return StringLiteral::Create(Importer.getToContext(), E->getBytes(), + E->getKind(), E->isPascal(), *ToTypeOrErr, + ToLocations); } ExpectedStmt ASTNodeImporter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { @@ -9399,8 +9399,9 @@ public: if (Err) return; - AttributeCommonInfo ToI(ToAttrName, ToScopeName, ToAttrRange, ToScopeLoc, - FromAttr->getParsedKind(), FromAttr->getForm()); + AttributeCommonInfo ToI( + ToAttrName, AttributeScopeInfo(ToScopeName, ToScopeLoc), ToAttrRange, + FromAttr->getParsedKind(), FromAttr->getForm()); // The "SemanticSpelling" is not needed to be passed to the constructor. // That value is recalculated from the SpellingListIndex if needed. ToAttr = T::Create(Importer.getToContext(), diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index fefb8f55a9ee..5875a925d3fb 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -224,6 +224,12 @@ void OMPDeclareVariantAttr::printPrettyPragma( PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end()); OS << ")"; } + if (adjustArgsNeedDeviceAddr_size()) { + OS << " adjust_args(need_device_addr:"; + PrintExprs(adjustArgsNeedDeviceAddr_begin(), + adjustArgsNeedDeviceAddr_end()); + OS << ")"; + } auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) { for (OMPInteropInfo *I = Begin; I != End; ++I) { diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index d91d5f16fc7a..965e23503603 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -176,7 +176,8 @@ static void emitSerialized(std::vector &Code, const T &Val, } // Access must be aligned! - size_t ValPos = align(Code.size()); + assert(aligned(Code.size())); + size_t ValPos = Code.size(); Size = align(Size); assert(aligned(ValPos + Size)); Code.resize(ValPos + Size); diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index bf38b2e5d537..c5ac40210e47 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -748,7 +748,8 @@ bool Compiler::VisitFloatingLiteral(const FloatingLiteral *E) { if (DiscardResult) return true; - return this->emitConstFloat(E->getValue(), E); + APFloat F = E->getValue(); + return this->emitFloat(F, E); } template @@ -4185,13 +4186,14 @@ bool Compiler::visitZeroInitializer(PrimType T, QualType QT, nullptr, E); case PT_MemberPtr: return this->emitNullMemberPtr(0, nullptr, E); - case PT_Float: - return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); + case PT_Float: { + APFloat F = APFloat::getZero(Ctx.getFloatSemantics(QT)); + return this->emitFloat(F, E); + } case PT_FixedPoint: { auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType()); return this->emitConstFixedPoint(FixedPoint::zero(Sem), E); } - llvm_unreachable("Implement"); } llvm_unreachable("unknown primitive type"); } @@ -4674,10 +4676,7 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, if (!visitInitializer(Init)) return false; - if (!this->emitFinishInit(Init)) - return false; - - return this->emitPopPtr(Init); + return this->emitFinishInitGlobal(Init); }; DeclScope LocalScope(this, VD); @@ -4698,51 +4697,45 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, return false; return !Init || (checkDecl() && initGlobal(*GlobalIndex)); - } else { - InitLinkScope ILS(this, InitLink::Decl(VD)); - - if (VarT) { - unsigned Offset = this->allocateLocalPrimitive( - VD, *VarT, VD->getType().isConstQualified(), nullptr, - ScopeKind::Block, IsConstexprUnknown); - if (Init) { - // If this is a toplevel declaration, create a scope for the - // initializer. - if (Toplevel) { - LocalScope Scope(this); - if (!this->visit(Init)) - return false; - return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); - } else { - if (!this->visit(Init)) - return false; - return this->emitSetLocal(*VarT, Offset, VD); - } - } - } else { - if (std::optional Offset = - this->allocateLocal(VD, VD->getType(), nullptr, ScopeKind::Block, - IsConstexprUnknown)) { - if (!Init) - return true; - - if (!this->emitGetPtrLocal(*Offset, Init)) - return false; - - if (!visitInitializer(Init)) - return false; - - if (!this->emitFinishInit(Init)) - return false; - - return this->emitPopPtr(Init); - } - return false; - } - return true; } + // Local variables. + InitLinkScope ILS(this, InitLink::Decl(VD)); - return false; + if (VarT) { + unsigned Offset = this->allocateLocalPrimitive( + VD, *VarT, VD->getType().isConstQualified(), nullptr, ScopeKind::Block, + IsConstexprUnknown); + if (Init) { + // If this is a toplevel declaration, create a scope for the + // initializer. + if (Toplevel) { + LocalScope Scope(this); + if (!this->visit(Init)) + return false; + return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); + } else { + if (!this->visit(Init)) + return false; + return this->emitSetLocal(*VarT, Offset, VD); + } + } + } else { + if (std::optional Offset = this->allocateLocal( + VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) { + if (!Init) + return true; + + if (!this->emitGetPtrLocal(*Offset, Init)) + return false; + + if (!visitInitializer(Init)) + return false; + + return this->emitFinishInitPop(Init); + } + return false; + } + return true; } template @@ -4751,8 +4744,10 @@ bool Compiler::visitAPValue(const APValue &Val, PrimType ValType, assert(!DiscardResult); if (Val.isInt()) return this->emitConst(Val.getInt(), ValType, E); - else if (Val.isFloat()) - return this->emitConstFloat(Val.getFloat(), E); + else if (Val.isFloat()) { + APFloat F = Val.getFloat(); + return this->emitFloat(F, E); + } if (Val.isLValue()) { if (Val.isNullPointer()) @@ -6133,8 +6128,10 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); if (!this->emitLoadFloat(E)) return false; - if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E)) + APFloat F(TargetSemantics, 1); + if (!this->emitFloat(F, E)) return false; + if (!this->emitAddf(getFPOptions(E), E)) return false; if (!this->emitStoreFloat(E)) @@ -6176,8 +6173,10 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); if (!this->emitLoadFloat(E)) return false; - if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E)) + APFloat F(TargetSemantics, 1); + if (!this->emitFloat(F, E)) return false; + if (!this->emitSubf(getFPOptions(E), E)) return false; if (!this->emitStoreFloat(E)) @@ -6591,10 +6590,6 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { return T->isReferenceType(); }; - // DecompositionDecls are just proxies for us. - if (isa(VD)) - return revisit(VD); - if ((VD->hasGlobalStorage() || VD->isStaticDataMember()) && typeShouldBeVisited(VD->getType())) { if (const Expr *Init = VD->getAnyInitializer(); @@ -6957,6 +6952,20 @@ bool Compiler::emitDummyPtr(const DeclTy &D, const Expr *E) { return true; } +template +bool Compiler::emitFloat(const APFloat &F, const Expr *E) { + assert(!DiscardResult && "Should've been checked before"); + + if (Floating::singleWord(F.getSemantics())) + return this->emitConstFloat(Floating(F), E); + + APInt I = F.bitcastToAPInt(); + return this->emitConstFloat( + Floating(const_cast(I.getRawData()), + llvm::APFloatBase::SemanticsToEnum(F.getSemantics())), + E); +} + // This function is constexpr if and only if To, From, and the types of // all subobjects of To and From are types T such that... // (3.1) - is_union_v is false; diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index ac3ad84766dc..a1d068cc7e0a 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -391,6 +391,7 @@ private: bool emitRecordDestruction(const Record *R, SourceInfo Loc); bool emitDestruction(const Descriptor *Desc, SourceInfo Loc); bool emitDummyPtr(const DeclTy &D, const Expr *E); + bool emitFloat(const APFloat &F, const Expr *E); unsigned collectBaseOffset(const QualType BaseType, const QualType DerivedType); bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 5531295dfa2f..46e4d0d940b3 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -368,7 +368,7 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsTemporary, bool IsConst, UnknownSize) : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(MD.value_or(0)), - AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), + AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type), IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index 846dc2fe92a7..a3eecd06369b 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -50,34 +50,57 @@ inline static std::string printArg(Program &P, CodePtr &OpPC) { } template <> inline std::string printArg(Program &P, CodePtr &OpPC) { - auto F = Floating::deserialize(*OpPC); - OpPC += align(F.bytesToSerialize()); + auto Sem = Floating::deserializeSemantics(*OpPC); - std::string Result; - llvm::raw_string_ostream SS(Result); - SS << F; - return Result; + unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits( + llvm::APFloatBase::EnumToSemantics(Sem)); + auto Memory = + std::make_unique(llvm::APInt::getNumWords(BitWidth)); + Floating Result(Memory.get(), Sem); + Floating::deserialize(*OpPC, &Result); + + OpPC += align(Result.bytesToSerialize()); + + std::string S; + llvm::raw_string_ostream SS(S); + SS << Result; + return S; } template <> inline std::string printArg>(Program &P, CodePtr &OpPC) { - auto F = IntegralAP::deserialize(*OpPC); - OpPC += align(F.bytesToSerialize()); + using T = IntegralAP; + uint32_t BitWidth = T::deserializeSize(*OpPC); + auto Memory = + std::make_unique(llvm::APInt::getNumWords(BitWidth)); - std::string Result; - llvm::raw_string_ostream SS(Result); - SS << F; - return Result; + T Result(Memory.get(), BitWidth); + T::deserialize(*OpPC, &Result); + + OpPC += align(Result.bytesToSerialize()); + + std::string Str; + llvm::raw_string_ostream SS(Str); + SS << Result; + return Str; } + template <> inline std::string printArg>(Program &P, CodePtr &OpPC) { - auto F = IntegralAP::deserialize(*OpPC); - OpPC += align(F.bytesToSerialize()); + using T = IntegralAP; + uint32_t BitWidth = T::deserializeSize(*OpPC); + auto Memory = + std::make_unique(llvm::APInt::getNumWords(BitWidth)); - std::string Result; - llvm::raw_string_ostream SS(Result); - SS << F; - return Result; + T Result(Memory.get(), BitWidth); + T::deserialize(*OpPC, &Result); + + OpPC += align(Result.bytesToSerialize()); + + std::string Str; + llvm::raw_string_ostream SS(Str); + SS << Result; + return Str; } template <> inline std::string printArg(Program &P, CodePtr &OpPC) { diff --git a/clang/lib/AST/ByteCode/Floating.h b/clang/lib/AST/ByteCode/Floating.h index 3750568fc23c..659892e720ab 100644 --- a/clang/lib/AST/ByteCode/Floating.h +++ b/clang/lib/AST/ByteCode/Floating.h @@ -17,63 +17,79 @@ #include "clang/AST/APValue.h" #include "llvm/ADT/APFloat.h" +// XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL +// floating values. +#define ALLOCATE_ALL 0 + namespace clang { namespace interp { using APFloat = llvm::APFloat; using APSInt = llvm::APSInt; +using APInt = llvm::APInt; +/// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY. +/// It will NOT copy the memory (unless, of course, copy() is called) and it +/// won't alllocate anything. The allocation should happen via InterpState or +/// Program. class Floating final { private: - // The underlying value storage. - APFloat F; + union { + uint64_t Val = 0; + uint64_t *Memory; + }; + llvm::APFloatBase::Semantics Semantics; + + APFloat getValue() const { + unsigned BitWidth = bitWidth(); + if (singleWord()) + return APFloat(getSemantics(), APInt(BitWidth, Val)); + unsigned NumWords = numWords(); + return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory)); + } public: - /// Zero-initializes a Floating. - Floating() : F(0.0f) {} - Floating(const APFloat &F) : F(F) {} + Floating() = default; + Floating(llvm::APFloatBase::Semantics Semantics) + : Val(0), Semantics(Semantics) {} + Floating(const APFloat &F) { - // Static constructors for special floating point values. - static Floating getInf(const llvm::fltSemantics &Sem) { - return Floating(APFloat::getInf(Sem)); + Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics()); + this->copy(F); } - const APFloat &getAPFloat() const { return F; } + Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics) + : Memory(Memory), Semantics(Semantics) {} - bool operator<(Floating RHS) const { return F < RHS.F; } - bool operator>(Floating RHS) const { return F > RHS.F; } - bool operator<=(Floating RHS) const { return F <= RHS.F; } - bool operator>=(Floating RHS) const { return F >= RHS.F; } - bool operator==(Floating RHS) const { return F == RHS.F; } - bool operator!=(Floating RHS) const { return F != RHS.F; } - Floating operator-() const { return Floating(-F); } + APFloat getAPFloat() const { return getValue(); } + + bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); } + bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); } + bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); } + bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); } APFloat::opStatus convertToInteger(APSInt &Result) const { bool IsExact; - return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact); + return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero, + &IsExact); } - Floating toSemantics(const llvm::fltSemantics *Sem, - llvm::RoundingMode RM) const { - APFloat Copy = F; + void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, + Floating *Result) const { + APFloat Copy = getValue(); bool LosesInfo; Copy.convert(*Sem, RM, &LosesInfo); (void)LosesInfo; - return Floating(Copy); - } - - /// Convert this Floating to one with the same semantics as \Other. - Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const { - return toSemantics(&Other.F.getSemantics(), RM); + Result->copy(Copy); } APSInt toAPSInt(unsigned NumBits = 0) const { - return APSInt(F.bitcastToAPInt()); + return APSInt(getValue().bitcastToAPInt()); } - APValue toAPValue(const ASTContext &) const { return APValue(F); } + APValue toAPValue(const ASTContext &) const { return APValue(getValue()); } void print(llvm::raw_ostream &OS) const { // Can't use APFloat::print() since it appends a newline. SmallVector Buffer; - F.toString(Buffer); + getValue().toString(Buffer); OS << Buffer; } std::string toDiagnosticString(const ASTContext &Ctx) const { @@ -83,25 +99,62 @@ public: return NameStr; } - unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); } + unsigned bitWidth() const { + return llvm::APFloatBase::semanticsSizeInBits(getSemantics()); + } + unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); } + bool singleWord() const { +#if ALLOCATE_ALL + return false; +#endif + return numWords() == 1; + } + static bool singleWord(const llvm::fltSemantics &Sem) { +#if ALLOCATE_ALL + return false; +#endif + return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1; + } + const llvm::fltSemantics &getSemantics() const { + return llvm::APFloatBase::EnumToSemantics(Semantics); + } + + void copy(const APFloat &F) { + if (singleWord()) { + Val = F.bitcastToAPInt().getZExtValue(); + } else { + assert(Memory); + std::memcpy(Memory, F.bitcastToAPInt().getRawData(), + numWords() * sizeof(uint64_t)); + } + } + + void take(uint64_t *NewMemory) { + if (singleWord()) + return; + + if (Memory) + std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t)); + Memory = NewMemory; + } bool isSigned() const { return true; } - bool isNegative() const { return F.isNegative(); } - bool isZero() const { return F.isZero(); } - bool isNonZero() const { return F.isNonZero(); } - bool isMin() const { return F.isSmallest(); } - bool isMinusOne() const { return F.isExactlyValue(-1.0); } - bool isNan() const { return F.isNaN(); } - bool isSignaling() const { return F.isSignaling(); } - bool isInf() const { return F.isInfinity(); } - bool isFinite() const { return F.isFinite(); } - bool isNormal() const { return F.isNormal(); } - bool isDenormal() const { return F.isDenormal(); } - llvm::FPClassTest classify() const { return F.classify(); } - APFloat::fltCategory getCategory() const { return F.getCategory(); } + bool isNegative() const { return getValue().isNegative(); } + bool isZero() const { return getValue().isZero(); } + bool isNonZero() const { return getValue().isNonZero(); } + bool isMin() const { return getValue().isSmallest(); } + bool isMinusOne() const { return getValue().isExactlyValue(-1.0); } + bool isNan() const { return getValue().isNaN(); } + bool isSignaling() const { return getValue().isSignaling(); } + bool isInf() const { return getValue().isInfinity(); } + bool isFinite() const { return getValue().isFinite(); } + bool isNormal() const { return getValue().isNormal(); } + bool isDenormal() const { return getValue().isDenormal(); } + llvm::FPClassTest classify() const { return getValue().classify(); } + APFloat::fltCategory getCategory() const { return getValue().getCategory(); } ComparisonCategoryResult compare(const Floating &RHS) const { - llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); + llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue()); switch (CmpRes) { case llvm::APFloatBase::cmpLessThan: return ComparisonCategoryResult::Less; @@ -118,97 +171,130 @@ public: static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, - Floating &Result) { + Floating *Result) { APFloat F = APFloat(Sem); APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM); - Result = Floating(F); + Result->copy(F); return Status; } - static Floating bitcastFromMemory(const std::byte *Buff, - const llvm::fltSemantics &Sem) { + static void bitcastFromMemory(const std::byte *Buff, + const llvm::fltSemantics &Sem, + Floating *Result) { size_t Size = APFloat::semanticsSizeInBits(Sem); llvm::APInt API(Size, true); llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); - - return Floating(APFloat(Sem, API)); + Result->copy(APFloat(Sem, API)); } void bitcastToMemory(std::byte *Buff) const { - llvm::APInt API = F.bitcastToAPInt(); + llvm::APInt API = getValue().bitcastToAPInt(); llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8); } // === Serialization support === size_t bytesToSerialize() const { - return sizeof(llvm::fltSemantics *) + - (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); + return sizeof(Semantics) + (numWords() * sizeof(uint64_t)); } void serialize(std::byte *Buff) const { - // Semantics followed by an APInt. - *reinterpret_cast(Buff) = &F.getSemantics(); - - llvm::APInt API = F.bitcastToAPInt(); - llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), - bitWidth() / 8); + std::memcpy(Buff, &Semantics, sizeof(Semantics)); + if (singleWord()) { + std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t)); + } else { + std::memcpy(Buff + sizeof(Semantics), Memory, + numWords() * sizeof(uint64_t)); + } } - static Floating deserialize(const std::byte *Buff) { - const llvm::fltSemantics *Sem; - std::memcpy((void *)&Sem, Buff, sizeof(void *)); - return bitcastFromMemory(Buff + sizeof(void *), *Sem); + static llvm::APFloatBase::Semantics + deserializeSemantics(const std::byte *Buff) { + return *reinterpret_cast(Buff); } - static Floating abs(const Floating &F) { - APFloat V = F.F; - if (V.isNegative()) - V.changeSign(); - return Floating(V); + static void deserialize(const std::byte *Buff, Floating *Result) { + llvm::APFloatBase::Semantics Semantics; + std::memcpy(&Semantics, Buff, sizeof(Semantics)); + + unsigned BitWidth = llvm::APFloat::semanticsSizeInBits( + llvm::APFloatBase::EnumToSemantics(Semantics)); + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + + Result->Semantics = Semantics; + if (NumWords == 1 && !ALLOCATE_ALL) { + std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t)); + } else { + assert(Result->Memory); + std::memcpy(Result->Memory, Buff + sizeof(Semantics), + NumWords * sizeof(uint64_t)); + } } // ------- static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - *R = Floating(A.F); - return R->F.add(B.F, RM); + APFloat LHS = A.getValue(); + APFloat RHS = B.getValue(); + + auto Status = LHS.add(RHS, RM); + R->copy(LHS); + return Status; } static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R) { - APFloat One(A.F.getSemantics(), 1); - *R = Floating(A.F); - return R->F.add(One, RM); + APFloat One(A.getSemantics(), 1); + APFloat LHS = A.getValue(); + + auto Status = LHS.add(One, RM); + R->copy(LHS); + return Status; } static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - *R = Floating(A.F); - return R->F.subtract(B.F, RM); + APFloat LHS = A.getValue(); + APFloat RHS = B.getValue(); + + auto Status = LHS.subtract(RHS, RM); + R->copy(LHS); + return Status; } static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R) { - APFloat One(A.F.getSemantics(), 1); - *R = Floating(A.F); - return R->F.subtract(One, RM); + APFloat One(A.getSemantics(), 1); + APFloat LHS = A.getValue(); + + auto Status = LHS.subtract(One, RM); + R->copy(LHS); + return Status; } static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - *R = Floating(A.F); - return R->F.multiply(B.F, RM); + + APFloat LHS = A.getValue(); + APFloat RHS = B.getValue(); + + auto Status = LHS.multiply(RHS, RM); + R->copy(LHS); + return Status; } static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - *R = Floating(A.F); - return R->F.divide(B.F, RM); + APFloat LHS = A.getValue(); + APFloat RHS = B.getValue(); + + auto Status = LHS.divide(RHS, RM); + R->copy(LHS); + return Status; } static bool neg(const Floating &A, Floating *R) { - *R = -A; + R->copy(-A.getValue()); return false; } }; diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index 13fdb5369f2b..af5cd2d13ecc 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -99,6 +99,9 @@ public: bool operator>=(Integral RHS) const { return V >= RHS.V; } bool operator==(Integral RHS) const { return V == RHS.V; } bool operator!=(Integral RHS) const { return V != RHS.V; } + bool operator>=(unsigned RHS) const { + return static_cast(V) >= RHS; + } bool operator>(unsigned RHS) const { return V >= 0 && static_cast(V) > RHS; diff --git a/clang/lib/AST/ByteCode/IntegralAP.h b/clang/lib/AST/ByteCode/IntegralAP.h index 8ee08dfb5cfe..6683db941c73 100644 --- a/clang/lib/AST/ByteCode/IntegralAP.h +++ b/clang/lib/AST/ByteCode/IntegralAP.h @@ -28,12 +28,19 @@ namespace interp { using APInt = llvm::APInt; using APSInt = llvm::APSInt; -template class Integral; +/// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY. +/// It will NOT copy the memory (unless, of course, copy() is called) and it +/// won't alllocate anything. The allocation should happen via InterpState or +/// Program. template class IntegralAP final { -private: +public: + union { + uint64_t *Memory = nullptr; + uint64_t Val; + }; + uint32_t BitWidth = 0; friend IntegralAP; - APInt V; template static T truncateCast(const APInt &V) { @@ -52,106 +59,126 @@ private: : V.trunc(BitSize).getZExtValue(); } + APInt getValue() const { + if (singleWord()) + return APInt(BitWidth, Val, Signed); + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + return llvm::APInt(BitWidth, NumWords, Memory); + } + public: using AsUnsigned = IntegralAP; - template - IntegralAP(T Value, unsigned BitWidth) - : V(APInt(BitWidth, static_cast(Value), Signed)) {} - - IntegralAP(APInt V) : V(V) {} - /// Arbitrary value for uninitialized variables. - IntegralAP() : IntegralAP(Signed ? -1 : 7, 3) {} - - IntegralAP operator-() const { return IntegralAP(-V); } - IntegralAP operator-(const IntegralAP &Other) const { - return IntegralAP(V - Other.V); + void take(uint64_t *NewMemory) { + assert(!singleWord()); + std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t)); + Memory = NewMemory; } + + void copy(const APInt &V) { + assert(BitWidth == V.getBitWidth()); + assert(numWords() == V.getNumWords()); + + if (V.isSingleWord()) { + if constexpr (Signed) + Val = V.getSExtValue(); + else + Val = V.getZExtValue(); + return; + } + assert(Memory); + std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t)); + } + + IntegralAP() = default; + /// Zeroed, single-word IntegralAP of the given bitwidth. + IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) { + assert(singleWord()); + } + IntegralAP(uint64_t *Memory, unsigned BitWidth) + : Memory(Memory), BitWidth(BitWidth) {} + IntegralAP(const APInt &V) : BitWidth(V.getBitWidth()) { + if (V.isSingleWord()) { + Val = Signed ? V.getSExtValue() : V.getZExtValue(); + } else { + Memory = const_cast(V.getRawData()); + } + } + + IntegralAP operator-() const { return IntegralAP(-getValue()); } bool operator>(const IntegralAP &RHS) const { if constexpr (Signed) - return V.ugt(RHS.V); - return V.sgt(RHS.V); + return getValue().sgt(RHS.getValue()); + return getValue().ugt(RHS.getValue()); } - bool operator>=(IntegralAP RHS) const { + bool operator>=(unsigned RHS) const { if constexpr (Signed) - return V.uge(RHS.V); - return V.sge(RHS.V); + return getValue().sge(RHS); + return getValue().uge(RHS); } bool operator<(IntegralAP RHS) const { if constexpr (Signed) - return V.slt(RHS.V); - return V.slt(RHS.V); - } - bool operator<=(IntegralAP RHS) const { - if constexpr (Signed) - return V.ult(RHS.V); - return V.ult(RHS.V); + return getValue().slt(RHS.getValue()); + return getValue().ult(RHS.getValue()); } template >> explicit operator Ty() const { - return truncateCast(V); + return truncateCast(getValue()); } template static IntegralAP from(T Value, unsigned NumBits = 0) { + if (NumBits == 0) + NumBits = sizeof(T) * 8; assert(NumBits > 0); + assert(APInt::getNumWords(NumBits) == 1); APInt Copy = APInt(NumBits, static_cast(Value), Signed); - return IntegralAP(Copy); } - template - static IntegralAP from(IntegralAP V, unsigned NumBits = 0) { - if (NumBits == 0) - NumBits = V.bitWidth(); - - if constexpr (InputSigned) - return IntegralAP(V.V.sextOrTrunc(NumBits)); - return IntegralAP(V.V.zextOrTrunc(NumBits)); - } - - template - static IntegralAP from(Integral I, unsigned BitWidth) { - return IntegralAP(I.toAPInt(BitWidth)); - } - - static IntegralAP zero(int32_t BitWidth) { - APInt V = APInt(BitWidth, 0LL, Signed); - return IntegralAP(V); - } - - constexpr unsigned bitWidth() const { return V.getBitWidth(); } + constexpr uint32_t bitWidth() const { return BitWidth; } + constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); } + constexpr bool singleWord() const { return numWords() == 1; } APSInt toAPSInt(unsigned Bits = 0) const { if (Bits == 0) Bits = bitWidth(); + APInt V = getValue(); if constexpr (Signed) - return APSInt(V.sext(Bits), !Signed); + return APSInt(getValue().sext(Bits), !Signed); else - return APSInt(V.zext(Bits), !Signed); + return APSInt(getValue().zext(Bits), !Signed); } APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } - bool isZero() const { return V.isZero(); } + bool isZero() const { return getValue().isZero(); } bool isPositive() const { if constexpr (Signed) - return V.isNonNegative(); + return getValue().isNonNegative(); return true; } bool isNegative() const { if constexpr (Signed) - return !V.isNonNegative(); + return !getValue().isNonNegative(); return false; } - bool isMin() const { return V.isMinValue(); } - bool isMax() const { return V.isMaxValue(); } + bool isMin() const { + if constexpr (Signed) + return getValue().isMinSignedValue(); + return getValue().isMinValue(); + } + bool isMax() const { + if constexpr (Signed) + return getValue().isMaxSignedValue(); + return getValue().isMaxValue(); + } static constexpr bool isSigned() { return Signed; } - bool isMinusOne() const { return Signed && V == -1; } + bool isMinusOne() const { return Signed && getValue().isAllOnes(); } - unsigned countLeadingZeros() const { return V.countl_zero(); } + unsigned countLeadingZeros() const { return getValue().countl_zero(); } - void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);} + void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); } std::string toDiagnosticString(const ASTContext &Ctx) const { std::string NameStr; llvm::raw_string_ostream OS(NameStr); @@ -161,53 +188,57 @@ public: IntegralAP truncate(unsigned BitWidth) const { if constexpr (Signed) - return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth())); + return IntegralAP( + getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth())); else - return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth())); + return IntegralAP( + getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth())); } IntegralAP toUnsigned() const { - APInt Copy = V; - return IntegralAP(Copy); + return IntegralAP(Memory, BitWidth); } void bitcastToMemory(std::byte *Dest) const { - llvm::StoreIntToMemory(V, (uint8_t *)Dest, bitWidth() / 8); + llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8); } - static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) { + static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, + IntegralAP *Result) { APInt V(BitWidth, static_cast(0), Signed); llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8); - return IntegralAP(V); + Result->copy(V); } ComparisonCategoryResult compare(const IntegralAP &RHS) const { assert(Signed == RHS.isSigned()); assert(bitWidth() == RHS.bitWidth()); + APInt V1 = getValue(); + APInt V2 = RHS.getValue(); if constexpr (Signed) { - if (V.slt(RHS.V)) + if (V1.slt(V2)) return ComparisonCategoryResult::Less; - if (V.sgt(RHS.V)) + if (V1.sgt(V2)) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; } assert(!Signed); - if (V.ult(RHS.V)) + if (V1.ult(V2)) return ComparisonCategoryResult::Less; - if (V.ugt(RHS.V)) + if (V1.ugt(V2)) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; } static bool increment(IntegralAP A, IntegralAP *R) { - IntegralAP One(1, A.bitWidth()); - return add(A, One, A.bitWidth() + 1, R); + APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); + return add(A, IntegralAP(One), A.bitWidth() + 1, R); } static bool decrement(IntegralAP A, IntegralAP *R) { - IntegralAP One(1, A.bitWidth()); - return sub(A, One, A.bitWidth() + 1, R); + APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); + return sub(A, IntegralAP(One), A.bitWidth() + 1, R); } static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { @@ -224,87 +255,96 @@ public: static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { if constexpr (Signed) - *R = IntegralAP(A.V.srem(B.V)); + R->copy(A.getValue().srem(B.getValue())); else - *R = IntegralAP(A.V.urem(B.V)); + R->copy(A.getValue().urem(B.getValue())); return false; } static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { if constexpr (Signed) - *R = IntegralAP(A.V.sdiv(B.V)); + R->copy(A.getValue().sdiv(B.getValue())); else - *R = IntegralAP(A.V.udiv(B.V)); + R->copy(A.getValue().udiv(B.getValue())); return false; } static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - *R = IntegralAP(A.V & B.V); + R->copy(A.getValue() & B.getValue()); return false; } static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - *R = IntegralAP(A.V | B.V); + R->copy(A.getValue() | B.getValue()); return false; } static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - *R = IntegralAP(A.V ^ B.V); + R->copy(A.getValue() ^ B.getValue()); return false; } static bool neg(const IntegralAP &A, IntegralAP *R) { - APInt AI = A.V; + APInt AI = A.getValue(); AI.negate(); - *R = IntegralAP(AI); + R->copy(AI); return false; } static bool comp(IntegralAP A, IntegralAP *R) { - *R = IntegralAP(~A.V); + R->copy(~A.getValue()); return false; } static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R) { - *R = IntegralAP(A.V.shl(B.V.getZExtValue())); + *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue())); } static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R) { - unsigned ShiftAmount = B.V.getZExtValue(); + unsigned ShiftAmount = B.getValue().getZExtValue(); if constexpr (Signed) - *R = IntegralAP(A.V.ashr(ShiftAmount)); + R->copy(A.getValue().ashr(ShiftAmount)); else - *R = IntegralAP(A.V.lshr(ShiftAmount)); + R->copy(A.getValue().lshr(ShiftAmount)); } // === Serialization support === size_t bytesToSerialize() const { - // 4 bytes for the BitWidth followed by N bytes for the actual APInt. - return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT); + assert(BitWidth != 0); + return sizeof(uint32_t) + (numWords() * sizeof(uint64_t)); } void serialize(std::byte *Buff) const { - assert(V.getBitWidth() < std::numeric_limits::max()); - uint32_t BitWidth = V.getBitWidth(); - std::memcpy(Buff, &BitWidth, sizeof(uint32_t)); - llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)), - BitWidth / CHAR_BIT); + if (singleWord()) + std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t)); + else { + std::memcpy(Buff + sizeof(uint32_t), Memory, + numWords() * sizeof(uint64_t)); + } } - static IntegralAP deserialize(const std::byte *Buff) { - uint32_t BitWidth; - std::memcpy(&BitWidth, Buff, sizeof(uint32_t)); - IntegralAP Val(APInt(BitWidth, 0ull, !Signed)); + static uint32_t deserializeSize(const std::byte *Buff) { + return *reinterpret_cast(Buff); + } - llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t), - BitWidth / CHAR_BIT); - return Val; + static void deserialize(const std::byte *Buff, IntegralAP *Result) { + uint32_t BitWidth = Result->BitWidth; + assert(BitWidth != 0); + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + + if (NumWords == 1) + std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t)); + else { + assert(Result->Memory); + std::memcpy(Result->Memory, Buff + sizeof(uint32_t), + NumWords * sizeof(uint64_t)); + } } private: @@ -312,7 +352,7 @@ private: static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, unsigned BitWidth, IntegralAP *R) { if constexpr (!Signed) { - R->V = Op{}(A.V, B.V); + R->copy(Op{}(A.getValue(), B.getValue())); return false; } @@ -320,7 +360,7 @@ private: const APSInt &RHS = B.toAPSInt(); APSInt Value = Op{}(LHS.extend(BitWidth), RHS.extend(BitWidth)); APSInt Result = Value.trunc(LHS.getBitWidth()); - R->V = Result; + R->copy(Result); return Result.extend(BitWidth) != Value; } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 5c8abffb3a99..1e2032feabb6 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1935,8 +1935,10 @@ bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth)) return false; - S.Stk.push>( - IntegralAP::from(Ptr.getIntegerRepresentation(), BitWidth)); + auto Result = S.allocAP>(BitWidth); + Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation())); + + S.Stk.push>(Result); return true; } @@ -1946,8 +1948,10 @@ bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth)) return false; - S.Stk.push>( - IntegralAP::from(Ptr.getIntegerRepresentation(), BitWidth)); + auto Result = S.allocAP>(BitWidth); + Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation())); + + S.Stk.push>(Result); return true; } @@ -2053,6 +2057,100 @@ bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, return Shorter == Longer.take_front(Shorter.size()); } +static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr, + PrimType T) { + + if (T == PT_IntAPS) { + auto &Val = Ptr.deref>(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } + } else if (T == PT_IntAP) { + auto &Val = Ptr.deref>(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } + } else if (T == PT_Float) { + auto &Val = Ptr.deref(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } + } +} + +template +static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr) { + assert(needsAlloc()); + auto &Val = Ptr.deref(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } +} + +static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) { + if (const Record *R = Ptr.getRecord()) { + for (const Record::Field &Fi : R->fields()) { + if (Fi.Desc->isPrimitive()) { + TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), { + copyPrimitiveMemory(S, Ptr.atField(Fi.Offset)); + }); + copyPrimitiveMemory(S, Ptr.atField(Fi.Offset), Fi.Desc->getPrimType()); + } else + finishGlobalRecurse(S, Ptr.atField(Fi.Offset)); + } + return; + } + + if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) { + unsigned NumElems = D->getNumElems(); + if (NumElems == 0) + return; + + if (D->isPrimitiveArray()) { + PrimType PT = D->getPrimType(); + if (!needsAlloc(PT)) + return; + assert(NumElems >= 1); + const Pointer EP = Ptr.atIndex(0); + bool AllSingleWord = true; + TYPE_SWITCH_ALLOC(PT, { + if (!EP.deref().singleWord()) { + copyPrimitiveMemory(S, EP); + AllSingleWord = false; + } + }); + if (AllSingleWord) + return; + for (unsigned I = 1; I != D->getNumElems(); ++I) { + const Pointer EP = Ptr.atIndex(I); + copyPrimitiveMemory(S, EP, PT); + } + } else { + assert(D->isCompositeArray()); + for (unsigned I = 0; I != D->getNumElems(); ++I) { + const Pointer EP = Ptr.atIndex(I).narrow(); + finishGlobalRecurse(S, EP); + } + } + } +} + +bool FinishInitGlobal(InterpState &S, CodePtr OpPC) { + const Pointer &Ptr = S.Stk.pop(); + + finishGlobalRecurse(S, Ptr); + if (Ptr.canBeInitialized()) { + Ptr.initialize(); + Ptr.activate(); + } + + return true; +} + // https://github.com/llvm/llvm-project/issues/102513 #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) #pragma optimize("", off) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index ae3d4a441a79..cb6eb1e76c43 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -189,7 +189,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, // C++11 [expr.shift]p1: Shift width must be less than the bit width of // the shifted type. - if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { + if (Bits > 1 && RHS >= Bits) { const Expr *E = S.Current->getExpr(OpPC); const APSInt Val = RHS.toAPSInt(); QualType Ty = E->getType(); @@ -370,6 +370,9 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS) { // Fast path - add the numbers with fixed width. T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(LHS.bitWidth()); + if (!OpFW(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -408,6 +411,7 @@ bool Add(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); const unsigned Bits = RHS.bitWidth() + 1; + return AddSubMulHelper(S, OpPC, Bits, LHS, RHS); } @@ -423,7 +427,7 @@ inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &LHS = S.Stk.pop(); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - Floating Result; + Floating Result = S.allocFloat(LHS.getSemantics()); auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result); S.Stk.push(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); @@ -434,6 +438,7 @@ bool Sub(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); const unsigned Bits = RHS.bitWidth() + 1; + return AddSubMulHelper(S, OpPC, Bits, LHS, RHS); } @@ -442,7 +447,7 @@ inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &LHS = S.Stk.pop(); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - Floating Result; + Floating Result = S.allocFloat(LHS.getSemantics()); auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result); S.Stk.push(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); @@ -453,6 +458,7 @@ bool Mul(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); const unsigned Bits = RHS.bitWidth() * 2; + return AddSubMulHelper(S, OpPC, Bits, LHS, RHS); } @@ -461,8 +467,10 @@ inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &LHS = S.Stk.pop(); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - Floating Result; + Floating Result = S.allocFloat(LHS.getSemantics()); + auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result); + S.Stk.push(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); } @@ -484,9 +492,14 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { HandleComplexComplexMul(A, B, C, D, ResR, ResI); // Copy into the result. - Result.atIndex(0).deref() = Floating(ResR); + Floating RA = S.allocFloat(A.getSemantics()); + RA.copy(ResR); + Result.atIndex(0).deref() = RA; // Floating(ResR); Result.atIndex(0).initialize(); - Result.atIndex(1).deref() = Floating(ResI); + + Floating RI = S.allocFloat(A.getSemantics()); + RI.copy(ResI); + Result.atIndex(1).deref() = RI; // Floating(ResI); Result.atIndex(1).initialize(); Result.initialize(); } else { @@ -539,10 +552,20 @@ inline bool Divc(InterpState &S, CodePtr OpPC) { HandleComplexComplexDiv(A, B, C, D, ResR, ResI); // Copy into the result. - Result.atIndex(0).deref() = Floating(ResR); + // Result.atIndex(0).deref() = Floating(ResR); + // Result.atIndex(0).initialize(); + // Result.atIndex(1).deref() = Floating(ResI); + // Result.atIndex(1).initialize(); + + Floating RA = S.allocFloat(A.getSemantics()); + RA.copy(ResR); + Result.atIndex(0).deref() = RA; // Floating(ResR); Result.atIndex(0).initialize(); - Result.atIndex(1).deref() = Floating(ResI); - Result.atIndex(1).initialize(); + + Floating RI = S.allocFloat(A.getSemantics()); + RI.copy(ResI); + Result.atIndex(1).deref() = RI; // Floating(ResI); + Result.initialize(); } else { // Integer element type. @@ -608,9 +631,12 @@ template ::T> bool BitAnd(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); - unsigned Bits = RHS.bitWidth(); + T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Bits); + if (!T::bitAnd(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -625,9 +651,12 @@ template ::T> bool BitOr(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); - unsigned Bits = RHS.bitWidth(); + T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Bits); + if (!T::bitOr(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -644,7 +673,11 @@ bool BitXor(InterpState &S, CodePtr OpPC) { const T &LHS = S.Stk.pop(); unsigned Bits = RHS.bitWidth(); + T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Bits); + if (!T::bitXor(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -659,12 +692,15 @@ template ::T> bool Rem(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); + const unsigned Bits = RHS.bitWidth() * 2; if (!CheckDivRem(S, OpPC, LHS, RHS)) return false; - const unsigned Bits = RHS.bitWidth() * 2; T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(LHS.bitWidth()); + if (!T::rem(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -679,12 +715,15 @@ template ::T> bool Div(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop(); const T &LHS = S.Stk.pop(); + const unsigned Bits = RHS.bitWidth() * 2; if (!CheckDivRem(S, OpPC, LHS, RHS)) return false; - const unsigned Bits = RHS.bitWidth() * 2; T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(LHS.bitWidth()); + if (!T::div(LHS, RHS, Bits, &Result)) { S.Stk.push(Result); return true; @@ -707,8 +746,10 @@ inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { return false; FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - Floating Result; + + Floating Result = S.allocFloat(LHS.getSemantics()); auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result); + S.Stk.push(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); } @@ -730,31 +771,44 @@ inline bool Inv(InterpState &S, CodePtr OpPC) { template ::T> bool Neg(InterpState &S, CodePtr OpPC) { const T &Value = S.Stk.pop(); - T Result; - if (!T::neg(Value, &Result)) { + if constexpr (std::is_same_v) { + T Result = S.allocFloat(Value.getSemantics()); + + if (!T::neg(Value, &Result)) { + S.Stk.push(Result); + return true; + } + return false; + } else { + T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Value.bitWidth()); + + if (!T::neg(Value, &Result)) { + S.Stk.push(Result); + return true; + } + + assert(isIntegralType(Name) && + "don't expect other types to fail at constexpr negation"); S.Stk.push(Result); - return true; + + APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); + if (S.checkingForUndefinedBehavior()) { + const Expr *E = S.Current->getExpr(OpPC); + QualType Type = E->getType(); + SmallString<32> Trunc; + NegatedValue.trunc(Result.bitWidth()) + .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, + /*UpperCase=*/true, /*InsertSeparators=*/true); + S.report(E->getExprLoc(), diag::warn_integer_constant_overflow) + << Trunc << Type << E->getSourceRange(); + return true; + } + + return handleOverflow(S, OpPC, NegatedValue); } - - assert(isIntegralType(Name) && - "don't expect other types to fail at constexpr negation"); - S.Stk.push(Result); - - APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); - if (S.checkingForUndefinedBehavior()) { - const Expr *E = S.Current->getExpr(OpPC); - QualType Type = E->getType(); - SmallString<32> Trunc; - NegatedValue.trunc(Result.bitWidth()) - .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, - /*UpperCase=*/true, /*InsertSeparators=*/true); - S.report(E->getExprLoc(), diag::warn_integer_constant_overflow) - << Trunc << Type << E->getSourceRange(); - return true; - } - - return handleOverflow(S, OpPC, NegatedValue); } enum class PushVal : bool { @@ -783,6 +837,8 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const T &Value = Ptr.deref(); T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Value.bitWidth()); if constexpr (DoPush == PushVal::Yes) S.Stk.push(Value); @@ -890,7 +946,6 @@ bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) { const Pointer &Ptr = S.Stk.peek(); if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; - return IncDecHelper(S, OpPC, Ptr, CanOverflow); } @@ -898,7 +953,7 @@ template bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI) { Floating Value = Ptr.deref(); - Floating Result; + Floating Result = S.allocFloat(Value.getSemantics()); if constexpr (DoPush == PushVal::Yes) S.Stk.push(Value); @@ -952,12 +1007,15 @@ inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) { template ::T> bool Comp(InterpState &S, CodePtr OpPC) { const T &Val = S.Stk.pop(); + T Result; + if constexpr (needsAlloc()) + Result = S.allocAP(Val.bitWidth()); + if (!T::comp(Val, &Result)) { S.Stk.push(Result); return true; } - return false; } @@ -1325,10 +1383,23 @@ bool Flip(InterpState &S, CodePtr OpPC) { template ::T> bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { + if constexpr (needsAlloc()) { + T Result = S.allocAP(Arg.bitWidth()); + Result.copy(Arg.toAPSInt()); + S.Stk.push(Result); + return true; + } S.Stk.push(Arg); return true; } +inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) { + Floating Result = S.allocFloat(F.getSemantics()); + Result.copy(F.getAPFloat()); + S.Stk.push(Result); + return true; +} + //===----------------------------------------------------------------------===// // Get/Set Local/Param/Global/This //===----------------------------------------------------------------------===// @@ -1483,7 +1554,24 @@ bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { template ::T> bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &P = S.P.getGlobal(I); + P.deref() = S.Stk.pop(); + + if constexpr (std::is_same_v) { + auto &Val = P.deref(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } + + } else if constexpr (needsAlloc()) { + auto &Val = P.deref(); + if (!Val.singleWord()) { + uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()]; + Val.take(NewMemory); + } + } + P.initialize(); return true; } @@ -1585,7 +1673,22 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { assert(F->isBitField()); const T &Value = S.Stk.pop(); const Pointer &Field = S.Stk.peek().atField(F->Offset); - Field.deref() = Value.truncate(F->Decl->getBitWidthValue()); + + if constexpr (needsAlloc()) { + T Result = S.allocAP(Value.bitWidth()); + if (T::isSigned()) + Result.copy(Value.toAPSInt() + .trunc(F->Decl->getBitWidthValue()) + .sextOrTrunc(Value.bitWidth())); + else + Result.copy(Value.toAPSInt() + .trunc(F->Decl->getBitWidthValue()) + .zextOrTrunc(Value.bitWidth())); + + Field.deref() = Result; + } else { + Field.deref() = Value.truncate(F->Decl->getBitWidthValue()); + } Field.activate(); Field.initialize(); return true; @@ -1765,6 +1868,8 @@ inline bool FinishInit(InterpState &S, CodePtr OpPC) { return true; } +bool FinishInitGlobal(InterpState &S, CodePtr OpPC); + inline bool Dump(InterpState &S, CodePtr OpPC) { S.Stk.dump(); return true; @@ -2271,7 +2376,8 @@ template bool Cast(InterpState &S, CodePtr OpPC) { inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM) { Floating F = S.Stk.pop(); - Floating Result = F.toSemantics(Sem, RM); + Floating Result = S.allocFloat(*Sem); + F.toSemantics(Sem, RM, &Result); S.Stk.push(Result); return true; } @@ -2295,15 +2401,25 @@ inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) { /// to know what bitwidth the result should be. template ::T> bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { - S.Stk.push>( - IntegralAP::from(S.Stk.pop(), BitWidth)); + auto Result = S.allocAP>(BitWidth); + // Copy data. + { + APInt Source = S.Stk.pop().toAPSInt().extOrTrunc(BitWidth); + Result.copy(Source); + } + S.Stk.push>(Result); return true; } template ::T> bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { - S.Stk.push>( - IntegralAP::from(S.Stk.pop(), BitWidth)); + auto Result = S.allocAP>(BitWidth); + // Copy data. + { + APInt Source = S.Stk.pop().toAPSInt().extOrTrunc(BitWidth); + Result.copy(Source); + } + S.Stk.push>(Result); return true; } @@ -2312,11 +2428,11 @@ bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI) { const T &From = S.Stk.pop(); APSInt FromAP = From.toAPSInt(); - Floating Result; FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); + Floating Result = S.allocFloat(*Sem); auto Status = - Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result); + Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result); S.Stk.push(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); @@ -2365,7 +2481,12 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, return handleOverflow(S, OpPC, F.getAPFloat()); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - S.Stk.push>(IntegralAP(Result)); + + auto ResultAP = S.allocAP>(BitWidth); + ResultAP.copy(Result); + + S.Stk.push>(ResultAP); + return CheckFloatResult(S, OpPC, F, Status, FPO); } @@ -2381,7 +2502,12 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, return handleOverflow(S, OpPC, F.getAPFloat()); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - S.Stk.push>(IntegralAP(Result)); + + auto ResultAP = S.allocAP>(BitWidth); + ResultAP.copy(Result); + + S.Stk.push>(ResultAP); + return CheckFloatResult(S, OpPC, F, Status, FPO); } @@ -2441,8 +2567,9 @@ static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem) { const auto &Fixed = S.Stk.pop(); - - S.Stk.push(Fixed.toFloat(Sem)); + Floating Result = S.allocFloat(*Sem); + Result.copy(Fixed.toFloat(Sem)); + S.Stk.push(Result); return true; } @@ -2506,12 +2633,18 @@ bool Zero(InterpState &S, CodePtr OpPC) { } static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { - S.Stk.push>(IntegralAP::zero(BitWidth)); + auto Result = S.allocAP>(BitWidth); + if (!Result.singleWord()) + std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t)); + S.Stk.push>(Result); return true; } static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { - S.Stk.push>(IntegralAP::zero(BitWidth)); + auto Result = S.allocAP>(BitWidth); + if (!Result.singleWord()) + std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t)); + S.Stk.push>(Result); return true; } @@ -2578,7 +2711,9 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) { //===----------------------------------------------------------------------===// template -inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { +inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS, + LT *Result) { + static_assert(!needsAlloc()); const unsigned Bits = LHS.bitWidth(); // OpenCL 6.3j: shift values are effectively % word size of LHS. @@ -2596,7 +2731,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { RHS = -RHS; return DoShift( - S, OpPC, LHS, RHS); + S, OpPC, LHS, RHS, Result); } if (!CheckShift(S, OpPC, LHS, RHS, Bits)) @@ -2635,7 +2770,10 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), LT::AsUnsigned::from(RHS, Bits), Bits, &R); } - } else { + S.Stk.push(LT::from(R)); + return true; + } + // Right shift. if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) == ComparisonCategoryResult::Greater) { @@ -2646,12 +2784,56 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A); R = LT::AsUnsigned::from(A); } - } S.Stk.push(LT::from(R)); return true; } +/// A version of DoShift that works on IntegralAP. +template +inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS, + APSInt RHS, LT *Result) { + const unsigned Bits = LHS.getBitWidth(); + + // OpenCL 6.3j: shift values are effectively % word size of LHS. + if (S.getLangOpts().OpenCL) + RHS &= + APSInt(llvm::APInt(RHS.getBitWidth(), static_cast(Bits - 1)), + RHS.isUnsigned()); + + if (RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such a + // shift is not a constant expression. + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt(); + if (!S.noteUndefinedBehavior()) + return false; + return DoShiftAP( + S, OpPC, LHS, -RHS, Result); + } + + if (!CheckShift(S, OpPC, static_cast(LHS), static_cast(RHS), + Bits)) + return false; + + unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1); + if constexpr (Dir == ShiftDir::Left) { + if constexpr (needsAlloc()) + Result->copy(LHS << SA); + else + *Result = LT(LHS << SA); + } else { + if constexpr (needsAlloc()) + Result->copy(LHS >> SA); + else + *Result = LT(LHS >> SA); + } + + S.Stk.push(*Result); + return true; +} + template inline bool Shr(InterpState &S, CodePtr OpPC) { using LT = typename PrimConv::T; @@ -2659,7 +2841,16 @@ inline bool Shr(InterpState &S, CodePtr OpPC) { auto RHS = S.Stk.pop(); auto LHS = S.Stk.pop(); - return DoShift(S, OpPC, LHS, RHS); + if constexpr (needsAlloc() || needsAlloc()) { + LT Result; + if constexpr (needsAlloc()) + Result = S.allocAP(LHS.bitWidth()); + return DoShiftAP(S, OpPC, LHS.toAPSInt(), + RHS.toAPSInt(), &Result); + } else { + LT Result; + return DoShift(S, OpPC, LHS, RHS, &Result); + } } template @@ -2669,7 +2860,16 @@ inline bool Shl(InterpState &S, CodePtr OpPC) { auto RHS = S.Stk.pop(); auto LHS = S.Stk.pop(); - return DoShift(S, OpPC, LHS, RHS); + if constexpr (needsAlloc() || needsAlloc()) { + LT Result; + if constexpr (needsAlloc()) + Result = S.allocAP(LHS.bitWidth()); + return DoShiftAP(S, OpPC, LHS.toAPSInt(), + RHS.toAPSInt(), &Result); + } else { + LT Result; + return DoShift(S, OpPC, LHS, RHS, &Result); + } } static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) { @@ -3252,7 +3452,15 @@ inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, if constexpr (std::is_same_v) { assert(Sem); - S.Stk.push(T::bitcastFromMemory(Buff.data(), *Sem)); + Floating Result = S.allocFloat(*Sem); + Floating::bitcastFromMemory(Buff.data(), *Sem, &Result); + S.Stk.push(Result); + + // S.Stk.push(T::bitcastFromMemory(Buff.data(), *Sem)); + } else if constexpr (needsAlloc()) { + T Result = S.allocAP(ResultBitWidth); + T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result); + S.Stk.push(Result); } else { assert(!Sem); S.Stk.push(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); @@ -3310,7 +3518,11 @@ template inline T ReadArg(InterpState &S, CodePtr &OpPC) { } template <> inline Floating ReadArg(InterpState &S, CodePtr &OpPC) { - Floating F = Floating::deserialize(*OpPC); + auto &Semantics = + llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC)); + + auto F = S.allocFloat(Semantics); + Floating::deserialize(*OpPC, &F); OpPC += align(F.bytesToSerialize()); return F; } @@ -3318,17 +3530,25 @@ template <> inline Floating ReadArg(InterpState &S, CodePtr &OpPC) { template <> inline IntegralAP ReadArg>(InterpState &S, CodePtr &OpPC) { - IntegralAP I = IntegralAP::deserialize(*OpPC); - OpPC += align(I.bytesToSerialize()); - return I; + uint32_t BitWidth = IntegralAP::deserializeSize(*OpPC); + auto Result = S.allocAP>(BitWidth); + assert(Result.bitWidth() == BitWidth); + + IntegralAP::deserialize(*OpPC, &Result); + OpPC += align(Result.bytesToSerialize()); + return Result; } template <> inline IntegralAP ReadArg>(InterpState &S, CodePtr &OpPC) { - IntegralAP I = IntegralAP::deserialize(*OpPC); - OpPC += align(I.bytesToSerialize()); - return I; + uint32_t BitWidth = IntegralAP::deserializeSize(*OpPC); + auto Result = S.allocAP>(BitWidth); + assert(Result.bitWidth() == BitWidth); + + IntegralAP::deserialize(*OpPC, &Result); + OpPC += align(Result.bytesToSerialize()); + return Result; } template <> diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index 9ef44cd29ff8..f60307870ffc 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.cpp +++ b/clang/lib/AST/ByteCode/InterpBlock.cpp @@ -69,20 +69,26 @@ void Block::cleanup() { void Block::replacePointer(Pointer *Old, Pointer *New) { assert(Old); assert(New); + assert(Old != New); if (IsStatic) { assert(!Pointers); return; } - #ifndef NDEBUG assert(hasPointer(Old)); #endif - removePointer(Old); - addPointer(New); + if (Old->Prev) + Old->Prev->Next = New; + if (Old->Next) + Old->Next->Prev = New; + New->Prev = Old->Prev; + New->Next = Old->Next; + if (Pointers == Old) + Pointers = New; Old->PointeeStorage.BS.Pointee = nullptr; - + New->PointeeStorage.BS.Pointee = this; #ifndef NDEBUG assert(!hasPointer(Old)); assert(hasPointer(New)); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 5fc503456959..ea96e21ea944 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -57,6 +57,21 @@ static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) { assert(T); unsigned BitWidth = S.getASTContext().getTypeSize(QT); + + if (T == PT_IntAPS) { + auto Result = S.allocAP>(BitWidth); + Result.copy(Val); + S.Stk.push>(Result); + return; + } + + if (T == PT_IntAP) { + auto Result = S.allocAP>(BitWidth); + Result.copy(Val); + S.Stk.push>(Result); + return; + } + if (QT->isSignedIntegerOrEnumerationType()) { int64_t V = Val.getSExtValue(); INT_TYPE_SWITCH(*T, { S.Stk.push(T::from(V, BitWidth)); }); @@ -81,10 +96,21 @@ static void pushInteger(InterpState &S, T Val, QualType QT) { QT); } -static void assignInteger(const Pointer &Dest, PrimType ValueT, +static void assignInteger(InterpState &S, const Pointer &Dest, PrimType ValueT, const APSInt &Value) { - INT_TYPE_SWITCH_NO_BOOL( - ValueT, { Dest.deref() = T::from(static_cast(Value)); }); + + if (ValueT == PT_IntAPS) { + Dest.deref>() = + S.allocAP>(Value.getBitWidth()); + Dest.deref>().copy(Value); + } else if (ValueT == PT_IntAP) { + Dest.deref>() = + S.allocAP>(Value.getBitWidth()); + Dest.deref>().copy(Value); + } else { + INT_TYPE_SWITCH_NO_BOOL( + ValueT, { Dest.deref() = T::from(static_cast(Value)); }); + } } static QualType getElemType(const Pointer &P) { @@ -327,13 +353,13 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, S.getASTContext().getFloatTypeSemantics( Call->getDirectCallee()->getReturnType()); - Floating Result; + Floating Result = S.allocFloat(TargetSemantics); if (S.getASTContext().getTargetInfo().isNan2008()) { if (Signaling) - Result = Floating( + Result.copy( llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); else - Result = Floating( + Result.copy( llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); } else { // Prior to IEEE 754-2008, architectures were allowed to choose whether @@ -342,10 +368,10 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as // sNaN. This is now known as "legacy NaN" encoding. if (Signaling) - Result = Floating( + Result.copy( llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); else - Result = Floating( + Result.copy( llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); } @@ -360,7 +386,9 @@ static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, S.getASTContext().getFloatTypeSemantics( Call->getDirectCallee()->getReturnType()); - S.Stk.push(Floating::getInf(TargetSemantics)); + Floating Result = S.allocFloat(TargetSemantics); + Result.copy(APFloat::getInf(TargetSemantics)); + S.Stk.push(Result); return true; } @@ -368,10 +396,12 @@ static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { const Floating &Arg2 = S.Stk.pop(); const Floating &Arg1 = S.Stk.pop(); + Floating Result = S.allocFloat(Arg1.getSemantics()); APFloat Copy = Arg1.getAPFloat(); Copy.copySign(Arg2.getAPFloat()); - S.Stk.push(Floating(Copy)); + Result.copy(Copy); + S.Stk.push(Result); return true; } @@ -380,11 +410,13 @@ static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool IsNumBuiltin) { const Floating &RHS = S.Stk.pop(); const Floating &LHS = S.Stk.pop(); + Floating Result = S.allocFloat(LHS.getSemantics()); if (IsNumBuiltin) - S.Stk.push(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat())); + Result.copy(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat())); else - S.Stk.push(minnum(LHS.getAPFloat(), RHS.getAPFloat())); + Result.copy(minnum(LHS.getAPFloat(), RHS.getAPFloat())); + S.Stk.push(Result); return true; } @@ -392,11 +424,13 @@ static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool IsNumBuiltin) { const Floating &RHS = S.Stk.pop(); const Floating &LHS = S.Stk.pop(); + Floating Result = S.allocFloat(LHS.getSemantics()); if (IsNumBuiltin) - S.Stk.push(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat())); + Result.copy(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat())); else - S.Stk.push(maxnum(LHS.getAPFloat(), RHS.getAPFloat())); + Result.copy(maxnum(LHS.getAPFloat(), RHS.getAPFloat())); + S.Stk.push(Result); return true; } @@ -571,8 +605,16 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { const Floating &Val = S.Stk.pop(); + APFloat F = Val.getAPFloat(); + if (!F.isNegative()) { + S.Stk.push(Val); + return true; + } - S.Stk.push(Floating::abs(Val)); + Floating Result = S.allocFloat(Val.getSemantics()); + F.changeSign(); + Result.copy(F); + S.Stk.push(Result); return true; } @@ -818,7 +860,7 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC, } // Write Result to ResultPtr and put Overflow on the stack. - assignInteger(ResultPtr, ResultT, Result); + assignInteger(S, ResultPtr, ResultT, Result); ResultPtr.initialize(); assert(Call->getDirectCallee()->getReturnType()->isBooleanType()); S.Stk.push(Overflow); @@ -871,7 +913,7 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType(); PrimType CarryOutT = *S.getContext().classify(CarryOutType); - assignInteger(CarryOutPtr, CarryOutT, CarryOut); + assignInteger(S, CarryOutPtr, CarryOutT, CarryOut); CarryOutPtr.initialize(); assert(Call->getType() == Call->getArg(0)->getType()); @@ -1383,7 +1425,7 @@ static bool interp__builtin_ia32_addcarry_subborrow(InterpState &S, QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType(); PrimType CarryOutT = *S.getContext().classify(CarryOutType); - assignInteger(CarryOutPtr, CarryOutT, APSInt(Result, true)); + assignInteger(S, CarryOutPtr, CarryOutT, APSInt(Result, true)); pushInteger(S, CarryOut, Call->getType()); @@ -1423,7 +1465,6 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, // Walk up the call stack to find the appropriate caller and get the // element type from it. auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate"); - APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0))); if (ElemType.isNull()) { S.FFDiag(Call, S.getLangOpts().CPlusPlus20 @@ -1439,6 +1480,25 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, return false; } + // We only care about the first parameter (the size), so discard all the + // others. + { + unsigned NumArgs = Call->getNumArgs(); + assert(NumArgs >= 1); + + // The std::nothrow_t arg never gets put on the stack. + if (Call->getArg(NumArgs - 1)->getType()->isNothrowT()) + --NumArgs; + auto Args = llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()); + // First arg is needed. + Args = Args.drop_front(); + + // Discard the rest. + for (const Expr *Arg : Args) + discard(S.Stk, *S.getContext().classify(Arg)); + } + + APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0))); CharUnits ElemSize = S.getASTContext().getTypeSizeInChars(ElemType); assert(!ElemSize.isZero()); // Divide the number of bytes by sizeof(ElemType), so we get the number of diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 239b3104e89f..2569cac018b3 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -402,7 +402,9 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, if (llvm::sys::IsBigEndianHost) swapBytes(M.get(), NumBits.roundToBytes()); - P.deref() = Floating::bitcastFromMemory(M.get(), Semantics); + Floating R = S.allocFloat(Semantics); + Floating::bitcastFromMemory(M.get(), Semantics, &R); + P.deref() = R; P.initialize(); return true; } diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index b183335dd588..6b748d62b83b 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -19,9 +19,7 @@ using namespace clang; using namespace clang::interp; -InterpStack::~InterpStack() { clear(); } - -void InterpStack::clear() { +InterpStack::~InterpStack() { if (Chunk && Chunk->Next) std::free(Chunk->Next); if (Chunk) @@ -33,6 +31,21 @@ void InterpStack::clear() { #endif } +// We keep the last chunk around to reuse. +void InterpStack::clear() { + if (!Chunk) + return; + + if (Chunk->Next) + std::free(Chunk->Next); + + assert(Chunk); + StackSize = 0; +#ifndef NDEBUG + ItemTypes.clear(); +#endif +} + void InterpStack::clearTo(size_t NewSize) { assert(NewSize <= size()); size_t ToShrink = size() - NewSize; diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index e8dc6f0483d6..08765561985e 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -15,6 +15,7 @@ #include "Context.h" #include "DynamicAllocator.h" +#include "Floating.h" #include "Function.h" #include "InterpFrame.h" #include "InterpStack.h" @@ -126,6 +127,33 @@ public: StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const; + void *allocate(size_t Size, unsigned Align = 8) const { + return Allocator.Allocate(Size, Align); + } + template T *allocate(size_t Num = 1) const { + return static_cast(allocate(Num * sizeof(T), alignof(T))); + } + + template T allocAP(unsigned BitWidth) { + unsigned NumWords = APInt::getNumWords(BitWidth); + if (NumWords == 1) + return T(BitWidth); + uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t)); + // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug + return T(Mem, BitWidth); + } + + Floating allocFloat(const llvm::fltSemantics &Sem) { + if (Floating::singleWord(Sem)) + return Floating(llvm::APFloatBase::SemanticsToEnum(Sem)); + + unsigned NumWords = + APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)); + uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t)); + // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug + return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem)); + } + private: friend class EvaluationResult; friend class InterpStateCCOverride; @@ -161,6 +189,8 @@ public: llvm::SmallVector< std::pair> SeenGlobalTemporaries; + + mutable llvm::BumpPtrAllocator Allocator; }; class InterpStateCCOverride final { diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index c76ac5f8ae86..57e01f7bd9da 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -48,6 +48,7 @@ def ArgUint64 : ArgType { let Name = "uint64_t"; } def ArgIntAP : ArgType { let Name = "IntegralAP"; let AsRef = true; } def ArgIntAPS : ArgType { let Name = "IntegralAP"; let AsRef = true; } def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; } + def ArgBool : ArgType { let Name = "bool"; } def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; } @@ -88,6 +89,9 @@ def IntegerAndFixedTypeClass : TypeClass { Uint32, Sint64, Uint64, IntAP, IntAPS, FixedPoint]; } +def IntegralTypeClass : TypeClass { + let Types = !listconcat(IntegerTypeClass.Types, [Bool]); +} def FixedSizeIntegralTypeClass : TypeClass { let Types = [Sint8, Uint8, Sint16, Uint16, Sint32, Uint32, Sint64, Uint64, Bool]; @@ -265,12 +269,13 @@ def ConstSint32 : ConstOpcode; def ConstUint32 : ConstOpcode; def ConstSint64 : ConstOpcode; def ConstUint64 : ConstOpcode; -def ConstFloat : ConstOpcode; -def constIntAP : ConstOpcode; -def constIntAPS : ConstOpcode; +def ConstIntAP : ConstOpcode; +def ConstIntAPS : ConstOpcode; def ConstBool : ConstOpcode; def ConstFixedPoint : ConstOpcode; +def ConstFloat : Opcode { let Args = [ArgFloat]; } + // [] -> [Integer] def Zero : Opcode { let Types = [FixedSizeIntegralTypeClass]; @@ -328,6 +333,7 @@ def GetMemberPtrBasePop : Opcode { def FinishInitPop : Opcode; def FinishInit : Opcode; +def FinishInitGlobal : Opcode; def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; } @@ -389,7 +395,7 @@ class AccessOpcode : Opcode { } class BitFieldOpcode : Opcode { - let Types = [AluTypeClass]; + let Types = [IntegralTypeClass]; let Args = [ArgRecordField]; let HasGroup = 1; } diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 50453c72c582..f0b0384f32ac 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -114,7 +114,6 @@ void Pointer::operator=(Pointer &&P) { } if (Block *Pointee = PointeeStorage.BS.Pointee) { - assert(P.block() != this->block()); Pointee->removePointer(this); PointeeStorage.BS.Pointee = nullptr; Pointee->cleanup(); diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index 6152fbfbe3a7..a156cccbb3c1 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -76,6 +76,13 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, } constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; } +template constexpr bool needsAlloc() { + return std::is_same_v> || + std::is_same_v> || std::is_same_v; +} +constexpr bool needsAlloc(PrimType T) { + return T == PT_IntAP || T == PT_IntAPS || T == PT_Float; +} /// Mapping from primitive types to their representation. template struct PrimConv; @@ -209,6 +216,16 @@ static inline bool aligned(const void *P) { } \ } while (0) +#define TYPE_SWITCH_ALLOC(Expr, B) \ + do { \ + switch (Expr) { \ + TYPE_SWITCH_CASE(PT_Float, B) \ + TYPE_SWITCH_CASE(PT_IntAP, B) \ + TYPE_SWITCH_CASE(PT_IntAPS, B) \ + default:; \ + } \ + } while (0) + #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ do { \ switch (Expr) { \ diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index 23ba1bbd193b..5d9c42244749 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -132,6 +132,14 @@ public: bool IsMutable = false, bool IsVolatile = false, const Expr *Init = nullptr); + void *Allocate(size_t Size, unsigned Align = 8) const { + return Allocator.Allocate(Size, Align); + } + template T *Allocate(size_t Num = 1) const { + return static_cast(Allocate(Num * sizeof(T), alignof(T))); + } + void Deallocate(void *Ptr) const {} + /// Context to manage declaration lifetimes. class DeclScope { public: @@ -204,7 +212,7 @@ private: }; /// Allocator for globals. - PoolAllocTy Allocator; + mutable PoolAllocTy Allocator; /// Global objects. std::vector Globals; @@ -238,4 +246,18 @@ public: } // namespace interp } // namespace clang +inline void *operator new(size_t Bytes, const clang::interp::Program &C, + size_t Alignment = 8) { + return C.Allocate(Bytes, Alignment); +} + +inline void operator delete(void *Ptr, const clang::interp::Program &C, + size_t) { + C.Deallocate(Ptr); +} +inline void *operator new[](size_t Bytes, const clang::interp::Program &C, + size_t Alignment = 8) { + return C.Allocate(Bytes, Alignment); +} + #endif diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 0e75a44d6996..751c891f1e6b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2110,7 +2110,7 @@ void QualifierInfo::setTemplateParameterListsInfo( if (!TPLists.empty()) { TemplParamLists = new (Context) TemplateParameterList *[TPLists.size()]; NumTemplParamLists = TPLists.size(); - std::copy(TPLists.begin(), TPLists.end(), TemplParamLists); + llvm::copy(TPLists, TemplParamLists); } } @@ -2452,6 +2452,30 @@ VarDecl *VarDecl::getInitializingDeclaration() { return Def; } +bool VarDecl::hasInitWithSideEffects() const { + if (!hasInit()) + return false; + + // Check if we can get the initializer without deserializing + const Expr *E = nullptr; + if (auto *S = dyn_cast(Init)) { + E = cast(S); + } else { + E = cast_or_null(getEvaluatedStmt()->Value.getWithoutDeserializing()); + } + + if (E) + return E->HasSideEffects(getASTContext()) && + // We can get a value-dependent initializer during error recovery. + (E->isValueDependent() || !evaluateValue()); + + assert(getEvaluatedStmt()->Value.isOffset()); + // ASTReader tracks this without having to deserialize the initializer + if (auto Source = getASTContext().getExternalSource()) + return Source->hasInitializerWithSideEffects(this); + return false; +} + bool VarDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; @@ -3774,7 +3798,7 @@ void FunctionDecl::setParams(ASTContext &C, // Zero params -> null pointer. if (!NewParamInfo.empty()) { ParamInfo = new (C) ParmVarDecl*[NewParamInfo.size()]; - std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); + llvm::copy(NewParamInfo, ParamInfo); } } @@ -5361,7 +5385,7 @@ void BlockDecl::setParams(ArrayRef NewParamInfo) { if (!NewParamInfo.empty()) { NumParams = NewParamInfo.size(); ParamInfo = new (getASTContext()) ParmVarDecl*[NewParamInfo.size()]; - std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); + llvm::copy(NewParamInfo, ParamInfo); } } @@ -5418,8 +5442,8 @@ PragmaCommentDecl *PragmaCommentDecl::Create(const ASTContext &C, PragmaCommentDecl *PCD = new (C, DC, additionalSizeToAlloc(Arg.size() + 1)) PragmaCommentDecl(DC, CommentLoc, CommentKind); - memcpy(PCD->getTrailingObjects(), Arg.data(), Arg.size()); - PCD->getTrailingObjects()[Arg.size()] = '\0'; + llvm::copy(Arg, PCD->getTrailingObjects()); + PCD->getTrailingObjects()[Arg.size()] = '\0'; return PCD; } @@ -5440,9 +5464,9 @@ PragmaDetectMismatchDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, PragmaDetectMismatchDecl *PDMD = new (C, DC, additionalSizeToAlloc(ValueStart + Value.size() + 1)) PragmaDetectMismatchDecl(DC, Loc, ValueStart); - memcpy(PDMD->getTrailingObjects(), Name.data(), Name.size()); + llvm::copy(Name, PDMD->getTrailingObjects()); PDMD->getTrailingObjects()[Name.size()] = '\0'; - memcpy(PDMD->getTrailingObjects() + ValueStart, Value.data(), Value.size()); + llvm::copy(Value, PDMD->getTrailingObjects() + ValueStart); PDMD->getTrailingObjects()[ValueStart + Value.size()] = '\0'; return PDMD; } @@ -5482,9 +5506,9 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { void LabelDecl::setMSAsmLabel(StringRef Name) { char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; - memcpy(Buffer, Name.data(), Name.size()); - Buffer[Name.size()] = '\0'; - MSAsmName = Buffer; +llvm::copy(Name, Buffer); +Buffer[Name.size()] = '\0'; +MSAsmName = Buffer; } void ValueDecl::anchor() {} @@ -5867,7 +5891,7 @@ void HLSLBufferDecl::setDefaultBufferDecls(ArrayRef Decls) { // allocate array for default decls with ASTContext allocator Decl **DeclsArray = new (getASTContext()) Decl *[Decls.size()]; - std::copy(Decls.begin(), Decls.end(), DeclsArray); + llvm::copy(Decls, DeclsArray); DefaultBufferDecls = ArrayRef(DeclsArray, Decls.size()); } @@ -5908,8 +5932,7 @@ HLSLRootSignatureDecl *HLSLRootSignatureDecl::Create( RootElements.size())) HLSLRootSignatureDecl(DC, Loc, ID, RootElements.size()); auto *StoredElems = RSDecl->getElems(); - std::uninitialized_copy(RootElements.begin(), RootElements.end(), - StoredElems); + llvm::uninitialized_copy(RootElements, StoredElems); return RSDecl; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 245be84b6ff5..fb1ab9725200 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1142,6 +1142,12 @@ bool Decl::isInExportDeclContext() const { return isa_and_nonnull(DC); } +bool Decl::isModuleLocal() const { + auto *M = getOwningModule(); + return M && M->isNamedModule() && + getModuleOwnershipKind() == ModuleOwnershipKind::ReachableWhenImported; +} + bool Decl::isInAnotherModuleUnit() const { auto *M = getOwningModule(); diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 596262e21798..5cf0e9a7b259 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -1512,7 +1512,7 @@ ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc, ArrayRef typeParams, SourceLocation rAngleLoc) : Brackets(lAngleLoc, rAngleLoc), NumParams(typeParams.size()) { - std::copy(typeParams.begin(), typeParams.end(), begin()); + llvm::copy(typeParams, begin()); } ObjCTypeParamList *ObjCTypeParamList::create( diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 548a6e5cd610..abcbf967d5e5 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -670,7 +670,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(Name, /*SpecifiedArgs=*/TemplateArgs, - /*CanonicalArgs=*/std::nullopt); + /*CanonicalArgs=*/{}); return CommonPtr->InjectedClassNameType; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 007d820f42f7..d4fb9c213cbf 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1123,14 +1123,13 @@ unsigned StringLiteral::mapCharByteWidth(TargetInfo const &Target, StringLiteral::StringLiteral(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, - const SourceLocation *Loc, - unsigned NumConcatenated) + ArrayRef Locs) : Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary) { unsigned Length = Str.size(); StringLiteralBits.Kind = llvm::to_underlying(Kind); - StringLiteralBits.NumConcatenated = NumConcatenated; + StringLiteralBits.NumConcatenated = Locs.size(); if (Kind != StringLiteralKind::Unevaluated) { assert(Ctx.getAsConstantArrayType(Ty) && @@ -1169,11 +1168,10 @@ StringLiteral::StringLiteral(const ASTContext &Ctx, StringRef Str, // Initialize the trailing array of SourceLocation. // This is safe since SourceLocation is POD-like. - std::memcpy(getTrailingObjects(), Loc, - NumConcatenated * sizeof(SourceLocation)); + llvm::copy(Locs, getTrailingObjects()); // Initialize the trailing array of char holding the string data. - std::memcpy(getTrailingObjects(), Str.data(), Str.size()); + llvm::copy(Str, getTrailingObjects()); setDependence(ExprDependence::None); } @@ -1188,13 +1186,12 @@ StringLiteral::StringLiteral(EmptyShell Empty, unsigned NumConcatenated, StringLiteral *StringLiteral::Create(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, - QualType Ty, const SourceLocation *Loc, - unsigned NumConcatenated) { + QualType Ty, + ArrayRef Locs) { void *Mem = Ctx.Allocate(totalSizeToAlloc( - 1, NumConcatenated, Str.size()), + 1, Locs.size(), Str.size()), alignof(StringLiteral)); - return new (Mem) - StringLiteral(Ctx, Str, Kind, Pascal, Ty, Loc, NumConcatenated); + return new (Mem) StringLiteral(Ctx, Str, Kind, Pascal, Ty, Locs); } StringLiteral *StringLiteral::CreateEmpty(const ASTContext &Ctx, @@ -3621,7 +3618,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: case FunctionParmPackExprClass: - case TypoExprClass: case RecoveryExprClass: case CXXFoldExprClass: // Make a conservative assumption for dependent nodes. @@ -4429,7 +4425,7 @@ void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef Exprs) { this->ShuffleVectorExprBits.NumExprs = Exprs.size(); SubExprs = new (C) Stmt *[ShuffleVectorExprBits.NumExprs]; - memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size()); + llvm::copy(Exprs, SubExprs); } GenericSelectionExpr::GenericSelectionExpr( diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 77da667886fd..c75827e29c87 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -263,9 +263,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, getTrailingObjects()[arraySizeOffset()] = *ArraySize; if (Initializer) getTrailingObjects()[initExprOffset()] = Initializer; - for (unsigned I = 0; I != PlacementArgs.size(); ++I) - getTrailingObjects()[placementNewArgsOffset() + I] = - PlacementArgs[I]; + llvm::copy(PlacementArgs, + getTrailingObjects() + placementNewArgsOffset()); if (IsParenTypeId) getTrailingObjects()[0] = TypeIdParens; @@ -808,8 +807,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T, new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, RParenLoc, AngleBrackets); if (PathSize) - llvm::uninitialized_copy(*BasePath, - E->getTrailingObjects()); + llvm::uninitialized_copy(*BasePath, E->getTrailingObjects()); return E; } @@ -871,8 +869,7 @@ CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T, new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, RParenLoc, AngleBrackets); if (PathSize) - llvm::uninitialized_copy(*BasePath, - E->getTrailingObjects()); + llvm::uninitialized_copy(*BasePath, E->getTrailingObjects()); return E; } @@ -1211,10 +1208,8 @@ CXXConstructExpr::CXXConstructExpr( CXXConstructExprBits.Loc = Loc; Stmt **TrailingArgs = getTrailingArgs(); - for (unsigned I = 0, N = Args.size(); I != N; ++I) { - assert(Args[I] && "NULL argument in CXXConstructExpr!"); - TrailingArgs[I] = Args[I]; - } + llvm::copy(Args, TrailingArgs); + assert(llvm::all_of(Args, [](const Stmt *Arg) { return Arg != nullptr; })); // CXXTemporaryObjectExpr does this itself after setting its TypeSourceInfo. if (SC == CXXConstructExprClass) @@ -1475,8 +1470,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( RParenLoc(RParenLoc) { CXXUnresolvedConstructExprBits.NumArgs = Args.size(); auto **StoredArgs = getTrailingObjects(); - for (unsigned I = 0; I != Args.size(); ++I) - StoredArgs[I] = Args[I]; + llvm::copy(Args, StoredArgs); setDependence(computeDependence(this)); } @@ -1888,8 +1882,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, assert(Args.size() == TypeTraitExprBits.NumArgs && "TypeTraitExprBits.NumArgs overflow!"); auto **ToArgs = getTrailingObjects(); - for (unsigned I = 0, N = Args.size(); I != N; ++I) - ToArgs[I] = Args[I]; + llvm::copy(Args, ToArgs); setDependence(computeDependence(this)); diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 952cfb1b4777..822ace8ec4a8 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -131,7 +131,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: - case Expr::TypoExprClass: case Expr::DependentCoawaitExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index e6afcdd5dc3e..a2cf431a312a 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -144,10 +144,8 @@ RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, if (RequirementContainsError(R)) setDependence(getDependence() | ExprDependence::Error); } - std::copy(LocalParameters.begin(), LocalParameters.end(), - getTrailingObjects()); - std::copy(Requirements.begin(), Requirements.end(), - getTrailingObjects()); + llvm::copy(LocalParameters, getTrailingObjects()); + llvm::copy(Requirements, getTrailingObjects()); RequiresExprBits.IsSatisfied |= Dependent; // FIXME: move the computing dependency logic to ComputeDependence.h if (ContainsUnexpandedParameterPack) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f019812020a8..58b3dd10b5e1 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -17651,7 +17651,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CXXDeleteExprClass: case Expr::CXXPseudoDestructorExprClass: case Expr::UnresolvedLookupExprClass: - case Expr::TypoExprClass: case Expr::RecoveryExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: diff --git a/clang/lib/AST/ExprObjC.cpp b/clang/lib/AST/ExprObjC.cpp index 79b5db301d41..3df9c404b5ca 100644 --- a/clang/lib/AST/ExprObjC.cpp +++ b/clang/lib/AST/ExprObjC.cpp @@ -163,10 +163,8 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef Args, MyArgs[I] = Args[I]; SelLocsKind = SelLocsK; - if (!isImplicit()) { - if (SelLocsK == SelLoc_NonStandard) - std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); - } + if (!isImplicit() && SelLocsK == SelLoc_NonStandard) + llvm::copy(SelLocs, getStoredSelLocs()); } ObjCMessageExpr * diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index f35b00b7b68f..aaa605285c7f 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5165,7 +5165,6 @@ recurse: case Expr::ParenListExprClass: case Expr::MSPropertyRefExprClass: case Expr::MSPropertySubscriptExprClass: - case Expr::TypoExprClass: // This should no longer exist in the AST by now. case Expr::RecoveryExprClass: case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 0e5052b94416..8b1caa05eec3 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -370,26 +370,26 @@ OMPOrderedClause *OMPOrderedClause::CreateEmpty(const ASTContext &C, void OMPOrderedClause::setLoopNumIterations(unsigned NumLoop, Expr *NumIterations) { assert(NumLoop < NumberOfLoops && "out of loops number."); - getTrailingObjects()[NumLoop] = NumIterations; + getTrailingObjects()[NumLoop] = NumIterations; } ArrayRef OMPOrderedClause::getLoopNumIterations() const { - return getTrailingObjects(NumberOfLoops); + return getTrailingObjects(NumberOfLoops); } void OMPOrderedClause::setLoopCounter(unsigned NumLoop, Expr *Counter) { assert(NumLoop < NumberOfLoops && "out of loops number."); - getTrailingObjects()[NumberOfLoops + NumLoop] = Counter; + getTrailingObjects()[NumberOfLoops + NumLoop] = Counter; } Expr *OMPOrderedClause::getLoopCounter(unsigned NumLoop) { assert(NumLoop < NumberOfLoops && "out of loops number."); - return getTrailingObjects()[NumberOfLoops + NumLoop]; + return getTrailingObjects()[NumberOfLoops + NumLoop]; } const Expr *OMPOrderedClause::getLoopCounter(unsigned NumLoop) const { assert(NumLoop < NumberOfLoops && "out of loops number."); - return getTrailingObjects()[NumberOfLoops + NumLoop]; + return getTrailingObjects()[NumberOfLoops + NumLoop]; } OMPUpdateClause *OMPUpdateClause::Create(const ASTContext &C, @@ -428,7 +428,7 @@ OMPUpdateClause *OMPUpdateClause::CreateEmpty(const ASTContext &C, void OMPPrivateClause::setPrivateCopies(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), varlist_end()); + llvm::copy(VL, varlist_end()); } OMPPrivateClause * @@ -453,13 +453,13 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, void OMPFirstprivateClause::setPrivateCopies(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), varlist_end()); + llvm::copy(VL, varlist_end()); } void OMPFirstprivateClause::setInits(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of inits is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), getPrivateCopies().end()); + llvm::copy(VL, getPrivateCopies().end()); } OMPFirstprivateClause * @@ -486,29 +486,28 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C, void OMPLastprivateClause::setPrivateCopies(ArrayRef PrivateCopies) { assert(PrivateCopies.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(PrivateCopies.begin(), PrivateCopies.end(), varlist_end()); + llvm::copy(PrivateCopies, varlist_end()); } void OMPLastprivateClause::setSourceExprs(ArrayRef SrcExprs) { assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " "not the same as the " "preallocated buffer"); - std::copy(SrcExprs.begin(), SrcExprs.end(), getPrivateCopies().end()); + llvm::copy(SrcExprs, getPrivateCopies().end()); } void OMPLastprivateClause::setDestinationExprs(ArrayRef DstExprs) { assert(DstExprs.size() == varlist_size() && "Number of destination " "expressions is not the same as " "the preallocated buffer"); - std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); + llvm::copy(DstExprs, getSourceExprs().end()); } void OMPLastprivateClause::setAssignmentOps(ArrayRef AssignmentOps) { assert(AssignmentOps.size() == varlist_size() && "Number of assignment expressions is not the same as the preallocated " "buffer"); - std::copy(AssignmentOps.begin(), AssignmentOps.end(), - getDestinationExprs().end()); + llvm::copy(AssignmentOps, getDestinationExprs().end()); } OMPLastprivateClause *OMPLastprivateClause::Create( @@ -555,32 +554,32 @@ OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, unsigned N) { void OMPLinearClause::setPrivates(ArrayRef PL) { assert(PL.size() == varlist_size() && "Number of privates is not the same as the preallocated buffer"); - std::copy(PL.begin(), PL.end(), varlist_end()); + llvm::copy(PL, varlist_end()); } void OMPLinearClause::setInits(ArrayRef IL) { assert(IL.size() == varlist_size() && "Number of inits is not the same as the preallocated buffer"); - std::copy(IL.begin(), IL.end(), getPrivates().end()); + llvm::copy(IL, getPrivates().end()); } void OMPLinearClause::setUpdates(ArrayRef UL) { assert(UL.size() == varlist_size() && "Number of updates is not the same as the preallocated buffer"); - std::copy(UL.begin(), UL.end(), getInits().end()); + llvm::copy(UL, getInits().end()); } void OMPLinearClause::setFinals(ArrayRef FL) { assert(FL.size() == varlist_size() && "Number of final updates is not the same as the preallocated buffer"); - std::copy(FL.begin(), FL.end(), getUpdates().end()); + llvm::copy(FL, getUpdates().end()); } void OMPLinearClause::setUsedExprs(ArrayRef UE) { assert( UE.size() == varlist_size() + 1 && "Number of used expressions is not the same as the preallocated buffer"); - std::copy(UE.begin(), UE.end(), getFinals().end() + 2); + llvm::copy(UE, getFinals().end() + 2); } OMPLinearClause *OMPLinearClause::Create( @@ -659,22 +658,21 @@ void OMPCopyinClause::setSourceExprs(ArrayRef SrcExprs) { assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " "not the same as the " "preallocated buffer"); - std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end()); + llvm::copy(SrcExprs, varlist_end()); } void OMPCopyinClause::setDestinationExprs(ArrayRef DstExprs) { assert(DstExprs.size() == varlist_size() && "Number of destination " "expressions is not the same as " "the preallocated buffer"); - std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); + llvm::copy(DstExprs, getSourceExprs().end()); } void OMPCopyinClause::setAssignmentOps(ArrayRef AssignmentOps) { assert(AssignmentOps.size() == varlist_size() && "Number of assignment expressions is not the same as the preallocated " "buffer"); - std::copy(AssignmentOps.begin(), AssignmentOps.end(), - getDestinationExprs().end()); + llvm::copy(AssignmentOps, getDestinationExprs().end()); } OMPCopyinClause *OMPCopyinClause::Create( @@ -700,22 +698,21 @@ void OMPCopyprivateClause::setSourceExprs(ArrayRef SrcExprs) { assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " "not the same as the " "preallocated buffer"); - std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end()); + llvm::copy(SrcExprs, varlist_end()); } void OMPCopyprivateClause::setDestinationExprs(ArrayRef DstExprs) { assert(DstExprs.size() == varlist_size() && "Number of destination " "expressions is not the same as " "the preallocated buffer"); - std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); + llvm::copy(DstExprs, getSourceExprs().end()); } void OMPCopyprivateClause::setAssignmentOps(ArrayRef AssignmentOps) { assert(AssignmentOps.size() == varlist_size() && "Number of assignment expressions is not the same as the preallocated " "buffer"); - std::copy(AssignmentOps.begin(), AssignmentOps.end(), - getDestinationExprs().end()); + llvm::copy(AssignmentOps, getDestinationExprs().end()); } OMPCopyprivateClause *OMPCopyprivateClause::Create( @@ -741,28 +738,28 @@ OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C, void OMPReductionClause::setPrivates(ArrayRef Privates) { assert(Privates.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(Privates.begin(), Privates.end(), varlist_end()); + llvm::copy(Privates, varlist_end()); } void OMPReductionClause::setLHSExprs(ArrayRef LHSExprs) { assert( LHSExprs.size() == varlist_size() && "Number of LHS expressions is not the same as the preallocated buffer"); - std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end()); + llvm::copy(LHSExprs, getPrivates().end()); } void OMPReductionClause::setRHSExprs(ArrayRef RHSExprs) { assert( RHSExprs.size() == varlist_size() && "Number of RHS expressions is not the same as the preallocated buffer"); - std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); + llvm::copy(RHSExprs, getLHSExprs().end()); } void OMPReductionClause::setReductionOps(ArrayRef ReductionOps) { assert(ReductionOps.size() == varlist_size() && "Number of reduction " "expressions is not the same " "as the preallocated buffer"); - std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); + llvm::copy(ReductionOps, getRHSExprs().end()); } void OMPReductionClause::setInscanCopyOps(ArrayRef Ops) { @@ -843,28 +840,28 @@ OMPReductionClause::CreateEmpty(const ASTContext &C, unsigned N, void OMPTaskReductionClause::setPrivates(ArrayRef Privates) { assert(Privates.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(Privates.begin(), Privates.end(), varlist_end()); + llvm::copy(Privates, varlist_end()); } void OMPTaskReductionClause::setLHSExprs(ArrayRef LHSExprs) { assert( LHSExprs.size() == varlist_size() && "Number of LHS expressions is not the same as the preallocated buffer"); - std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end()); + llvm::copy(LHSExprs, getPrivates().end()); } void OMPTaskReductionClause::setRHSExprs(ArrayRef RHSExprs) { assert( RHSExprs.size() == varlist_size() && "Number of RHS expressions is not the same as the preallocated buffer"); - std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); + llvm::copy(RHSExprs, getLHSExprs().end()); } void OMPTaskReductionClause::setReductionOps(ArrayRef ReductionOps) { assert(ReductionOps.size() == varlist_size() && "Number of task reduction " "expressions is not the same " "as the preallocated buffer"); - std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); + llvm::copy(ReductionOps, getRHSExprs().end()); } OMPTaskReductionClause *OMPTaskReductionClause::Create( @@ -896,28 +893,28 @@ OMPTaskReductionClause *OMPTaskReductionClause::CreateEmpty(const ASTContext &C, void OMPInReductionClause::setPrivates(ArrayRef Privates) { assert(Privates.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(Privates.begin(), Privates.end(), varlist_end()); + llvm::copy(Privates, varlist_end()); } void OMPInReductionClause::setLHSExprs(ArrayRef LHSExprs) { assert( LHSExprs.size() == varlist_size() && "Number of LHS expressions is not the same as the preallocated buffer"); - std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end()); + llvm::copy(LHSExprs, getPrivates().end()); } void OMPInReductionClause::setRHSExprs(ArrayRef RHSExprs) { assert( RHSExprs.size() == varlist_size() && "Number of RHS expressions is not the same as the preallocated buffer"); - std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); + llvm::copy(RHSExprs, getLHSExprs().end()); } void OMPInReductionClause::setReductionOps(ArrayRef ReductionOps) { assert(ReductionOps.size() == varlist_size() && "Number of in reduction " "expressions is not the same " "as the preallocated buffer"); - std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); + llvm::copy(ReductionOps, getRHSExprs().end()); } void OMPInReductionClause::setTaskgroupDescriptors( @@ -925,8 +922,7 @@ void OMPInReductionClause::setTaskgroupDescriptors( assert(TaskgroupDescriptors.size() == varlist_size() && "Number of in reduction descriptors is not the same as the " "preallocated buffer"); - std::copy(TaskgroupDescriptors.begin(), TaskgroupDescriptors.end(), - getReductionOps().end()); + llvm::copy(TaskgroupDescriptors, getReductionOps().end()); } OMPInReductionClause *OMPInReductionClause::Create( @@ -1322,13 +1318,13 @@ OMPFromClause::CreateEmpty(const ASTContext &C, void OMPUseDevicePtrClause::setPrivateCopies(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of private copies is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), varlist_end()); + llvm::copy(VL, varlist_end()); } void OMPUseDevicePtrClause::setInits(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of inits is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), getPrivateCopies().end()); + llvm::copy(VL, getPrivateCopies().end()); } OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create( @@ -1543,7 +1539,7 @@ OMPNontemporalClause *OMPNontemporalClause::CreateEmpty(const ASTContext &C, void OMPNontemporalClause::setPrivateRefs(ArrayRef VL) { assert(VL.size() == varlist_size() && "Number of private references is not " "the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), varlist_end()); + llvm::copy(VL, varlist_end()); } OMPInclusiveClause *OMPInclusiveClause::Create(const ASTContext &C, @@ -1678,7 +1674,7 @@ OMPInitClause *OMPInitClause::Create(const ASTContext &C, Expr *InteropVar, InteropInfo.IsTarget, InteropInfo.IsTargetSync, StartLoc, LParenLoc, VarLoc, EndLoc, InteropInfo.PreferTypes.size() + 1); Clause->setInteropVar(InteropVar); - llvm::copy(InteropInfo.PreferTypes, Clause->getTrailingObjects() + 1); + llvm::copy(InteropInfo.PreferTypes, Clause->getTrailingObjects() + 1); return Clause; } diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 4d11a3b62331..39703d6d7b88 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -140,7 +140,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, if (MightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType( TST->getTemplateName(), FQArgs, - /*CanonicalArgs=*/std::nullopt, TST->desugar()); + /*CanonicalArgs=*/{}, TST->desugar()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify // it. @@ -172,8 +172,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, TemplateName TN(TSTDecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType( TN, FQArgs, - /*CanonicalArgs=*/std::nullopt, - TSTRecord->getCanonicalTypeInternal()); + /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify // it. diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 0b0289cd5ec0..4fc4a99ad240 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -384,8 +384,7 @@ CompoundStmt::CompoundStmt(ArrayRef Stmts, FPOptionsOverride FPFeatures, void CompoundStmt::setStmts(ArrayRef Stmts) { assert(CompoundStmtBits.NumStmts == Stmts.size() && "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!"); - - std::copy(Stmts.begin(), Stmts.end(), body_begin()); + llvm::copy(Stmts, body_begin()); } CompoundStmt *CompoundStmt::Create(const ASTContext &C, ArrayRef Stmts, @@ -947,10 +946,10 @@ void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr, AsmStr = copyIntoContext(C, asmstr); Exprs = new (C) Stmt*[exprs.size()]; - std::copy(exprs.begin(), exprs.end(), Exprs); + llvm::copy(exprs, Exprs); AsmToks = new (C) Token[asmtoks.size()]; - std::copy(asmtoks.begin(), asmtoks.end(), AsmToks); + llvm::copy(asmtoks, AsmToks); Constraints = new (C) StringRef[exprs.size()]; std::transform(constraints.begin(), constraints.end(), Constraints, @@ -1385,7 +1384,7 @@ CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind, // Copy all Capture objects. Capture *Buffer = getStoredCaptures(); - std::copy(Captures.begin(), Captures.end(), Buffer); + llvm::copy(Captures, Buffer); } CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index 78f394845fdd..fe562cd65f9d 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -43,7 +43,7 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, CompoundStmt *tryBlock, : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) { Stmt **Stmts = getStmts(); Stmts[0] = tryBlock; - std::copy(handlers.begin(), handlers.end(), Stmts + 1); + llvm::copy(handlers, Stmts + 1); } CXXForRangeStmt::CXXForRangeStmt(Stmt *Init, DeclStmt *Range, @@ -124,8 +124,7 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args) SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt; SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] = Args.ReturnStmtOnAllocFailure; - std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(), - const_cast(getParamMoves().data())); + llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data())); } CXXExpansionStmt::CXXExpansionStmt( diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 093e1f659916..2eeb5e45ab51 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -471,18 +471,21 @@ OMPUnrollDirective *OMPUnrollDirective::CreateEmpty(const ASTContext &C, OMPReverseDirective * OMPReverseDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt, - Stmt *TransformedStmt, Stmt *PreInits) { + unsigned NumLoops, Stmt *TransformedStmt, + Stmt *PreInits) { OMPReverseDirective *Dir = createDirective( - C, {}, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc); + C, {}, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc, + NumLoops); Dir->setTransformedStmt(TransformedStmt); Dir->setPreInits(PreInits); return Dir; } -OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C) { +OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C, + unsigned NumLoops) { return createEmptyDirective( C, /*NumClauses=*/0, /*HasAssociatedStmt=*/true, - TransformedStmtOffset + 1, SourceLocation(), SourceLocation()); + TransformedStmtOffset + 1, SourceLocation(), SourceLocation(), NumLoops); } OMPInterchangeDirective *OMPInterchangeDirective::Create( diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index a9a53d56575a..a8cc46d4a081 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -3046,11 +3046,6 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { PrintExpr(Node->getSourceExpr()); } -void StmtPrinter::VisitTypoExpr(TypoExpr *Node) { - // TODO: Print something reasonable for a TypoExpr, if necessary. - llvm_unreachable("Cannot print TypoExpr nodes"); -} - void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) { OS << "("; const char *Sep = ""; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index cccc1f5311d3..cbb61fff6f8f 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2189,8 +2189,14 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) { void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) { VisitExpr(S); - VisitNestedNameSpecifier(S->getQualifier()); - VisitName(S->getName(), /*TreatAsDecl*/ true); + bool DescribingDependentVarTemplate = + S->getNumDecls() == 1 && isa(*S->decls_begin()); + if (DescribingDependentVarTemplate) { + VisitDecl(*S->decls_begin()); + } else { + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getName(), /*TreatAsDecl*/ true); + } ID.AddBoolean(S->hasExplicitTemplateArgs()); if (S->hasExplicitTemplateArgs()) VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); @@ -2441,10 +2447,6 @@ void StmtProfiler::VisitCXXExpansionInitListExpr( VisitExpr(E); } -void StmtProfiler::VisitTypoExpr(const TypoExpr *E) { - VisitExpr(E); -} - void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { VisitExpr(E); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 1952117ed646..2e9b74eefda4 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4029,10 +4029,9 @@ CountAttributedType::CountAttributedType( CountAttributedTypeBits.NumCoupledDecls = CoupledDecls.size(); CountAttributedTypeBits.CountInBytes = CountInBytes; CountAttributedTypeBits.OrNull = OrNull; - auto *DeclSlot = getTrailingObjects(); + auto *DeclSlot = getTrailingObjects(); + llvm::copy(CoupledDecls, DeclSlot); Decls = llvm::ArrayRef(DeclSlot, CoupledDecls.size()); - for (unsigned i = 0; i != CoupledDecls.size(); ++i) - DeclSlot[i] = CoupledDecls[i]; } StringRef CountAttributedType::getAttributeName(bool WithMacroPrefix) const { diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 8b1ca6b80971..631a546b45ff 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -30,7 +30,6 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Casting.h" #include #include #include diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index 905046685934..004e5209a44a 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -119,7 +119,6 @@ normalizeAttrScopeName(const IdentifierInfo *ScopeName, AttributeCommonInfo::Syntax SyntaxUsed) { if (ScopeName) return normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed); - return ""; } @@ -141,12 +140,23 @@ static StringRef normalizeAttrName(StringRef AttrName, return AttrName; } +StringRef AttributeCommonInfo::getNormalizedScopeName() const { + return normalizeAttrScopeName(getScopeName(), getSyntax()); +} + +StringRef +AttributeCommonInfo::getNormalizedAttrName(StringRef ScopeName) const { + return normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax()); +} + bool AttributeCommonInfo::isGNUScope() const { - return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); + return AttrScope.isValid() && (AttrScope.getName()->isStr("gnu") || + AttrScope.getName()->isStr("__gnu__")); } bool AttributeCommonInfo::isClangScope() const { - return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); + return AttrScope.isValid() && (AttrScope.getName()->isStr("clang") || + AttrScope.getName()->isStr("_Clang")); } #include "clang/Sema/AttrParsedAttrKinds.inc" @@ -198,8 +208,16 @@ std::string AttributeCommonInfo::getNormalizedFullName() const { normalizeName(getAttrName(), getScopeName(), getSyntax())); } +std::string +AttributeCommonInfo::getNormalizedFullName(StringRef ScopeName, + StringRef AttrName) const { + return static_cast( + normalizeName(AttrName, ScopeName, getSyntax())); +} + SourceRange AttributeCommonInfo::getNormalizedRange() const { - return hasScope() ? SourceRange(ScopeLoc, AttrRange.getEnd()) : AttrRange; + return hasScope() ? SourceRange(AttrScope.getNameLoc(), AttrRange.getEnd()) + : AttrRange; } static AttributeCommonInfo::Scope @@ -239,10 +257,8 @@ static constexpr const char *AttrScopeSpellingList[] = { #include "clang/Basic/AttributeSpellingList.inc" }; -std::optional -AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target, - const LangOptions &LangOpts) const { - StringRef ScopeName = normalizeAttrScopeName(getScopeName(), getSyntax()); +std::optional +AttributeCommonInfo::tryGetCorrectedScopeName(StringRef ScopeName) const { if (ScopeName.size() > 0 && llvm::none_of(AttrScopeSpellingList, [&](const char *S) { return S == ScopeName; })) { @@ -251,25 +267,26 @@ AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target, STC.add(Scope); if (auto CorrectedScopeName = STC.getCorrection()) - ScopeName = *CorrectedScopeName; + return CorrectedScopeName; } + return std::nullopt; +} - StringRef AttrName = - normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax()); +std::optional AttributeCommonInfo::tryGetCorrectedAttrName( + StringRef ScopeName, StringRef AttrName, const TargetInfo &Target, + const LangOptions &LangOpts) const { if (llvm::none_of(AttrSpellingList, [&](const char *A) { return A == AttrName; })) { SimpleTypoCorrection STC(AttrName); for (const auto &Attr : AttrSpellingList) STC.add(Attr); - if (auto CorrectedAttrName = STC.getCorrection()) - AttrName = *CorrectedAttrName; + if (auto CorrectedAttrName = STC.getCorrection()) { + if (hasAttribute(getSyntax(), ScopeName, *CorrectedAttrName, Target, + LangOpts, + /*CheckPlugins=*/true)) + return CorrectedAttrName; + } } - - if (hasAttribute(getSyntax(), ScopeName, AttrName, Target, LangOpts, - /*CheckPlugins=*/true)) - return static_cast( - normalizeName(AttrName, ScopeName, getSyntax())); - return std::nullopt; } diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 694224071347..a30bfa28eca7 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -119,6 +119,8 @@ bool DiagnosticsEngine::popMappings(SourceLocation Loc) { return true; } +void DiagnosticsEngine::ResetPragmas() { DiagStatesByLoc.clear(/*Soft=*/true); } + void DiagnosticsEngine::Reset(bool soft /*=false*/) { ErrorOccurred = false; UncompilableErrorOccurred = false; @@ -130,12 +132,12 @@ void DiagnosticsEngine::Reset(bool soft /*=false*/) { TrapNumErrorsOccurred = 0; TrapNumUnrecoverableErrorsOccurred = 0; - LastDiagLevel = DiagnosticIDs::Ignored; + LastDiagLevel = Ignored; if (!soft) { // Clear state related to #pragma diagnostic. DiagStates.clear(); - DiagStatesByLoc.clear(); + DiagStatesByLoc.clear(false); DiagStateOnPushStack.clear(); // Create a DiagState and DiagStatePoint representing diagnostic changes @@ -658,13 +660,95 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { Level DiagLevel = storedDiag.getLevel(); Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(), DiagStorage, storedDiag.getMessage()); + Report(DiagLevel, Info); +} + +void DiagnosticsEngine::Report(Level DiagLevel, const Diagnostic &Info) { + assert(DiagLevel != Ignored && "Cannot emit ignored diagnostics!"); Client->HandleDiagnostic(DiagLevel, Info); if (Client->IncludeInDiagnosticCounts()) { - if (DiagLevel == DiagnosticsEngine::Warning) + if (DiagLevel == Warning) ++NumWarnings; } } +/// ProcessDiag - This is the method used to report a diagnostic that is +/// finally fully formed. +bool DiagnosticsEngine::ProcessDiag(const DiagnosticBuilder &DiagBuilder) { + Diagnostic Info(this, DiagBuilder); + + assert(getClient() && "DiagnosticClient not set!"); + + // Figure out the diagnostic level of this message. + unsigned DiagID = Info.getID(); + Level DiagLevel = getDiagnosticLevel(DiagID, Info.getLocation()); + + // Update counts for DiagnosticErrorTrap even if a fatal error occurred + // or diagnostics are suppressed. + if (DiagLevel >= Error) { + ++TrapNumErrorsOccurred; + if (Diags->isUnrecoverable(DiagID)) + ++TrapNumUnrecoverableErrorsOccurred; + } + + if (SuppressAllDiagnostics) + return false; + + if (DiagLevel != Note) { + // Record that a fatal error occurred only when we see a second + // non-note diagnostic. This allows notes to be attached to the + // fatal error, but suppresses any diagnostics that follow those + // notes. + if (LastDiagLevel == Fatal) + FatalErrorOccurred = true; + + LastDiagLevel = DiagLevel; + } + + // If a fatal error has already been emitted, silence all subsequent + // diagnostics. + if (FatalErrorOccurred) { + if (DiagLevel >= Error && Client->IncludeInDiagnosticCounts()) + ++NumErrors; + + return false; + } + + // If the client doesn't care about this message, don't issue it. If this is + // a note and the last real diagnostic was ignored, ignore it too. + if (DiagLevel == Ignored || (DiagLevel == Note && LastDiagLevel == Ignored)) + return false; + + if (DiagLevel >= Error) { + if (Diags->isUnrecoverable(DiagID)) + UnrecoverableErrorOccurred = true; + + // Warnings which have been upgraded to errors do not prevent compilation. + if (Diags->isDefaultMappingAsError(DiagID)) + UncompilableErrorOccurred = true; + + ErrorOccurred = true; + if (Client->IncludeInDiagnosticCounts()) + ++NumErrors; + + // If we've emitted a lot of errors, emit a fatal error instead of it to + // stop a flood of bogus errors. + if (ErrorLimit && NumErrors > ErrorLimit && DiagLevel == Error) { + Report(diag::fatal_too_many_errors); + return false; + } + } + + // Make sure we set FatalErrorOccurred to ensure that the notes from the + // diagnostic that caused `fatal_too_many_errors` won't be emitted. + if (Info.getID() == diag::fatal_too_many_errors) + FatalErrorOccurred = true; + + // Finally, report it. + Report(DiagLevel, Info); + return true; +} + bool DiagnosticsEngine::EmitDiagnostic(const DiagnosticBuilder &DB, bool Force) { assert(getClient() && "DiagnosticClient not set!"); @@ -674,14 +758,12 @@ bool DiagnosticsEngine::EmitDiagnostic(const DiagnosticBuilder &DB, Diagnostic Info(this, DB); // Figure out the diagnostic level of this message. - DiagnosticIDs::Level DiagLevel = - Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this); + Level DiagLevel = getDiagnosticLevel(Info.getID(), Info.getLocation()); - Emitted = (DiagLevel != DiagnosticIDs::Ignored); - if (Emitted) { - // Emit the diagnostic regardless of suppression level. - Diags->EmitDiag(*this, DB, DiagLevel); - } + // Emit the diagnostic regardless of suppression level. + Emitted = DiagLevel != Ignored; + if (Emitted) + Report(DiagLevel, Info); } else { // Process the diagnostic, sending the accumulated information to the // DiagnosticConsumer. diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index 062992de8ea8..21d4df9a1744 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -827,103 +827,6 @@ unsigned DiagnosticIDs::getCXXCompatDiagId(const LangOptions &LangOpts, return StdVer >= D.StdVer ? D.DiagId : D.PreDiagId; } -/// ProcessDiag - This is the method used to report a diagnostic that is -/// finally fully formed. -bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag, - const DiagnosticBuilder &DiagBuilder) const { - Diagnostic Info(&Diag, DiagBuilder); - - assert(Diag.getClient() && "DiagnosticClient not set!"); - - // Figure out the diagnostic level of this message. - unsigned DiagID = Info.getID(); - DiagnosticIDs::Level DiagLevel - = getDiagnosticLevel(DiagID, Info.getLocation(), Diag); - - // Update counts for DiagnosticErrorTrap even if a fatal error occurred - // or diagnostics are suppressed. - if (DiagLevel >= DiagnosticIDs::Error) { - ++Diag.TrapNumErrorsOccurred; - if (isUnrecoverable(DiagID)) - ++Diag.TrapNumUnrecoverableErrorsOccurred; - } - - if (Diag.SuppressAllDiagnostics) - return false; - - if (DiagLevel != DiagnosticIDs::Note) { - // Record that a fatal error occurred only when we see a second - // non-note diagnostic. This allows notes to be attached to the - // fatal error, but suppresses any diagnostics that follow those - // notes. - if (Diag.LastDiagLevel == DiagnosticIDs::Fatal) - Diag.FatalErrorOccurred = true; - - Diag.LastDiagLevel = DiagLevel; - } - - // If a fatal error has already been emitted, silence all subsequent - // diagnostics. - if (Diag.FatalErrorOccurred) { - if (DiagLevel >= DiagnosticIDs::Error && - Diag.Client->IncludeInDiagnosticCounts()) { - ++Diag.NumErrors; - } - - return false; - } - - // If the client doesn't care about this message, don't issue it. If this is - // a note and the last real diagnostic was ignored, ignore it too. - if (DiagLevel == DiagnosticIDs::Ignored || - (DiagLevel == DiagnosticIDs::Note && - Diag.LastDiagLevel == DiagnosticIDs::Ignored)) - return false; - - if (DiagLevel >= DiagnosticIDs::Error) { - if (isUnrecoverable(DiagID)) - Diag.UnrecoverableErrorOccurred = true; - - // Warnings which have been upgraded to errors do not prevent compilation. - if (isDefaultMappingAsError(DiagID)) - Diag.UncompilableErrorOccurred = true; - - Diag.ErrorOccurred = true; - if (Diag.Client->IncludeInDiagnosticCounts()) { - ++Diag.NumErrors; - } - - // If we've emitted a lot of errors, emit a fatal error instead of it to - // stop a flood of bogus errors. - if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit && - DiagLevel == DiagnosticIDs::Error) { - Diag.Report(diag::fatal_too_many_errors); - return false; - } - } - - // Make sure we set FatalErrorOccurred to ensure that the notes from the - // diagnostic that caused `fatal_too_many_errors` won't be emitted. - if (Info.getID() == diag::fatal_too_many_errors) - Diag.FatalErrorOccurred = true; - // Finally, report it. - EmitDiag(Diag, DiagBuilder, DiagLevel); - return true; -} - -void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, - const DiagnosticBuilder &DiagBuilder, - Level DiagLevel) const { - Diagnostic Info(&Diag, DiagBuilder); - assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!"); - - Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info); - if (Diag.Client->IncludeInDiagnosticCounts()) { - if (DiagLevel == DiagnosticIDs::Warning) - ++Diag.NumWarnings; - } -} - bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const { // Only errors may be unrecoverable. if (getDiagClass(DiagID) < CLASS_ERROR) diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index 7e696620993f..912b890569cf 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/LangOptions.h" -#include "llvm/ADT/SmallString.h" #include "llvm/Support/Path.h" using namespace clang; diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp index a019f0ac18c8..dce9ffaedb90 100644 --- a/clang/lib/Basic/OffloadArch.cpp +++ b/clang/lib/Basic/OffloadArch.cpp @@ -86,6 +86,7 @@ static const OffloadArchToStringMap ArchNames[] = { {OffloadArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"}, GFX(1200), // gfx1200 GFX(1201), // gfx1201 + GFX(1250), // gfx1250 {OffloadArch::AMDGCNSPIRV, "amdgcnspirv", "compute_amdgcn"}, // Intel CPUs {OffloadArch::GRANITERAPIDS, "graniterapids", ""}, diff --git a/clang/lib/Basic/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp index aaea5a00ab6a..8481deffe2a7 100644 --- a/clang/lib/Basic/ProfileList.cpp +++ b/clang/lib/Basic/ProfileList.cpp @@ -69,24 +69,24 @@ ProfileList::ProfileList(ArrayRef Paths, SourceManager &SM) ProfileList::~ProfileList() = default; -static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) { +static StringRef getSectionName(llvm::driver::ProfileInstrKind Kind) { switch (Kind) { - case CodeGenOptions::ProfileNone: + case llvm::driver::ProfileInstrKind::ProfileNone: return ""; - case CodeGenOptions::ProfileClangInstr: + case llvm::driver::ProfileInstrKind::ProfileClangInstr: return "clang"; - case CodeGenOptions::ProfileIRInstr: + case llvm::driver::ProfileInstrKind::ProfileIRInstr: return "llvm"; - case CodeGenOptions::ProfileCSIRInstr: + case llvm::driver::ProfileInstrKind::ProfileCSIRInstr: return "csllvm"; - case CodeGenOptions::ProfileIRSampleColdCov: + case llvm::driver::ProfileInstrKind::ProfileIRSampleColdCov: return "sample-coldcov"; } - llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum"); + llvm_unreachable("Unhandled llvm::driver::ProfileInstrKind enum"); } ProfileList::ExclusionType -ProfileList::getDefault(CodeGenOptions::ProfileInstrKind Kind) const { +ProfileList::getDefault(llvm::driver::ProfileInstrKind Kind) const { StringRef Section = getSectionName(Kind); // Check for "default:" if (SCL->inSection(Section, "default", "allow")) @@ -117,7 +117,7 @@ ProfileList::inSection(StringRef Section, StringRef Prefix, std::optional ProfileList::isFunctionExcluded(StringRef FunctionName, - CodeGenOptions::ProfileInstrKind Kind) const { + llvm::driver::ProfileInstrKind Kind) const { StringRef Section = getSectionName(Kind); // Check for "function:=" if (auto V = inSection(Section, "function", FunctionName)) @@ -131,13 +131,13 @@ ProfileList::isFunctionExcluded(StringRef FunctionName, std::optional ProfileList::isLocationExcluded(SourceLocation Loc, - CodeGenOptions::ProfileInstrKind Kind) const { + llvm::driver::ProfileInstrKind Kind) const { return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind); } std::optional ProfileList::isFileExcluded(StringRef FileName, - CodeGenOptions::ProfileInstrKind Kind) const { + llvm::driver::ProfileInstrKind Kind) const { StringRef Section = getSectionName(Kind); // Check for "source:=" if (auto V = inSection(Section, "source", FileName)) diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 09e5c6547fb5..053e82683a4a 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -344,6 +344,9 @@ void SourceManager::clearIDTables() { NextLocalOffset = 0; CurrentLoadedOffset = MaxLoadedOffset; createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1); + // Diagnostics engine keeps some references to fileids, mostly for dealing + // with diagnostic pragmas, make sure they're reset as well. + Diag.ResetPragmas(); } bool SourceManager::isMainFile(const FileEntry &SourceFile) { diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 0f79547d515e..0dbb0cb1776f 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -557,8 +557,7 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { bool TargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeatureVec) const { - for (const auto &F : FeatureVec) { - StringRef Name = F; + for (StringRef Name : FeatureVec) { if (Name.empty()) continue; // Apply the feature via the target. diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 9889141ad208..af1111a86330 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -164,6 +164,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, return std::make_unique>(Triple, Opts); } + case llvm::Triple::Managarm: + return std::make_unique>(Triple, + Opts); case llvm::Triple::NetBSD: return std::make_unique>(Triple, Opts); @@ -466,6 +469,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, return std::make_unique>(Triple, Opts); } + case llvm::Triple::Managarm: + return std::make_unique>(Triple, + Opts); default: return std::make_unique(Triple, Opts); } @@ -654,6 +660,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, return std::make_unique>(Triple, Opts); case llvm::Triple::Hurd: return std::make_unique>(Triple, Opts); + case llvm::Triple::Managarm: + 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 e8abdf9aafd8..124b340b62d9 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -625,6 +625,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasCRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + if (HasCSSC) + Builder.defineMacro("__ARM_FEATURE_CSSC", "1"); + if (HasRCPC3) Builder.defineMacro("__ARM_FEATURE_RCPC", "3"); else if (HasRCPC) @@ -874,6 +877,7 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const { .Case("rdm", HasRDM) .Case("lse", HasLSE) .Case("crc", HasCRC) + .Case("cssc", HasCSSC) .Case("sha2", HasSHA2) .Case("sha3", HasSHA3) .Cases("aes", "pmull", HasAES) @@ -1249,6 +1253,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, HasPAuthLR = true; HasPAuth = true; } + if (Feature == "+cssc") + HasCSSC = true; } // Check features that are manually disabled by command line options. diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index a4c65361105e..1951e0679d2e 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -66,6 +66,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { unsigned FPU = FPUMode; bool HasCRC = false; + bool HasCSSC = false; bool HasAES = false; bool HasSHA2 = false; bool HasSHA3 = false; diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp index 85ca4bc30c46..bbe7b01ca036 100644 --- a/clang/lib/Basic/Targets/AVR.cpp +++ b/clang/lib/Basic/Targets/AVR.cpp @@ -336,6 +336,9 @@ static MCUInfo AVRMcus[] = { {"attiny1624", "__AVR_ATtiny1624__", "103", 1}, {"attiny1626", "__AVR_ATtiny1626__", "103", 1}, {"attiny1627", "__AVR_ATtiny1627__", "103", 1}, + {"attiny3224", "__AVR_ATtiny3224__", "103", 1}, + {"attiny3226", "__AVR_ATtiny3226__", "103", 1}, + {"attiny3227", "__AVR_ATtiny3227__", "103", 1}, {"atmega808", "__AVR_ATmega808__", "103", 1}, {"atmega809", "__AVR_ATmega809__", "103", 1}, {"atmega1608", "__AVR_ATmega1608__", "103", 1}, @@ -344,6 +347,72 @@ static MCUInfo AVRMcus[] = { {"atmega3209", "__AVR_ATmega3209__", "103", 1}, {"atmega4808", "__AVR_ATmega4808__", "103", 1}, {"atmega4809", "__AVR_ATmega4809__", "103", 1}, + + // gcc 14 additions: + + {"avr64da28", "__AVR_AVR64DA28__", "102", 1}, + {"avr64da32", "__AVR_AVR64DA32__", "102", 1}, + {"avr64da48", "__AVR_AVR64DA48__", "102", 1}, + {"avr64da64", "__AVR_AVR64DA64__", "102", 1}, + {"avr64db28", "__AVR_AVR64DB28__", "102", 1}, + {"avr64db32", "__AVR_AVR64DB32__", "102", 1}, + {"avr64db48", "__AVR_AVR64DB48__", "102", 1}, + {"avr64db64", "__AVR_AVR64DB64__", "102", 1}, + {"avr64dd14", "__AVR_AVR64DD14__", "102", 1}, + {"avr64dd20", "__AVR_AVR64DD20__", "102", 1}, + {"avr64dd28", "__AVR_AVR64DD28__", "102", 1}, + {"avr64dd32", "__AVR_AVR64DD32__", "102", 1}, + {"avr64du28", "__AVR_AVR64DU28__", "102", 1}, + {"avr64du32", "__AVR_AVR64DU32__", "102", 1}, + {"avr64ea28", "__AVR_AVR64EA28__", "102", 1}, + {"avr64ea32", "__AVR_AVR64EA32__", "102", 1}, + {"avr64ea48", "__AVR_AVR64EA48__", "102", 1}, + {"avr64sd28", "__AVR_AVR64SD28__", "102", 1}, + {"avr64sd32", "__AVR_AVR64SD32__", "102", 1}, + {"avr64sd48", "__AVR_AVR64SD48__", "102", 1}, + + {"avr16dd20", "__AVR_AVR16DD20__", "103", 1}, + {"avr16dd28", "__AVR_AVR16DD28__", "103", 1}, + {"avr16dd32", "__AVR_AVR16DD32__", "103", 1}, + {"avr16du14", "__AVR_AVR16DU14__", "103", 1}, + {"avr16du20", "__AVR_AVR16DU20__", "103", 1}, + {"avr16du28", "__AVR_AVR16DU28__", "103", 1}, + {"avr16du32", "__AVR_AVR16DU32__", "103", 1}, + {"avr32da28", "__AVR_AVR32DA28__", "103", 1}, + {"avr32da32", "__AVR_AVR32DA32__", "103", 1}, + {"avr32da48", "__AVR_AVR32DA48__", "103", 1}, + {"avr32db28", "__AVR_AVR32DB28__", "103", 1}, + {"avr32db32", "__AVR_AVR32DB32__", "103", 1}, + {"avr32db48", "__AVR_AVR32DB48__", "103", 1}, + {"avr32dd14", "__AVR_AVR32DD14__", "103", 1}, + {"avr32dd20", "__AVR_AVR32DD20__", "103", 1}, + {"avr32dd28", "__AVR_AVR32DD28__", "103", 1}, + {"avr32dd32", "__AVR_AVR32DD32__", "103", 1}, + {"avr32du14", "__AVR_AVR32DU14__", "103", 1}, + {"avr32du20", "__AVR_AVR32DU20__", "103", 1}, + {"avr32du28", "__AVR_AVR32DU28__", "103", 1}, + {"avr32du32", "__AVR_AVR32DU32__", "103", 1}, + {"avr16eb14", "__AVR_AVR16EB14__", "103", 1}, + {"avr16eb20", "__AVR_AVR16EB20__", "103", 1}, + {"avr16eb28", "__AVR_AVR16EB28__", "103", 1}, + {"avr16eb32", "__AVR_AVR16EB32__", "103", 1}, + {"avr16ea28", "__AVR_AVR16EA28__", "103", 1}, + {"avr16ea32", "__AVR_AVR16EA32__", "103", 1}, + {"avr16ea48", "__AVR_AVR16EA48__", "103", 1}, + {"avr32ea28", "__AVR_AVR32EA28__", "103", 1}, + {"avr32ea32", "__AVR_AVR32EA32__", "103", 1}, + {"avr32ea48", "__AVR_AVR32EA48__", "103", 1}, + {"avr32sd20", "__AVR_AVR32SD20__", "103", 1}, + {"avr32sd28", "__AVR_AVR32SD28__", "103", 1}, + {"avr32sd32", "__AVR_AVR32SD32__", "103", 1}, + {"avr128da28", "__AVR_AVR128DA28__", "104", 2}, + {"avr128da32", "__AVR_AVR128DA32__", "104", 2}, + {"avr128da48", "__AVR_AVR128DA48__", "104", 2}, + {"avr128da64", "__AVR_AVR128DA64__", "104", 2}, + {"avr128db28", "__AVR_AVR128DB28__", "104", 2}, + {"avr128db32", "__AVR_AVR128DB32__", "104", 2}, + {"avr128db48", "__AVR_AVR128DB48__", "104", 2}, + {"avr128db64", "__AVR_AVR128DB64__", "104", 2}, }; } // namespace targets diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 3235bf2e710d..54b39fd072a8 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -238,6 +238,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case OffloadArch::GFX12_GENERIC: case OffloadArch::GFX1200: case OffloadArch::GFX1201: + case OffloadArch::GFX1250: case OffloadArch::AMDGCNSPIRV: case OffloadArch::Generic: case OffloadArch::GRANITERAPIDS: diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index d148b38d03c7..5dac699c2bb4 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -395,6 +395,36 @@ public: } }; +// Managarm Target +template +class LLVM_LIBRARY_VISIBILITY ManagarmTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__managarm__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + ManagarmTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) { + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + break; + } + } +}; + // NetBSD Target template class LLVM_LIBRARY_VISIBILITY NetBSDTargetInfo : public OSTargetInfo { diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index e6ef0ecc526b..77145e2891a8 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/TargetParser/PPCTargetParser.h" +#include using namespace clang; using namespace clang::targets; @@ -516,129 +517,14 @@ static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, bool PPCTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { - Features["altivec"] = llvm::StringSwitch(CPU) - .Case("7400", true) - .Case("g4", true) - .Case("7450", true) - .Case("g4+", true) - .Case("970", true) - .Case("g5", true) - .Case("pwr6", true) - .Case("pwr7", true) - .Case("pwr8", true) - .Case("pwr9", true) - .Case("ppc64", true) - .Case("ppc64le", true) - .Default(false); - Features["power9-vector"] = (CPU == "pwr9"); - Features["crypto"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["power8-vector"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["bpermd"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["extdiv"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["direct-move"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["crbits"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["vsx"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["htm"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); + const llvm::Triple &TheTriple = getTriple(); - // ROP Protect is off by default. - Features["rop-protect"] = false; - // Privileged instructions are off by default. - Features["privileged"] = false; - - if (getTriple().isOSAIX()) { - // The code generated by the -maix-small-local-[exec|dynamic]-tls option is - // turned off by default. - Features["aix-small-local-exec-tls"] = false; - Features["aix-small-local-dynamic-tls"] = false; - - // Turn off TLS model opt by default. - Features["aix-shared-lib-tls-model-opt"] = false; - } - - Features["spe"] = llvm::StringSwitch(CPU) - .Case("8548", true) - .Case("e500", true) - .Default(false); - - Features["isa-v206-instructions"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Case("a2", true) - .Default(false); - - Features["isa-v207-instructions"] = llvm::StringSwitch(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - - Features["isa-v30-instructions"] = - llvm::StringSwitch(CPU).Case("pwr9", true).Default(false); - - Features["quadword-atomics"] = - getTriple().isArch64Bit() && llvm::StringSwitch(CPU) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - - // Power10 includes all the same features as Power9 plus any features specific - // to the Power10 core. - if (CPU == "pwr10" || CPU == "power10") { - initFeatureMap(Features, Diags, "pwr9", FeaturesVec); - addP10SpecificFeatures(Features); - } - - // Power11 includes all the same features as Power10 plus any features - // specific to the Power11 core. - if (CPU == "pwr11" || CPU == "power11") { - initFeatureMap(Features, Diags, "pwr10", FeaturesVec); - addP11SpecificFeatures(Features); - } - - // Future CPU should include all of the features of Power 11 as well as any - // additional features (yet to be determined) specific to it. - if (CPU == "future") { - initFeatureMap(Features, Diags, "pwr11", FeaturesVec); - addFutureSpecificFeatures(Features); - } + std::optional> FeaturesOpt = + llvm::PPC::getPPCDefaultTargetFeatures(TheTriple, + llvm::PPC::normalizeCPUName(CPU)); + if (FeaturesOpt) + Features = FeaturesOpt.value(); if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) return false; @@ -700,26 +586,6 @@ bool PPCTargetInfo::initFeatureMap( return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } -// Add any Power10 specific features. -void PPCTargetInfo::addP10SpecificFeatures( - llvm::StringMap &Features) const { - Features["htm"] = false; // HTM was removed for P10. - Features["paired-vector-memops"] = true; - Features["mma"] = true; - Features["power10-vector"] = true; - Features["pcrelative-memops"] = true; - Features["prefix-instrs"] = true; - Features["isa-v31-instructions"] = true; -} - -// Add any Power11 specific features. -void PPCTargetInfo::addP11SpecificFeatures( - llvm::StringMap &Features) const {} - -// Add features specific to the "Future" CPU. -void PPCTargetInfo::addFutureSpecificFeatures( - llvm::StringMap &Features) const {} - bool PPCTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("powerpc", true) diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 470835aacff5..f3558ac247be 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -77,7 +77,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } bool validateAsmConstraint(const char *&Name, diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index 4c8c6ed289c3..9cec17bcb2fd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -39,6 +39,34 @@ mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin, return create(arrayLocEnd, flatPtrTy, basePtr, idx); } +cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, + llvm::APSInt intVal) { + bool isSigned = intVal.isSigned(); + unsigned width = intVal.getBitWidth(); + cir::IntType t = isSigned ? getSIntNTy(width) : getUIntNTy(width); + return getConstInt(loc, t, + isSigned ? intVal.getSExtValue() : intVal.getZExtValue()); +} + +cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, + llvm::APInt intVal) { + return getConstInt(loc, llvm::APSInt(intVal)); +} + +cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, mlir::Type t, + uint64_t c) { + assert(mlir::isa(t) && "expected cir::IntType"); + return create(loc, cir::IntAttr::get(t, c)); +} + +cir::ConstantOp +clang::CIRGen::CIRGenBuilderTy::getConstFP(mlir::Location loc, mlir::Type t, + llvm::APFloat fpVal) { + assert(mlir::isa(t) && + "expected floating point type"); + return create(loc, getAttr(t, fpVal)); +} + // This can't be defined in Address.h because that file is included by // CIRGenBuilder.h Address Address::withElementType(CIRGenBuilderTy &builder, diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 03077ee062a6..e38faba83b80 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -11,10 +11,12 @@ #include "Address.h" #include "CIRGenTypeCache.h" +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h" #include "clang/CIR/MissingFeatures.h" #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/MissingFeatures.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" namespace clang::CIRGen { @@ -22,6 +24,7 @@ namespace clang::CIRGen { class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { const CIRGenTypeCache &typeCache; llvm::StringMap recordNames; + llvm::StringMap globalsVersioning; public: CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc) @@ -137,8 +140,9 @@ public: } bool isSized(mlir::Type ty) { - if (mlir::isa(ty)) + if (mlir::isa( + ty)) return true; if (const auto vt = mlir::dyn_cast(ty)) @@ -229,6 +233,15 @@ public: cir::IntType getUInt32Ty() { return typeCache.UInt32Ty; } cir::IntType getUInt64Ty() { return typeCache.UInt64Ty; } + cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal); + + cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal); + + cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c); + + cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t, + llvm::APFloat fpVal); + bool isInt8Ty(mlir::Type i) { return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty; } @@ -321,6 +334,18 @@ public: return Address(baseAddr, destType, addr.getAlignment()); } + /// Cast the element type of the given address to a different type, + /// preserving information like the alignment. + Address createElementBitCast(mlir::Location loc, Address addr, + mlir::Type destType) { + if (destType == addr.getElementType()) + return addr; + + auto ptrTy = getPointerTo(destType); + return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType, + addr.getAlignment()); + } + cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile = false) { mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment()); @@ -335,6 +360,12 @@ public: return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align); } + mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, + mlir::Value imag) { + auto resultComplexTy = cir::ComplexType::get(real.getType()); + return create(loc, resultComplexTy, real, imag); + } + /// Create a cir.ptr_stride operation to get access to an array element. /// \p idx is the index of the element to access, \p shouldDecay is true if /// the result should decay to a pointer to the element type. @@ -347,6 +378,23 @@ public: /// pointed to by \p arrayPtr. mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr, mlir::Type eltTy); + + /// Creates a versioned global variable. If the symbol is already taken, an ID + /// will be appended to the symbol. The returned global must always be queried + /// for its name so it can be referenced correctly. + [[nodiscard]] cir::GlobalOp + createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, + mlir::StringRef name, mlir::Type type, + cir::GlobalLinkageKind linkage) { + // Create a unique name if the given name is already taken. + std::string uniqueName; + if (unsigned version = globalsVersioning[name.str()]++) + uniqueName = name.str() + "." + std::to_string(version); + else + uniqueName = name.str(); + + return createGlobal(module, loc, uniqueName, type, linkage); + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp new file mode 100644 index 000000000000..cff139a7802d --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// 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 contains code to emit Builtin calls as CIR or a function call to be +// later resolved. +// +//===----------------------------------------------------------------------===// + +#include "CIRGenCall.h" +#include "CIRGenConstantEmitter.h" +#include "CIRGenFunction.h" +#include "CIRGenModule.h" +#include "CIRGenValue.h" +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/Value.h" +#include "mlir/Support/LLVM.h" +#include "clang/AST/Expr.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/CIR/MissingFeatures.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; +using namespace clang::CIRGen; +using namespace llvm; + +static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd, + const CallExpr *e, mlir::Operation *calleeValue) { + CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd)); + return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot()); +} + +RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, + const CallExpr *e, + ReturnValueSlot returnValue) { + // See if we can constant fold this builtin. If so, don't emit it at all. + // TODO: Extend this handling to all builtin calls that we can constant-fold. + Expr::EvalResult result; + if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) && + !result.hasSideEffects()) { + if (result.Val.isInt()) { + return RValue::get(builder.getConstInt(getLoc(e->getSourceRange()), + result.Val.getInt())); + } + if (result.Val.isFloat()) { + // Note: we are using result type of CallExpr to determine the type of + // the constant. Classic codegen uses the result value to determine the + // type. We feel it should be Ok to use expression type because it is + // hard to imagine a builtin function evaluates to a value that + // over/underflows its own defined type. + mlir::Type type = convertType(e->getType()); + return RValue::get(builder.getConstFP(getLoc(e->getExprLoc()), type, + result.Val.getFloat())); + } + } + + const FunctionDecl *fd = gd.getDecl()->getAsFunction(); + + // If this is an alias for a lib function (e.g. __builtin_sin), emit + // the call using the normal call path, but using the unmangled + // version of the function name. + if (getContext().BuiltinInfo.isLibFunction(builtinID)) + return emitLibraryCall(*this, fd, e, + cgm.getBuiltinLibFunction(fd, builtinID)); + + assert(!cir::MissingFeatures::builtinCallF128()); + + // If the builtin has been declared explicitly with an assembler label, + // disable the specialized emitting below. Ideally we should communicate the + // rename in IR, or at least avoid generating the intrinsic calls that are + // likely to get lowered to the renamed library functions. + unsigned builtinIDIfNoAsmLabel = fd->hasAttr() ? 0 : builtinID; + + assert(!cir::MissingFeatures::builtinCallMathErrno()); + assert(!cir::MissingFeatures::builtinCall()); + + mlir::Location loc = getLoc(e->getExprLoc()); + + switch (builtinIDIfNoAsmLabel) { + default: + break; + + case Builtin::BI__assume: + case Builtin::BI__builtin_assume: { + if (e->getArg(0)->HasSideEffects(getContext())) + return RValue::get(nullptr); + + mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0)); + builder.create(loc, argValue); + return RValue::get(nullptr); + } + + case Builtin::BI__builtin_complex: { + mlir::Value real = emitScalarExpr(e->getArg(0)); + mlir::Value imag = emitScalarExpr(e->getArg(1)); + mlir::Value complex = builder.createComplexCreate(loc, real, imag); + return RValue::get(complex); + } + } + + cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call"); + return getUndefRValue(e->getType()); +} + +/// Given a builtin id for a function like "__builtin_fabsf", return a Function* +/// for "fabsf". +cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd, + unsigned builtinID) { + assert(astContext.BuiltinInfo.isLibFunction(builtinID)); + + // Get the name, skip over the __builtin_ prefix (if necessary). We may have + // to build this up so provide a small stack buffer to handle the vast + // majority of names. + llvm::SmallString<64> name; + + assert(!cir::MissingFeatures::asmLabelAttr()); + name = astContext.BuiltinInfo.getName(builtinID).substr(10); + + GlobalDecl d(fd); + mlir::Type type = convertType(fd->getType()); + return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false); +} + +mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) { + mlir::Value argValue = evaluateExprAsBool(e); + if (!sanOpts.has(SanitizerKind::Builtin)) + return argValue; + + assert(!cir::MissingFeatures::sanitizers()); + cgm.errorNYI(e->getSourceRange(), + "emitCheckedArgForAssume: sanitizers are NYI"); + return {}; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp new file mode 100644 index 000000000000..51751483d34e --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 contains code dealing with C++ code generation. +// +//===----------------------------------------------------------------------===// + +#include "CIRGenFunction.h" +#include "CIRGenModule.h" + +#include "clang/AST/GlobalDecl.h" +#include "clang/CIR/MissingFeatures.h" + +using namespace clang; +using namespace clang::CIRGen; + +cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) { + const CIRGenFunctionInfo &fnInfo = + getTypes().arrangeCXXStructorDeclaration(gd); + cir::FuncType funcType = getTypes().getFunctionType(fnInfo); + cir::FuncOp fn = getAddrOfCXXStructor(gd, &fnInfo, /*FnType=*/nullptr, + /*DontDefer=*/true, ForDefinition); + assert(!cir::MissingFeatures::opFuncLinkage()); + CIRGenFunction cgf{*this, builder}; + curCGF = &cgf; + { + mlir::OpBuilder::InsertionGuard guard(builder); + cgf.generateCode(gd, fn, funcType); + } + curCGF = nullptr; + + setNonAliasAttributes(gd, fn); + assert(!cir::MissingFeatures::opFuncAttributesForDefinition()); + return fn; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 107535ebc727..2d967fd307e0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -37,6 +37,10 @@ public: void setCXXABIThisValue(CIRGenFunction &cgf, mlir::Value thisPtr); + /// Emit a single constructor/destructor with the gen type from a C++ + /// constructor/destructor Decl. + virtual void emitCXXStructor(clang::GlobalDecl gd) = 0; + public: clang::ImplicitParamDecl *getThisDecl(CIRGenFunction &cgf) { return cgf.cxxabiThisDecl; @@ -55,12 +59,19 @@ public: return md->getParent(); } + /// Return whether the given global decl needs a VTT (virtual table table) + /// parameter. + virtual bool needsVTTParameter(clang::GlobalDecl gd) { return false; } + /// Build a parameter variable suitable for 'this'. void buildThisParam(CIRGenFunction &cgf, FunctionArgList ¶ms); /// Loads the incoming C++ this pointer as it was passed by the caller. mlir::Value loadIncomingCXXThis(CIRGenFunction &cgf); + /// Emit constructor variants required by this ABI. + virtual void emitCXXConstructors(const clang::CXXConstructorDecl *d) = 0; + /// Returns true if the given constructor or destructor is one of the kinds /// that the ABI says returns 'this' (only applies when called non-virtually /// for destructors). diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 9d25eea9e413..9c9c96604c16 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,52 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { return *this; } +void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) { + // In classic codegen: + // Function to store a first-class aggregate into memory. We prefer to + // store the elements rather than the aggregate to be more friendly to + // fast-isel. + // In CIR codegen: + // Emit the most simple cir.store possible (e.g. a store for a whole + // record), which can later be broken down in other CIR levels (or prior + // to dialect codegen). + + // Stored result for the callers of this function expected to be in the same + // scope as the value, don't make assumptions about current insertion point. + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointAfter(value.getDefiningOp()); + builder.createStore(*currSrcLoc, value, dest); +} + +/// Construct the CIR attribute list of a function or call. +void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo, + cir::SideEffect &sideEffect) { + assert(!cir::MissingFeatures::opCallCallConv()); + sideEffect = cir::SideEffect::All; + + assert(!cir::MissingFeatures::opCallAttrs()); + + const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl(); + + if (targetDecl) { + assert(!cir::MissingFeatures::opCallAttrs()); + + // 'const', 'pure' and 'noalias' attributed functions are also nounwind. + if (targetDecl->hasAttr()) { + // gcc specifies that 'const' functions have greater restrictions than + // 'pure' functions, so they also cannot have infinite loops. + sideEffect = cir::SideEffect::Const; + } else if (targetDecl->hasAttr()) { + // gcc specifies that 'pure' functions cannot have infinite loops. + sideEffect = cir::SideEffect::Pure; + } + + assert(!cir::MissingFeatures::opCallAttrs()); + } + + assert(!cir::MissingFeatures::opCallAttrs()); +} + /// Returns the canonical formal type of the given C++ method. static CanQual getFormalType(const CXXMethodDecl *md) { return md->getType() @@ -162,6 +208,46 @@ arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, return cgt.arrangeCIRFunctionInfo(resultType, prefix, required); } +void CIRGenFunction::emitDelegateCallArg(CallArgList &args, + const VarDecl *param, + SourceLocation loc) { + // StartFunction converted the ABI-lowered parameter(s) into a local alloca. + // We need to turn that into an r-value suitable for emitCall + Address local = getAddrOfLocalVar(param); + + QualType type = param->getType(); + + if (type->getAsCXXRecordDecl()) { + cgm.errorNYI(param->getSourceRange(), + "emitDelegateCallArg: record argument"); + return; + } + + // GetAddrOfLocalVar returns a pointer-to-pointer for references, but the + // argument needs to be the original pointer. + if (type->isReferenceType()) { + args.add( + RValue::get(builder.createLoad(getLoc(param->getSourceRange()), local)), + type); + } else if (getLangOpts().ObjCAutoRefCount) { + cgm.errorNYI(param->getSourceRange(), + "emitDelegateCallArg: ObjCAutoRefCount"); + // For the most part, we just need to load the alloca, except that aggregate + // r-values are actually pointers to temporaries. + } else { + args.add(convertTempToRValue(local, type, loc), type); + } + + // Deactivate the cleanup for the callee-destructed param that was pushed. + assert(!cir::MissingFeatures::thunks()); + if (type->isRecordType() && + type->castAs()->getDecl()->isParamDestroyedInCallee() && + param->needsDestruction(getContext())) { + cgm.errorNYI(param->getSourceRange(), + "emitDelegateCallArg: callee-destructed param"); + } +} + static const CIRGenFunctionInfo & arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, const CallArgList &args, @@ -329,7 +415,8 @@ static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, cir::FuncOp directFuncOp, - const SmallVectorImpl &cirCallArgs) { + const SmallVectorImpl &cirCallArgs, + cir::SideEffect sideEffect) { CIRGenBuilderTy &builder = cgf.getBuilder(); assert(!cir::MissingFeatures::opCallSurroundingTry()); @@ -340,11 +427,11 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, if (indirectFuncTy) { // TODO(cir): Set calling convention for indirect calls. assert(!cir::MissingFeatures::opCallCallConv()); - return builder.createIndirectCallOp(callLoc, indirectFuncVal, - indirectFuncTy, cirCallArgs); + return builder.createIndirectCallOp( + callLoc, indirectFuncVal, indirectFuncTy, cirCallArgs, sideEffect); } - return builder.createCallOp(callLoc, directFuncOp, cirCallArgs); + return builder.createCallOp(callLoc, directFuncOp, cirCallArgs, sideEffect); } const CIRGenFunctionInfo & @@ -386,7 +473,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, mlir::Value v; if (arg.isAggregate()) cgm.errorNYI(loc, "emitCall: aggregate call argument"); - v = arg.getKnownRValue().getScalarVal(); + v = arg.getKnownRValue().getValue(); // We might have to widen integers, but we should never truncate. if (argType != v.getType() && mlir::isa(v.getType())) @@ -399,8 +486,49 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, assert(!cir::MissingFeatures::opCallBitcastArg()); cirCallArgs[argNo] = v; } else { - assert(!cir::MissingFeatures::opCallAggregateArgs()); - cgm.errorNYI("emitCall: aggregate function call argument"); + Address src = Address::invalid(); + if (!arg.isAggregate()) + cgm.errorNYI(loc, "emitCall: non-aggregate call argument"); + else + src = arg.hasLValue() ? arg.getKnownLValue().getAddress() + : arg.getKnownRValue().getAggregateAddress(); + + // Fast-isel and the optimizer generally like scalar values better than + // FCAs, so we flatten them if this is safe to do for this argument. + auto argRecordTy = cast(argType); + mlir::Type srcTy = src.getElementType(); + // FIXME(cir): get proper location for each argument. + mlir::Location argLoc = loc; + + // If the source type is smaller than the destination type of the + // coerce-to logic, copy the source value into a temp alloca the size + // of the destination type to allow loading all of it. The bits past + // the source value are left undef. + // FIXME(cir): add data layout info and compare sizes instead of + // matching the types. + // + // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy); + // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy); + // if (SrcSize < DstSize) { + assert(!cir::MissingFeatures::dataLayoutTypeAllocSize()); + if (srcTy != argRecordTy) { + cgm.errorNYI(loc, "emitCall: source type does not match argument type"); + } else { + // FIXME(cir): this currently only runs when the types are exactly the + // same, but should be when alloc sizes are the same, fix this as soon + // as datalayout gets introduced. + assert(!cir::MissingFeatures::dataLayoutTypeAllocSize()); + } + + // assert(NumCIRArgs == STy.getMembers().size()); + // In LLVMGen: Still only pass the struct without any gaps but mark it + // as such somehow. + // + // In CIRGen: Emit a load from the "whole" struct, + // which shall be broken later by some lowering step into multiple + // loads. + assert(!cir::MissingFeatures::lowerAggregateLoadStore()); + cirCallArgs[argNo] = builder.createLoad(argLoc, src); } } @@ -415,8 +543,9 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, funcName = calleeFuncOp.getName(); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); assert(!cir::MissingFeatures::opCallAttrs()); + cir::SideEffect sideEffect; + cgm.constructAttributeList(callee.getAbstractInfo(), sideEffect); assert(!cir::MissingFeatures::invokeOp()); @@ -439,8 +568,10 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, assert(!cir::MissingFeatures::opCallAttrs()); - cir::CIRCallOpInterface theCall = emitCallLikeOp( - *this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs); + mlir::Location callLoc = loc; + cir::CIRCallOpInterface theCall = + emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, + cirCallArgs, sideEffect); if (callOp) *callOp = theCall; @@ -452,6 +583,19 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, if (isa(retCIRTy)) return getUndefRValue(retTy); switch (getEvaluationKind(retTy)) { + case cir::TEK_Aggregate: { + Address destPtr = returnValue.getValue(); + + if (!destPtr.isValid()) + destPtr = createMemTemp(retTy, callLoc, getCounterAggTmpAsString()); + + mlir::ResultRange results = theCall->getOpResults(); + assert(results.size() <= 1 && "multiple returns from a call"); + + SourceLocRAIIObject loc{*this, callLoc}; + emitAggregateStore(results[0], destPtr); + return RValue::getAggregate(destPtr); + } case cir::TEK_Scalar: { mlir::ResultRange results = theCall->getOpResults(); assert(results.size() == 1 && "unexpected number of returns"); @@ -468,7 +612,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, return RValue::get(results[0]); } case cir::TEK_Complex: - case cir::TEK_Aggregate: cgm.errorNYI(loc, "unsupported evaluation kind of function call result"); return getUndefRValue(retTy); } @@ -487,10 +630,21 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e, bool hasAggregateEvalKind = hasAggregateEvaluationKind(argType); - if (hasAggregateEvalKind) { - assert(!cir::MissingFeatures::opCallAggregateArgs()); - cgm.errorNYI(e->getSourceRange(), - "emitCallArg: aggregate function call argument"); + // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee. + // However, we still have to push an EH-only cleanup in case we unwind before + // we make it to the call. + if (argType->isRecordType() && + argType->castAs()->getDecl()->isParamDestroyedInCallee()) { + assert(!cir::MissingFeatures::msabi()); + cgm.errorNYI(e->getSourceRange(), "emitCallArg: msabi is NYI"); + } + + if (hasAggregateEvalKind && isa(e) && + cast(e)->getCastKind() == CK_LValueToRValue) { + LValue lv = emitLValue(cast(e)->getSubExpr()); + assert(lv.isSimple()); + args.addUncopiedAggregate(lv, argType); + return; } args.add(emitAnyExprToTemp(e), argType); @@ -511,12 +665,13 @@ QualType CIRGenFunction::getVarArgType(const Expr *arg) { /// Similar to emitAnyExpr(), however, the result will always be accessible /// even if no aggregate location is provided. RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) { - assert(!cir::MissingFeatures::opCallAggregateArgs()); + AggValueSlot aggSlot = AggValueSlot::ignored(); if (hasAggregateEvaluationKind(e->getType())) - cgm.errorNYI(e->getSourceRange(), "emit aggregate value to temp"); + aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()), + getCounterAggTmpAsString()); - return emitAnyExpr(e); + return emitAnyExpr(e, aggSlot); } void CIRGenFunction::emitCallArgs( diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h index 605625705a75..56c76c51a46d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -44,16 +44,25 @@ public: class CIRGenCallee { enum class SpecialKind : uintptr_t { Invalid, + Builtin, - Last = Invalid, + Last = Builtin, + }; + + struct BuiltinInfoStorage { + const clang::FunctionDecl *decl; + unsigned id; }; SpecialKind kindOrFunctionPtr; union { CIRGenCalleeInfo abstractInfo; + BuiltinInfoStorage builtinInfo; }; + explicit CIRGenCallee(SpecialKind kind) : kindOrFunctionPtr(kind) {} + public: CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {} @@ -69,6 +78,25 @@ public: return CIRGenCallee(abstractInfo, funcPtr); } + bool isBuiltin() const { return kindOrFunctionPtr == SpecialKind::Builtin; } + + const clang::FunctionDecl *getBuiltinDecl() const { + assert(isBuiltin()); + return builtinInfo.decl; + } + unsigned getBuiltinID() const { + assert(isBuiltin()); + return builtinInfo.id; + } + + static CIRGenCallee forBuiltin(unsigned builtinID, + const clang::FunctionDecl *builtinDecl) { + CIRGenCallee result(SpecialKind::Builtin); + result.builtinInfo.decl = builtinDecl; + result.builtinInfo.id = builtinID; + return result; + } + bool isOrdinary() const { return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last); } @@ -77,6 +105,12 @@ public: /// callee CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const; + CIRGenCalleeInfo getAbstractInfo() const { + assert(!cir::MissingFeatures::opCallVirtual()); + assert(isOrdinary()); + return abstractInfo; + } + mlir::Operation *getFunctionPointer() const { assert(isOrdinary()); return reinterpret_cast(kindOrFunctionPtr); @@ -105,8 +139,16 @@ public: CallArg(RValue rv, clang::QualType ty) : rv(rv), hasLV(false), isUsed(false), ty(ty) {} + CallArg(LValue lv, clang::QualType ty) + : lv(lv), hasLV(true), isUsed(false), ty(ty) {} + bool hasLValue() const { return hasLV; } + LValue getKnownLValue() const { + assert(hasLV && !isUsed); + return lv; + } + RValue getKnownRValue() const { assert(!hasLV && !isUsed); return rv; @@ -119,6 +161,10 @@ class CallArgList : public llvm::SmallVector { public: void add(RValue rvalue, clang::QualType type) { emplace_back(rvalue, type); } + void addUncopiedAggregate(LValue lvalue, clang::QualType type) { + emplace_back(lvalue, type); + } + /// Add all the arguments from another CallArgList to this one. After doing /// this, the old CallArgList retains its list of arguments, but must not /// be used to emit a call. @@ -134,7 +180,15 @@ public: /// Contains the address where the return value of a function can be stored, and /// whether the address is volatile or not. -class ReturnValueSlot {}; +class ReturnValueSlot { + Address addr = Address::invalid(); + +public: + ReturnValueSlot() = default; + ReturnValueSlot(Address addr) : addr(addr) {} + + Address getValue() const { return addr; } +}; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 8491a66ea6cb..e59a1fdb837c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -21,6 +21,125 @@ using namespace clang; using namespace clang::CIRGen; +/// Checks whether the given constructor is a valid subject for the +/// complete-to-base constructor delegation optimization, i.e. emitting the +/// complete constructor as a simple call to the base constructor. +bool CIRGenFunction::isConstructorDelegationValid( + const CXXConstructorDecl *ctor) { + // Currently we disable the optimization for classes with virtual bases + // because (1) the address of parameter variables need to be consistent across + // all initializers but (2) the delegate function call necessarily creates a + // second copy of the parameter variable. + // + // The limiting example (purely theoretical AFAIK): + // struct A { A(int &c) { c++; } }; + // struct A : virtual A { + // B(int count) : A(count) { printf("%d\n", count); } + // }; + // ...although even this example could in principle be emitted as a delegation + // since the address of the parameter doesn't escape. + if (ctor->getParent()->getNumVBases()) + return false; + + // We also disable the optimization for variadic functions because it's + // impossible to "re-pass" varargs. + if (ctor->getType()->castAs()->isVariadic()) + return false; + + // FIXME: Decide if we can do a delegation of a delegating constructor. + if (ctor->isDelegatingConstructor()) + return false; + + return true; +} + +/// This routine generates necessary code to initialize base classes and +/// non-static data members belonging to this constructor. +void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd, + CXXCtorType ctorType, + FunctionArgList &args) { + if (cd->isDelegatingConstructor()) + return emitDelegatingCXXConstructorCall(cd, args); + + if (cd->getNumCtorInitializers() != 0) { + // There's much more to do here. + cgm.errorNYI(cd->getSourceRange(), "emitCtorPrologue: any initializer"); + return; + } +} + +Address CIRGenFunction::loadCXXThisAddress() { + assert(curFuncDecl && "loading 'this' without a func declaration?"); + assert(isa(curFuncDecl)); + + // Lazily compute CXXThisAlignment. + if (cxxThisAlignment.isZero()) { + // Just use the best known alignment for the parent. + // TODO: if we're currently emitting a complete-object ctor/dtor, we can + // always use the complete-object alignment. + auto rd = cast(curFuncDecl)->getParent(); + cxxThisAlignment = cgm.getClassPointerAlignment(rd); + } + + return Address(loadCXXThis(), cxxThisAlignment); +} + +void CIRGenFunction::emitDelegateCXXConstructorCall( + const CXXConstructorDecl *ctor, CXXCtorType ctorType, + const FunctionArgList &args, SourceLocation loc) { + CallArgList delegateArgs; + + FunctionArgList::const_iterator i = args.begin(), e = args.end(); + assert(i != e && "no parameters to constructor"); + + // this + Address thisAddr = loadCXXThisAddress(); + delegateArgs.add(RValue::get(thisAddr.getPointer()), (*i)->getType()); + ++i; + + // FIXME: The location of the VTT parameter in the parameter list is specific + // to the Itanium ABI and shouldn't be hardcoded here. + if (cgm.getCXXABI().needsVTTParameter(curGD)) { + cgm.errorNYI(loc, "emitDelegateCXXConstructorCall: VTT parameter"); + return; + } + + // Explicit arguments. + for (; i != e; ++i) { + const VarDecl *param = *i; + // FIXME: per-argument source location + emitDelegateCallArg(delegateArgs, param, loc); + } + + assert(!cir::MissingFeatures::sanitizers()); + + emitCXXConstructorCall(ctor, ctorType, /*ForVirtualBase=*/false, + /*Delegating=*/true, thisAddr, delegateArgs, loc); +} + +void CIRGenFunction::emitDelegatingCXXConstructorCall( + const CXXConstructorDecl *ctor, const FunctionArgList &args) { + assert(ctor->isDelegatingConstructor()); + + Address thisPtr = loadCXXThisAddress(); + + assert(!cir::MissingFeatures::objCGC()); + assert(!cir::MissingFeatures::sanitizers()); + AggValueSlot aggSlot = AggValueSlot::forAddr( + thisPtr, Qualifiers(), AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, AggValueSlot::MayOverlap, + AggValueSlot::IsNotZeroed); + + emitAggExpr(ctor->init_begin()[0]->getInit(), aggSlot); + + const CXXRecordDecl *classDecl = ctor->getParent(); + if (cgm.getLangOpts().Exceptions && !classDecl->hasTrivialDestructor()) { + cgm.errorNYI(ctor->getSourceRange(), + "emitDelegatingCXXConstructorCall: exception"); + return; + } +} + Address CIRGenFunction::getAddressOfBaseClass( Address value, const CXXRecordDecl *derived, llvm::iterator_range path, diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 80b0172090aa..afbe92aded80 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -208,8 +208,25 @@ void CIRGenFunction::emitVarDecl(const VarDecl &d) { if (d.hasExternalStorage()) return; - if (d.getStorageDuration() != SD_Automatic) - cgm.errorNYI(d.getSourceRange(), "emitVarDecl automatic storage duration"); + if (d.getStorageDuration() != SD_Automatic) { + // Static sampler variables translated to function calls. + if (d.getType()->isSamplerT()) { + // Nothing needs to be done here, but let's flag it as an error until we + // have a test. It requires OpenCL support. + cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type"); + return; + } + + cir::GlobalLinkageKind linkage = + cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false); + + // FIXME: We need to force the emission/use of a guard variable for + // some variables even if we can constant-evaluate them because + // we can't guarantee every translation unit will constant-evaluate them. + + return emitStaticVarDecl(d, linkage); + } + if (d.getType().getAddressSpace() == LangAS::opencl_local) cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space"); @@ -219,6 +236,233 @@ void CIRGenFunction::emitVarDecl(const VarDecl &d) { return emitAutoVarDecl(d); } +static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) { + if (cgm.getLangOpts().CPlusPlus) + return cgm.getMangledName(&d).str(); + + // If this isn't C++, we don't need a mangled name, just a pretty one. + assert(!d.isExternallyVisible() && "name shouldn't matter"); + std::string contextName; + const DeclContext *dc = d.getDeclContext(); + if (auto *cd = dyn_cast(dc)) + dc = cast(cd->getNonClosureContext()); + if (const auto *fd = dyn_cast(dc)) + contextName = std::string(cgm.getMangledName(fd)); + else if (isa(dc)) + cgm.errorNYI(d.getSourceRange(), "block decl context for static var"); + else if (isa(dc)) + cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var"); + else + cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl"); + + contextName += "." + d.getNameAsString(); + return contextName; +} + +// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an +// interface for all constants? +cir::GlobalOp +CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d, + cir::GlobalLinkageKind linkage) { + // In general, we don't always emit static var decls once before we reference + // them. It is possible to reference them before emitting the function that + // contains them, and it is possible to emit the containing function multiple + // times. + if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d)) + return existingGV; + + QualType ty = d.getType(); + assert(ty->isConstantSizeType() && "VLAs can't be static"); + + // Use the label if the variable is renamed with the asm-label extension. + if (d.hasAttr()) + errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label"); + + std::string name = getStaticDeclName(*this, d); + + mlir::Type lty = getTypes().convertTypeForMem(ty); + assert(!cir::MissingFeatures::addressSpace()); + + if (d.hasAttr() || d.hasAttr()) + errorNYI(d.getSourceRange(), + "getOrCreateStaticVarDecl: LoaderUninitializedAttr"); + assert(!cir::MissingFeatures::addressSpace()); + + mlir::Attribute init = builder.getZeroInitAttr(convertType(ty)); + + cir::GlobalOp gv = builder.createVersionedGlobal( + getModule(), getLoc(d.getLocation()), name, lty, linkage); + // TODO(cir): infer visibility from linkage in global op builder. + gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage)); + gv.setInitialValueAttr(init); + gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value()); + + if (supportsCOMDAT() && gv.isWeakForLinker()) + gv.setComdat(true); + + assert(!cir::MissingFeatures::opGlobalThreadLocal()); + + setGVProperties(gv, &d); + + // OG checks if the expected address space, denoted by the type, is the + // same as the actual address space indicated by attributes. If they aren't + // the same, an addrspacecast is emitted when this variable is accessed. + // In CIR however, cir.get_global already carries that information in + // !cir.ptr type - if this global is in OpenCL local address space, then its + // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't + // need an explicit address space cast in CIR: they will get emitted when + // lowering to LLVM IR. + + // Ensure that the static local gets initialized by making sure the parent + // function gets emitted eventually. + const Decl *dc = cast(d.getDeclContext()); + + // We can't name blocks or captured statements directly, so try to emit their + // parents. + if (isa(dc) || isa(dc)) { + dc = dc->getNonClosureContext(); + // FIXME: Ensure that global blocks get emitted. + if (!dc) + errorNYI(d.getSourceRange(), "non-closure context"); + } + + GlobalDecl gd; + if (isa(dc)) + errorNYI(d.getSourceRange(), "C++ constructors static var context"); + else if (isa(dc)) + errorNYI(d.getSourceRange(), "C++ destructors static var context"); + else if (const auto *fd = dyn_cast(dc)) + gd = GlobalDecl(fd); + else { + // Don't do anything for Obj-C method decls or global closures. We should + // never defer them. + assert(isa(dc) && "unexpected parent code decl"); + } + if (gd.getDecl() && cir::MissingFeatures::openMP()) { + // Disable emission of the parent function for the OpenMP device codegen. + errorNYI(d.getSourceRange(), "OpenMP"); + } + + return gv; +} + +/// Add the initializer for 'd' to the global variable that has already been +/// created for it. If the initializer has a different type than gv does, this +/// may free gv and return a different one. Otherwise it just returns gv. +cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( + const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) { + ConstantEmitter emitter(*this); + mlir::TypedAttr init = + mlir::cast(emitter.tryEmitForInitializer(d)); + + // If constant emission failed, then this should be a C++ static + // initializer. + if (!init) { + cgm.errorNYI(d.getSourceRange(), "static var without initializer"); + return gv; + } + + // TODO(cir): There should be debug code here to assert that the decl size + // matches the CIR data layout type alloc size, but the code for calculating + // the type alloc size is not implemented yet. + assert(!cir::MissingFeatures::dataLayoutTypeAllocSize()); + + // The initializer may differ in type from the global. Rewrite + // the global to match the initializer. (We have to do this + // because some types, like unions, can't be completely represented + // in the LLVM type system.) + if (gv.getSymType() != init.getType()) { + gv.setSymType(init.getType()); + + // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv), + // but since at this point the current block hasn't been really attached, + // there's no visibility into the GetGlobalOp corresponding to this Global. + // Given those constraints, thread in the GetGlobalOp and update it + // directly. + assert(!cir::MissingFeatures::addressSpace()); + gvAddr.getAddr().setType(builder.getPointerTo(init.getType())); + } + + bool needsDtor = + d.needsDestruction(getContext()) == QualType::DK_cxx_destructor; + + assert(!cir::MissingFeatures::opGlobalConstant()); + gv.setInitialValueAttr(init); + + emitter.finalize(gv); + + if (needsDtor) { + // We have a constant initializer, but a nontrivial destructor. We still + // need to perform a guarded "initialization" in order to register the + // destructor. + cgm.errorNYI(d.getSourceRange(), "C++ guarded init"); + } + + return gv; +} + +void CIRGenFunction::emitStaticVarDecl(const VarDecl &d, + cir::GlobalLinkageKind linkage) { + // Check to see if we already have a global variable for this + // declaration. This can happen when double-emitting function + // bodies, e.g. with complete and base constructors. + cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage); + // TODO(cir): we should have a way to represent global ops as values without + // having to emit a get global op. Sometimes these emissions are not used. + mlir::Value addr = builder.createGetGlobal(globalOp); + auto getAddrOp = mlir::cast(addr.getDefiningOp()); + + CharUnits alignment = getContext().getDeclAlign(&d); + + // Store into LocalDeclMap before generating initializer to handle + // circular references. + mlir::Type elemTy = convertTypeForMem(d.getType()); + setAddrOfLocalVar(&d, Address(addr, elemTy, alignment)); + + // We can't have a VLA here, but we can have a pointer to a VLA, + // even though that doesn't really make any sense. + // Make sure to evaluate VLA bounds now so that we have them for later. + if (d.getType()->isVariablyModifiedType()) { + cgm.errorNYI(d.getSourceRange(), + "emitStaticVarDecl: variably modified type"); + } + + // Save the type in case adding the initializer forces a type change. + mlir::Type expectedType = addr.getType(); + + cir::GlobalOp var = globalOp; + + assert(!cir::MissingFeatures::cudaSupport()); + + // If this value has an initializer, emit it. + if (d.getInit()) + var = addInitializerToStaticVarDecl(d, var, getAddrOp); + + var.setAlignment(alignment.getAsAlign().value()); + + // There are a lot of attributes that need to be handled here. Until + // we start to support them, we just report an error if there are any. + if (d.hasAttrs()) + cgm.errorNYI(d.getSourceRange(), "static var with attrs"); + + if (cgm.getCodeGenOpts().KeepPersistentStorageVariables) + cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage"); + + // From traditional codegen: + // We may have to cast the constant because of the initializer + // mismatch above. + // + // FIXME: It is really dangerous to store this in the map; if anyone + // RAUW's the GV uses of this constant will be invalid. + mlir::Value castedAddr = + builder.createBitcast(getAddrOp.getAddr(), expectedType); + localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment); + cgm.setStaticLocalDeclAddress(&d, var); + + assert(!cir::MissingFeatures::sanitizers()); + assert(!cir::MissingFeatures::generateDebugInfo()); +} + void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit) { assert(!cir::MissingFeatures::objCLifetime()); @@ -255,11 +499,22 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d, emitScalarInit(init, getLoc(d->getSourceRange()), lvalue); return; case cir::TEK_Complex: { - cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: complex type"); + mlir::Value complex = emitComplexExpr(init); + if (capturedByInit) + cgm.errorNYI(init->getSourceRange(), + "emitExprAsInit: complex type captured by init"); + mlir::Location loc = getLoc(init->getExprLoc()); + emitStoreOfComplex(loc, complex, lvalue, + /*isInit*/ true); return; } case cir::TEK_Aggregate: - emitAggExpr(init, AggValueSlot::forLValue(lvalue)); + // The overlap flag here should be calculated. + assert(!cir::MissingFeatures::aggValueSlotMayOverlap()); + emitAggExpr(init, + AggValueSlot::forLValue(lvalue, AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, + AggValueSlot::MayOverlap)); return; } llvm_unreachable("bad evaluation kind"); @@ -344,8 +599,8 @@ void CIRGenFunction::emitDecl(const Decl &d) { // None of these decls require codegen support. return; - case Decl::Enum: // enum X; - case Decl::Record: // struct/union/class X; + case Decl::Enum: // enum X; + case Decl::Record: // struct/union/class X; case Decl::CXXRecord: // struct/union/class X; [C++] case Decl::NamespaceAlias: case Decl::Using: // using X; [C++] diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index f2c2de7a4f59..c31754dc11d6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -219,7 +219,7 @@ void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst, const mlir::Value vector = builder.createLoad(loc, dst.getVectorAddress()); const mlir::Value newVector = builder.create( - loc, vector, src.getScalarVal(), dst.getVectorIdx()); + loc, vector, src.getValue(), dst.getVectorIdx()); builder.createStore(loc, newVector, dst.getVectorAddress()); return; } @@ -232,7 +232,7 @@ void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst, assert(!cir::MissingFeatures::opLoadStoreObjC()); assert(src.isScalar() && "Can't emit an aggregate store with this method"); - emitStoreOfScalar(src.getScalarVal(), dst, isInit); + emitStoreOfScalar(src.getValue(), dst, isInit); } static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e, @@ -949,7 +949,7 @@ LValue CIRGenFunction::emitCallExprLValue(const CallExpr *e) { "Can't have a scalar return unless the return type is a " "reference type!"); - return makeNaturalAlignPointeeAddrLValue(rv.getScalarVal(), e->getType()); + return makeNaturalAlignPointeeAddrLValue(rv.getValue(), e->getType()); } LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { @@ -997,10 +997,9 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { } case cir::TEK_Complex: { - assert(!cir::MissingFeatures::complexType()); - cgm.errorNYI(e->getSourceRange(), "complex l-values"); - return {}; + return emitComplexAssignmentLValue(e); } + case cir::TEK_Aggregate: cgm.errorNYI(e->getSourceRange(), "aggregate lvalues"); return {}; @@ -1010,16 +1009,20 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { /// Emit code to compute the specified expression which /// can have any type. The result is returned as an RValue struct. -RValue CIRGenFunction::emitAnyExpr(const Expr *e) { +RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) { switch (CIRGenFunction::getEvaluationKind(e->getType())) { case cir::TEK_Scalar: return RValue::get(emitScalarExpr(e)); case cir::TEK_Complex: cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: complex type"); return RValue::get(nullptr); - case cir::TEK_Aggregate: - cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: aggregate type"); - return RValue::get(nullptr); + case cir::TEK_Aggregate: { + if (aggSlot.isIgnored()) + aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()), + getCounterAggTmpAsString()); + emitAggExpr(e, aggSlot); + return aggSlot.asRValue(); + } } llvm_unreachable("bad evaluation kind"); } @@ -1029,8 +1032,49 @@ static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) { return cgm.getAddrOfFunction(gd); } -static CIRGenCallee emitDirectCallee(CIRGenModule &cgm, GlobalDecl gd) { - assert(!cir::MissingFeatures::opCallBuiltinFunc()); +// Detect the unusual situation where an inline version is shadowed by a +// non-inline version. In that case we should pick the external one +// everywhere. That's GCC behavior too. +static bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *fd) { + for (const FunctionDecl *pd = fd; pd; pd = pd->getPreviousDecl()) + if (!pd->isInlineBuiltinDeclaration()) + return false; + return true; +} + +CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) { + const auto *fd = cast(gd.getDecl()); + + if (unsigned builtinID = fd->getBuiltinID()) { + if (fd->getAttr()) { + cgm.errorNYI("AsmLabelAttr"); + } + + StringRef ident = fd->getName(); + std::string fdInlineName = (ident + ".inline").str(); + + bool isPredefinedLibFunction = + cgm.getASTContext().BuiltinInfo.isPredefinedLibFunction(builtinID); + // Assume nobuiltins everywhere until we actually read the attributes. + bool hasAttributeNoBuiltin = true; + assert(!cir::MissingFeatures::attributeNoBuiltin()); + + // When directing calling an inline builtin, call it through it's mangled + // name to make it clear it's not the actual builtin. + auto fn = cast(curFn); + if (fn.getName() != fdInlineName && onlyHasInlineBuiltinDeclaration(fd)) { + cgm.errorNYI("Inline only builtin function calls"); + } + + // Replaceable builtins provide their own implementation of a builtin. If we + // are in an inline builtin implementation, avoid trivial infinite + // recursion. Honor __attribute__((no_builtin("foo"))) or + // __attribute__((no_builtin)) on the current function unless foo is + // not a predefined library function which means we must generate the + // builtin no matter what. + else if (!isPredefinedLibFunction || !hasAttributeNoBuiltin) + return CIRGenCallee::forBuiltin(builtinID, fd); + } cir::FuncOp callee = emitFunctionDeclPointer(cgm, gd); @@ -1106,7 +1150,7 @@ CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *e) { } else if (const auto *declRef = dyn_cast(e)) { // Resolve direct calls. const auto *funcDecl = cast(declRef->getDecl()); - return emitDirectCallee(cgm, funcDecl); + return emitDirectCallee(funcDecl); } else if (isa(e)) { cgm.errorNYI(e->getSourceRange(), "emitCallee: call to member function is NYI"); @@ -1162,10 +1206,9 @@ RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *e, CIRGenCallee callee = emitCallee(e->getCallee()); - if (e->getBuiltinCallee()) { - cgm.errorNYI(e->getSourceRange(), "call to builtin functions"); - } - assert(!cir::MissingFeatures::opCallBuiltinFunc()); + if (callee.isBuiltin()) + return emitBuiltinExpr(callee.getBuiltinDecl(), callee.getBuiltinID(), e, + returnValue); if (isa(e->getCallee())) { cgm.errorNYI(e->getSourceRange(), "call to pseudo destructor"); @@ -1222,6 +1265,23 @@ Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e) { return Address(ptr, addr.getAlignment()); } +/// Given the address of a temporary variable, produce an r-value of its type. +RValue CIRGenFunction::convertTempToRValue(Address addr, clang::QualType type, + clang::SourceLocation loc) { + LValue lvalue = makeAddrLValue(addr, type, AlignmentSource::Decl); + switch (getEvaluationKind(type)) { + case cir::TEK_Complex: + cgm.errorNYI(loc, "convertTempToRValue: complex type"); + return RValue::get(nullptr); + case cir::TEK_Aggregate: + cgm.errorNYI(loc, "convertTempToRValue: aggregate type"); + return RValue::get(nullptr); + case cir::TEK_Scalar: + return RValue::get(emitLoadOfScalar(lvalue, loc)); + } + llvm_unreachable("bad evaluation kind"); +} + /// Emit an `if` on a boolean condition, filling `then` and `else` into /// appropriated regions. mlir::LogicalResult CIRGenFunction::emitIfOnBoolExpr(const Expr *cond, @@ -1434,6 +1494,10 @@ void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, type = Ctor_Complete; break; case CXXConstructionKind::Delegating: + // We should be emitting a constructor; GlobalDecl will assert this + type = curGD.getCtorType(); + delegating = true; + break; case CXXConstructionKind::VirtualBase: case CXXConstructionKind::NonVirtualBase: cgm.errorNYI(e->getSourceRange(), @@ -1625,3 +1689,14 @@ mlir::Value CIRGenFunction::emitScalarConstant( } return builder.getConstant(getLoc(e->getSourceRange()), constant.getValue()); } + +/// An LValue is a candidate for having its loads and stores be made atomic if +/// we are operating under /volatile:ms *and* the LValue itself is volatile and +/// performing such an operation can be performed without a libcall. +bool CIRGenFunction::isLValueSuitableForInlineAtomic(LValue lv) { + if (!cgm.getLangOpts().MSVolatile) + return false; + + cgm.errorNYI("LValueSuitableForInlineAtomic LangOpts MSVolatile"); + return false; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index f1df1b79fc48..ffe1b701b244 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -28,6 +28,15 @@ class AggExprEmitter : public StmtVisitor { CIRGenFunction &cgf; AggValueSlot dest; + // Calls `fn` with a valid return value slot, potentially creating a temporary + // to do so. If a temporary is created, an appropriate copy into `Dest` will + // be emitted, as will lifetime markers. + // + // The given function should take a ReturnValueSlot, and return an RValue that + // points to said slot. + void withReturnValueSlot(const Expr *e, + llvm::function_ref fn); + AggValueSlot ensureSlot(mlir::Location loc, QualType t) { if (!dest.isIgnored()) return dest; @@ -40,16 +49,28 @@ public: AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest) : cgf(cgf), dest(dest) {} + /// Given an expression with aggregate type that represents a value lvalue, + /// this method emits the address of the lvalue, then loads the result into + /// DestPtr. + void emitAggLoadOfLValue(const Expr *e); + void emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy, Expr *exprToVisit, ArrayRef args, Expr *arrayFiller); + /// Perform the final copy to DestPtr, if desired. + void emitFinalDestCopy(QualType type, const LValue &src); + void emitInitializationToLValue(Expr *e, LValue lv); void emitNullInitializationToLValue(mlir::Location loc, LValue lv); void Visit(Expr *e) { StmtVisitor::Visit(e); } + void VisitCallExpr(const CallExpr *e); + + void VisitDeclRefExpr(DeclRefExpr *e) { emitAggLoadOfLValue(e); } + void VisitInitListExpr(InitListExpr *e); void VisitCXXConstructExpr(const CXXConstructExpr *e); @@ -80,6 +101,17 @@ static bool isTrivialFiller(Expr *e) { return false; } +/// Given an expression with aggregate type that represents a value lvalue, this +/// method emits the address of the lvalue, then loads the result into DestPtr. +void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) { + LValue lv = cgf.emitLValue(e); + + // If the type of the l-value is atomic, then do an atomic load. + assert(!cir::MissingFeatures::opLoadStoreAtomic()); + + emitFinalDestCopy(e->getType(), lv); +} + void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy, Expr *e, ArrayRef args, Expr *arrayFiller) { @@ -182,6 +214,18 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, } } +/// Perform the final copy to destPtr, if desired. +void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) { + // If dest is ignored, then we're evaluating an aggregate expression + // in a context that doesn't care about the result. Note that loads + // from volatile l-values force the existence of a non-ignored + // destination. + if (dest.isIgnored()) + return; + + cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI"); +} + void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) { const QualType type = lv.getType(); @@ -203,7 +247,11 @@ void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) { cgf.cgm.errorNYI("emitInitializationToLValue TEK_Complex"); break; case cir::TEK_Aggregate: - cgf.emitAggExpr(e, AggValueSlot::forLValue(lv)); + cgf.emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, + AggValueSlot::MayOverlap, + dest.isZeroed())); + return; case cir::TEK_Scalar: if (lv.isSimple()) @@ -246,6 +294,44 @@ void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc, cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType()); } +void AggExprEmitter::VisitCallExpr(const CallExpr *e) { + if (e->getCallReturnType(cgf.getContext())->isReferenceType()) { + cgf.cgm.errorNYI(e->getSourceRange(), "reference return type"); + return; + } + + withReturnValueSlot( + e, [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, slot); }); +} + +void AggExprEmitter::withReturnValueSlot( + const Expr *e, llvm::function_ref fn) { + QualType retTy = e->getType(); + + assert(!cir::MissingFeatures::aggValueSlotDestructedFlag()); + bool requiresDestruction = + retTy.isDestructedType() == QualType::DK_nontrivial_c_struct; + if (requiresDestruction) + cgf.cgm.errorNYI( + e->getSourceRange(), + "withReturnValueSlot: return value requiring destruction is NYI"); + + // If it makes no observable difference, save a memcpy + temporary. + // + // We need to always provide our own temporary if destruction is required. + // Otherwise, fn will emit its own, notice that it's "unused", and end its + // lifetime before we have the chance to emit a proper destructor call. + assert(!cir::MissingFeatures::aggValueSlotAlias()); + assert(!cir::MissingFeatures::aggValueSlotGC()); + + Address retAddr = dest.getAddress(); + assert(!cir::MissingFeatures::emitLifetimeMarkers()); + + assert(!cir::MissingFeatures::aggValueSlotVolatile()); + assert(!cir::MissingFeatures::aggValueSlotDestructedFlag()); + fn(ReturnValueSlot(retAddr)); +} + void AggExprEmitter::VisitInitListExpr(InitListExpr *e) { if (e->hadArrayRangeDesignator()) llvm_unreachable("GNU array range designator extension"); @@ -284,6 +370,8 @@ LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) { assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!"); Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange())); LValue lv = makeAddrLValue(temp, e->getType()); - emitAggExpr(e, AggValueSlot::forLValue(lv)); + emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsNotDestructed, + AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap)); return lv; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp new file mode 100644 index 000000000000..eaa199abc165 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -0,0 +1,228 @@ +#include "CIRGenBuilder.h" +#include "CIRGenFunction.h" + +#include "clang/AST/StmtVisitor.h" + +using namespace clang; +using namespace clang::CIRGen; + +namespace { +class ComplexExprEmitter : public StmtVisitor { + CIRGenFunction &cgf; + CIRGenBuilderTy &builder; + +public: + explicit ComplexExprEmitter(CIRGenFunction &cgf) + : cgf(cgf), builder(cgf.getBuilder()) {} + + //===--------------------------------------------------------------------===// + // Utilities + //===--------------------------------------------------------------------===// + + LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val); + + mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy); + + mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant, + Expr *e); + + /// Given an expression with complex type that represents a value l-value, + /// this method emits the address of the l-value, then loads and returns the + /// result. + mlir::Value emitLoadOfLValue(const Expr *e) { + return emitLoadOfLValue(cgf.emitLValue(e), e->getExprLoc()); + } + + mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc); + /// Store the specified real/imag parts into the + /// specified value pointer. + void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv, + bool isInit); + + mlir::Value VisitBinAssign(const BinaryOperator *e); + mlir::Value VisitCallExpr(const CallExpr *e); + mlir::Value VisitDeclRefExpr(DeclRefExpr *e); + mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e); + mlir::Value VisitInitListExpr(const InitListExpr *e); + mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il); +}; +} // namespace + +static const ComplexType *getComplexType(QualType type) { + type = type.getCanonicalType(); + if (const ComplexType *comp = dyn_cast(type)) + return comp; + return cast(cast(type)->getValueType()); +} + +LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, + mlir::Value &value) { + assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(), + e->getRHS()->getType()) && + "Invalid assignment"); + + // Emit the RHS. __block variables need the RHS evaluated first. + value = Visit(e->getRHS()); + + // Compute the address to store into. + LValue lhs = cgf.emitLValue(e->getLHS()); + + // Store the result value into the LHS lvalue. + emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, /*isInit*/ false); + return lhs; +} + +mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, + QualType destTy) { + switch (ck) { + case CK_LValueToRValue: + return Visit(op); + default: + cgf.cgm.errorNYI("ComplexType Cast"); + break; + } + return {}; +} + +mlir::Value ComplexExprEmitter::emitConstant( + const CIRGenFunction::ConstantEmission &constant, Expr *e) { + assert(constant && "not a constant"); + if (constant.isReference()) + return emitLoadOfLValue(constant.getReferenceLValue(cgf, e), + e->getExprLoc()); + + mlir::TypedAttr valueAttr = constant.getValue(); + return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr); +} + +mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv, + SourceLocation loc) { + assert(lv.isSimple() && "non-simple complex l-value?"); + if (lv.getType()->isAtomicType()) + cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV"); + + const Address srcAddr = lv.getAddress(); + return builder.createLoad(cgf.getLoc(loc), srcAddr); +} + +void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, + LValue lv, bool isInit) { + if (lv.getType()->isAtomicType() || + (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) { + cgf.cgm.errorNYI(loc, "StoreOfComplex with Atomic LV"); + return; + } + + const Address destAddr = lv.getAddress(); + builder.createStore(loc, val, destAddr); +} + +mlir::Value ComplexExprEmitter::VisitBinAssign(const BinaryOperator *e) { + mlir::Value value; + LValue lv = emitBinAssignLValue(e, value); + + // The result of an assignment in C is the assigned r-value. + if (!cgf.getLangOpts().CPlusPlus) + return value; + + // If the lvalue is non-volatile, return the computed value of the + // assignment. + if (!lv.isVolatile()) + return value; + + return emitLoadOfLValue(lv, e->getExprLoc()); +} + +mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) { + if (e->getCallReturnType(cgf.getContext())->isReferenceType()) + return emitLoadOfLValue(e); + + return cgf.emitCallExpr(e).getValue(); +} + +mlir::Value ComplexExprEmitter::VisitDeclRefExpr(DeclRefExpr *e) { + if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e)) + return emitConstant(constant, e); + return emitLoadOfLValue(e); +} + +mlir::Value ComplexExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *e) { + // Unlike for scalars, we don't have to worry about function->ptr demotion + // here. + if (e->changesVolatileQualification()) + return emitLoadOfLValue(e); + return emitCast(e->getCastKind(), e->getSubExpr(), e->getType()); +} + +mlir::Value ComplexExprEmitter::VisitInitListExpr(const InitListExpr *e) { + mlir::Location loc = cgf.getLoc(e->getExprLoc()); + if (e->getNumInits() == 2) { + mlir::Value real = cgf.emitScalarExpr(e->getInit(0)); + mlir::Value imag = cgf.emitScalarExpr(e->getInit(1)); + return builder.createComplexCreate(loc, real, imag); + } + + if (e->getNumInits() == 1) { + cgf.cgm.errorNYI("Create Complex with InitList with size 1"); + return {}; + } + + assert(e->getNumInits() == 0 && "Unexpected number of inits"); + QualType complexElemTy = + e->getType()->castAs()->getElementType(); + mlir::Type complexElemLLVMTy = cgf.convertType(complexElemTy); + mlir::TypedAttr defaultValue = builder.getZeroInitAttr(complexElemLLVMTy); + auto complexAttr = cir::ConstComplexAttr::get(defaultValue, defaultValue); + return builder.create(loc, complexAttr); +} + +mlir::Value +ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) { + auto ty = mlir::cast(cgf.convertType(il->getType())); + mlir::Type elementTy = ty.getElementType(); + mlir::Location loc = cgf.getLoc(il->getExprLoc()); + + mlir::TypedAttr realValueAttr; + mlir::TypedAttr imagValueAttr; + + if (mlir::isa(elementTy)) { + llvm::APInt imagValue = cast(il->getSubExpr())->getValue(); + realValueAttr = cir::IntAttr::get(elementTy, 0); + imagValueAttr = cir::IntAttr::get(elementTy, imagValue); + } else { + assert(mlir::isa(elementTy) && + "Expected complex element type to be floating-point"); + + llvm::APFloat imagValue = + cast(il->getSubExpr())->getValue(); + realValueAttr = cir::FPAttr::get( + elementTy, llvm::APFloat::getZero(imagValue.getSemantics())); + imagValueAttr = cir::FPAttr::get(elementTy, imagValue); + } + + auto complexAttr = cir::ConstComplexAttr::get(realValueAttr, imagValueAttr); + return builder.create(loc, complexAttr); +} + +LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { + assert(e->getOpcode() == BO_Assign && "Expected assign op"); + + mlir::Value value; // ignored + LValue lvalue = ComplexExprEmitter(*this).emitBinAssignLValue(e, value); + if (getLangOpts().OpenMP) + cgm.errorNYI("emitComplexAssignmentLValue OpenMP"); + + return lvalue; +} + +mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) { + assert(e && getComplexType(e->getType()) && + "Invalid complex expression to emit"); + + return ComplexExprEmitter(*this).Visit(const_cast(e)); +} + +void CIRGenFunction::emitStoreOfComplex(mlir::Location loc, mlir::Value v, + LValue dest, bool isInit) { + ComplexExprEmitter(*this).emitStoreOfComplex(loc, v, dest, isInit); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index c41ab54be09c..8b817f3f3d8d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -254,8 +254,8 @@ public: } mlir::Attribute VisitStringLiteral(StringLiteral *e, QualType t) { - cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitStringLiteral"); - return {}; + // This is a string literal initializing an array in an initializer. + return cgm.getConstantArrayFromStringLiteral(e); } mlir::Attribute VisitObjCEncodeExpr(ObjCEncodeExpr *e, QualType t) { @@ -329,6 +329,222 @@ emitArrayConstant(CIRGenModule &cgm, mlir::Type desiredType, return {}; } +//===----------------------------------------------------------------------===// +// ConstantLValueEmitter +//===----------------------------------------------------------------------===// + +namespace { +/// A struct which can be used to peephole certain kinds of finalization +/// that normally happen during l-value emission. +struct ConstantLValue { + llvm::PointerUnion value; + bool hasOffsetApplied; + + ConstantLValue(std::nullptr_t) : value(nullptr), hasOffsetApplied(false) {} + ConstantLValue() : value(nullptr), hasOffsetApplied(false) {} +}; + +/// A helper class for emitting constant l-values. +class ConstantLValueEmitter + : public ConstStmtVisitor { + CIRGenModule &cgm; + ConstantEmitter &emitter; + const APValue &value; + QualType destType; + + // Befriend StmtVisitorBase so that we don't have to expose Visit*. + friend StmtVisitorBase; + +public: + ConstantLValueEmitter(ConstantEmitter &emitter, const APValue &value, + QualType destType) + : cgm(emitter.cgm), emitter(emitter), value(value), destType(destType) {} + + mlir::Attribute tryEmit(); + +private: + mlir::Attribute tryEmitAbsolute(mlir::Type destTy); + ConstantLValue tryEmitBase(const APValue::LValueBase &base); + + ConstantLValue VisitStmt(const Stmt *s) { return nullptr; } + ConstantLValue VisitConstantExpr(const ConstantExpr *e); + ConstantLValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *e); + ConstantLValue VisitStringLiteral(const StringLiteral *e); + ConstantLValue VisitObjCBoxedExpr(const ObjCBoxedExpr *e); + ConstantLValue VisitObjCEncodeExpr(const ObjCEncodeExpr *e); + ConstantLValue VisitObjCStringLiteral(const ObjCStringLiteral *e); + ConstantLValue VisitPredefinedExpr(const PredefinedExpr *e); + ConstantLValue VisitAddrLabelExpr(const AddrLabelExpr *e); + ConstantLValue VisitCallExpr(const CallExpr *e); + ConstantLValue VisitBlockExpr(const BlockExpr *e); + ConstantLValue VisitCXXTypeidExpr(const CXXTypeidExpr *e); + ConstantLValue + VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *e); +}; + +} // namespace + +mlir::Attribute ConstantLValueEmitter::tryEmit() { + const APValue::LValueBase &base = value.getLValueBase(); + + // The destination type should be a pointer or reference + // type, but it might also be a cast thereof. + // + // FIXME: the chain of casts required should be reflected in the APValue. + // We need this in order to correctly handle things like a ptrtoint of a + // non-zero null pointer and addrspace casts that aren't trivially + // represented in LLVM IR. + mlir::Type destTy = cgm.getTypes().convertTypeForMem(destType); + assert(mlir::isa(destTy)); + + // If there's no base at all, this is a null or absolute pointer, + // possibly cast back to an integer type. + if (!base) + return tryEmitAbsolute(destTy); + + // Otherwise, try to emit the base. + ConstantLValue result = tryEmitBase(base); + + // If that failed, we're done. + llvm::PointerUnion &value = result.value; + if (!value) + return {}; + + // Apply the offset if necessary and not already done. + if (!result.hasOffsetApplied) { + cgm.errorNYI("ConstantLValueEmitter: apply offset"); + return {}; + } + + // Convert to the appropriate type; this could be an lvalue for + // an integer. FIXME: performAddrSpaceCast + if (mlir::isa(destTy)) { + if (auto attr = mlir::dyn_cast(value)) + return attr; + cgm.errorNYI("ConstantLValueEmitter: non-attribute pointer"); + return {}; + } + + cgm.errorNYI("ConstantLValueEmitter: other?"); + return {}; +} + +/// Try to emit an absolute l-value, such as a null pointer or an integer +/// bitcast to pointer type. +mlir::Attribute ConstantLValueEmitter::tryEmitAbsolute(mlir::Type destTy) { + // If we're producing a pointer, this is easy. + auto destPtrTy = mlir::cast(destTy); + return cgm.getBuilder().getConstPtrAttr( + destPtrTy, value.getLValueOffset().getQuantity()); +} + +ConstantLValue +ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { + // Handle values. + if (const ValueDecl *d = base.dyn_cast()) { + // The constant always points to the canonical declaration. We want to look + // at properties of the most recent declaration at the point of emission. + d = cast(d->getMostRecentDecl()); + + if (d->hasAttr()) { + cgm.errorNYI(d->getSourceRange(), + "ConstantLValueEmitter: emit pointer base for weakref"); + return {}; + } + + if (auto *fd = dyn_cast(d)) { + cgm.errorNYI(fd->getSourceRange(), + "ConstantLValueEmitter: function decl"); + return {}; + } + + if (auto *vd = dyn_cast(d)) { + cgm.errorNYI(vd->getSourceRange(), "ConstantLValueEmitter: var decl"); + return {}; + } + } + + // Handle typeid(T). + if (base.dyn_cast()) { + cgm.errorNYI("ConstantLValueEmitter: typeid"); + return {}; + } + + // Otherwise, it must be an expression. + return Visit(base.get()); +} + +ConstantLValue ConstantLValueEmitter::VisitConstantExpr(const ConstantExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: constant expr"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: compound literal"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitStringLiteral(const StringLiteral *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: string literal"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: objc encode expr"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitObjCStringLiteral(const ObjCStringLiteral *e) { + cgm.errorNYI(e->getSourceRange(), + "ConstantLValueEmitter: objc string literal"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitObjCBoxedExpr(const ObjCBoxedExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: objc boxed expr"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitPredefinedExpr(const PredefinedExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: predefined expr"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitAddrLabelExpr(const AddrLabelExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: addr label expr"); + return {}; +} + +ConstantLValue ConstantLValueEmitter::VisitCallExpr(const CallExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: call expr"); + return {}; +} + +ConstantLValue ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: block expr"); + return {}; +} + +ConstantLValue +ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *e) { + cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: cxx typeid expr"); + return {}; +} + +ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *e) { + cgm.errorNYI(e->getSourceRange(), + "ConstantLValueEmitter: materialize temporary expr"); + return {}; +} + //===----------------------------------------------------------------------===// // ConstantEmitter //===----------------------------------------------------------------------===// @@ -556,23 +772,8 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value, cgm.errorNYI("ConstExprEmitter::tryEmitPrivate member pointer"); return {}; } - case APValue::LValue: { - - if (value.getLValueBase()) { - cgm.errorNYI("non-null pointer initialization"); - } else { - - mlir::Type desiredType = cgm.convertType(destType); - if (const cir::PointerType ptrType = - mlir::dyn_cast(desiredType)) { - return builder.getConstPtrAttr(ptrType, - value.getLValueOffset().getQuantity()); - } else { - llvm_unreachable("non-pointer variable initialized with a pointer"); - } - } - return {}; - } + case APValue::LValue: + return ConstantLValueEmitter(*this, value, destType).tryEmit(); case APValue::Struct: case APValue::Union: cgm.errorNYI("ConstExprEmitter::tryEmitPrivate struct or union"); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 481eb492d187..8d0db5cd0a1e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -131,11 +131,11 @@ public: mlir::Value emitLoadOfLValue(const Expr *e) { LValue lv = cgf.emitLValue(e); // FIXME: add some akin to EmitLValueAlignmentAssumption(E, V); - return cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal(); + return cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue(); } mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) { - return cgf.emitLoadOfLValue(lv, loc).getScalarVal(); + return cgf.emitLoadOfLValue(lv, loc).getValue(); } // l-values @@ -162,6 +162,12 @@ public: builder.getAttr(type, e->getValue())); } + mlir::Value VisitCharacterLiteral(const CharacterLiteral *e) { + mlir::Type ty = cgf.convertType(e->getType()); + auto init = cir::IntAttr::get(ty, e->getValue()); + return builder.create(cgf.getLoc(e->getExprLoc()), init); + } + mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) { return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc())); } @@ -346,8 +352,8 @@ public: assert(!cir::MissingFeatures::fpConstraints()); castKind = cir::CastKind::float_to_int; } else if (mlir::isa(dstTy)) { - cgf.getCIRGenModule().errorNYI("floating point casts"); - return cgf.createDummyValue(src.getLoc(), dstType); + // TODO: split this to createFPExt/createFPTrunc + return builder.createFloatingCast(src, fullDstTy); } else { llvm_unreachable("Internal error: Cast to unexpected type"); } @@ -394,10 +400,10 @@ public: cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec"); // TODO(cir): This is not correct, but it will produce reasonable code // until atomic operations are implemented. - value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal(); + value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue(); input = value; } else { - value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal(); + value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue(); input = value; } @@ -1780,6 +1786,14 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { cgf.convertType(destTy)); } + case CK_VectorSplat: { + // Create a vector object and fill all elements with the same scalar value. + assert(destTy->isVectorType() && "CK_VectorSplat to non-vector type"); + return builder.create( + cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy), + Visit(subExpr)); + } + default: cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(), "CastExpr: ", ce->getCastKindName()); @@ -1791,7 +1805,7 @@ mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) { if (e->getCallReturnType(cgf.getContext())->isReferenceType()) return emitLoadOfLValue(e); - auto v = cgf.emitCallExpr(e).getScalarVal(); + auto v = cgf.emitCallExpr(e).getValue(); assert(!cir::MissingFeatures::emitLValueAlignmentAssumption()); return v; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index e32a5c836be0..fd413fe86383 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -465,7 +465,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, if (isa(funcDecl)) getCIRGenModule().errorNYI(bodyRange, "C++ destructor definition"); else if (isa(funcDecl)) - getCIRGenModule().errorNYI(bodyRange, "C++ constructor definition"); + emitConstructorBody(args); else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && funcDecl->hasAttr()) getCIRGenModule().errorNYI(bodyRange, "CUDA kernel"); @@ -496,6 +496,48 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, return fn; } +void CIRGenFunction::emitConstructorBody(FunctionArgList &args) { + assert(!cir::MissingFeatures::sanitizers()); + const auto *ctor = cast(curGD.getDecl()); + CXXCtorType ctorType = curGD.getCtorType(); + + assert((cgm.getTarget().getCXXABI().hasConstructorVariants() || + ctorType == Ctor_Complete) && + "can only generate complete ctor for this ABI"); + + if (ctorType == Ctor_Complete && isConstructorDelegationValid(ctor) && + cgm.getTarget().getCXXABI().hasConstructorVariants()) { + emitDelegateCXXConstructorCall(ctor, Ctor_Base, args, ctor->getEndLoc()); + return; + } + + const FunctionDecl *definition = nullptr; + Stmt *body = ctor->getBody(definition); + assert(definition == ctor && "emitting wrong constructor body"); + + if (isa_and_nonnull(body)) { + cgm.errorNYI(ctor->getSourceRange(), "emitConstructorBody: try body"); + return; + } + + assert(!cir::MissingFeatures::incrementProfileCounter()); + assert(!cir::MissingFeatures::runCleanupsScope()); + + // TODO: in restricted cases, we can emit the vbase initializers of a + // complete ctor and then delegate to the base ctor. + + // Emit the constructor prologue, i.e. the base and member initializers. + emitCtorPrologue(ctor, ctorType, args); + + // TODO(cir): propagate this result via mlir::logical result. Just unreachable + // now just to have it handled. + if (mlir::failed(emitStmt(body, true))) { + cgm.errorNYI(ctor->getSourceRange(), + "emitConstructorBody: emit body statement failed."); + return; + } +} + /// Given a value of type T* that may not be to a complete object, construct /// an l-vlaue withi the natural pointee alignment of T. LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val, @@ -522,16 +564,16 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd, cgm.getCXXABI().buildThisParam(*this, args); } - if (isa(fd)) - cgm.errorNYI(fd->getSourceRange(), - "buildFunctionArgList: CXXConstructorDecl"); + if (const auto *cd = dyn_cast(fd)) + if (cd->getInheritedConstructor()) + cgm.errorNYI(fd->getSourceRange(), + "buildFunctionArgList: inherited constructor"); for (auto *param : fd->parameters()) args.push_back(param); if (md && (isa(md) || isa(md))) - cgm.errorNYI(fd->getSourceRange(), - "buildFunctionArgList: implicit structor params"); + assert(!cir::MissingFeatures::cxxabiStructorImplicitParam()); return retTy; } @@ -587,6 +629,17 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { } } +static std::string getVersionedTmpName(llvm::StringRef name, unsigned cnt) { + SmallString<256> buffer; + llvm::raw_svector_ostream out(buffer); + out << name << cnt; + return std::string(out.str()); +} + +std::string CIRGenFunction::getCounterAggTmpAsString() { + return getVersionedTmpName("agg.tmp", counterAggTmp++); +} + void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty) { // Ignore empty classes in C++. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 7db7f6928fd8..82aa7ec9cb22 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -34,6 +34,12 @@ namespace { class ScalarExprEmitter; } // namespace +namespace mlir { +namespace acc { +class LoopOp; +} // namespace acc +} // namespace mlir + namespace clang::CIRGen { class CIRGenFunction : public CIRGenTypeCache { @@ -60,6 +66,7 @@ public: ImplicitParamDecl *cxxabiThisDecl = nullptr; mlir::Value cxxabiThisValue = nullptr; mlir::Value cxxThisValue = nullptr; + clang::CharUnits cxxThisAlignment; // Holds the Decl for the current outermost non-closure context const clang::Decl *curFuncDecl = nullptr; @@ -309,6 +316,10 @@ public: ~SourceLocRAIIObject() { restore(); } }; + /// Hold counters for incrementally naming temporaries + unsigned counterAggTmp = 0; + std::string getCounterAggTmpAsString(); + /// Helpers to convert Clang's SourceLocation to a MLIR Location. mlir::Location getLoc(clang::SourceLocation srcLoc); mlir::Location getLoc(clang::SourceRange srcLoc); @@ -327,6 +338,8 @@ public: PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {} }; + bool isLValueSuitableForInlineAtomic(LValue lv); + /// An abstract representation of regular/ObjC call/message targets. class AbstractCallee { /// The function declaration of the callee. @@ -458,6 +471,10 @@ public: /// compare the result against zero, returning an Int1Ty value. mlir::Value evaluateExprAsBool(const clang::Expr *e); + cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d, + cir::GlobalOp gv, + cir::GetGlobalOp gvAddr); + /// Set the address of a local variable. void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) { assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!"); @@ -467,6 +484,12 @@ public: bool shouldNullCheckClassCastValue(const CastExpr *ce); + RValue convertTempToRValue(Address addr, clang::QualType type, + clang::SourceLocation loc); + + static bool + isConstructorDelegationValid(const clang::CXXConstructorDecl *ctor); + LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t); /// Construct an address with the natural alignment of T. If a pointer to T @@ -511,6 +534,7 @@ public: assert(cxxThisValue && "no 'this' value for this function"); return cxxThisValue; } + Address loadCXXThisAddress(); /// Get an appropriate 'undef' rvalue for the given type. /// TODO: What's the equivalent for MLIR? Currently we're only using this for @@ -665,6 +689,8 @@ private: void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc, clang::CharUnits alignment); + CIRGenCallee emitDirectCallee(const GlobalDecl &gd); + public: Address emitAddrOfFieldStorage(Address base, const FieldDecl *field, llvm::StringRef fieldName, @@ -679,6 +705,8 @@ public: mlir::OpBuilder::InsertPoint ip, mlir::Value arraySize = nullptr); + void emitAggregateStore(mlir::Value value, Address dest); + void emitAggExpr(const clang::Expr *e, AggValueSlot slot); LValue emitAggExprToLValue(const Expr *e); @@ -687,7 +715,8 @@ public: /// result is returned as an RValue struct. If this is an aggregate /// expression, the aggloc/agglocvolatile arguments indicate where the result /// should be returned. - RValue emitAnyExpr(const clang::Expr *e); + RValue emitAnyExpr(const clang::Expr *e, + AggValueSlot aggSlot = AggValueSlot::ignored()); /// Similarly to emitAnyExpr(), however, the result will always be accessible /// even if no aggregate location is provided. @@ -711,6 +740,9 @@ public: mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s); + RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID, + const clang::CallExpr *e, ReturnValueSlot returnValue); + RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, @@ -740,8 +772,14 @@ public: LValue emitCastLValue(const CastExpr *e); + /// Emits an argument for a call to a `__builtin_assume`. If the builtin + /// sanitizer is enabled, a runtime check is also emitted. + mlir::Value emitCheckedArgForAssume(const Expr *e); + LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e); + void emitConstructorBody(FunctionArgList &args); + mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s); void emitCXXConstructExpr(const clang::CXXConstructExpr *e, @@ -779,6 +817,16 @@ public: const CXXMethodDecl *md, ReturnValueSlot returnValue); + void emitCtorPrologue(const clang::CXXConstructorDecl *ctor, + clang::CXXCtorType ctorType, FunctionArgList &args); + + // It's important not to confuse this and emitDelegateCXXConstructorCall. + // Delegating constructors are the C++11 feature. The constructor delegate + // optimization is used to reduce duplication in the base and complete + // constructors where they are substantially the same. + void emitDelegatingCXXConstructorCall(const CXXConstructorDecl *ctor, + const FunctionArgList &args); + mlir::LogicalResult emitDoStmt(const clang::DoStmt &s); /// Emit an expression as an initializer for an object (variable, field, etc.) @@ -818,6 +866,12 @@ public: mlir::LogicalResult emitForStmt(const clang::ForStmt &s); + /// Emit the computation of the specified expression of complex type, + /// returning the result. + mlir::Value emitComplexExpr(const Expr *e); + + LValue emitComplexAssignmentLValue(const BinaryOperator *e); + void emitCompoundStmt(const clang::CompoundStmt &s); void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); @@ -830,6 +884,17 @@ public: mlir::Type condType, bool buildingTopLevelCase); + void emitDelegateCXXConstructorCall(const clang::CXXConstructorDecl *ctor, + clang::CXXCtorType ctorType, + const FunctionArgList &args, + clang::SourceLocation loc); + + /// We are performing a delegate call; that is, the current function is + /// delegating to another one. Produce a r-value suitable for passing the + /// given parameter. + void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param, + clang::SourceLocation loc); + /// Emit an `if` on a boolean condition to the specified blocks. /// FIXME: Based on the condition, this might try to simplify the codegen of /// the conditional based on the branch. @@ -906,6 +971,11 @@ public: void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit = false); + void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage); + + void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, + bool isInit); + void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, bool isInit = false, bool isNontemporal = false); @@ -1077,6 +1147,12 @@ private: OpenACCDirectiveKind dirKind, SourceLocation dirLoc, ArrayRef clauses); + // The OpenACC LoopOp requires that we have auto, seq, or independent on all + // LoopOp operations for the 'none' device type case. This function checks if + // the LoopOp has one, else it updates it to have one. + void updateLoopOpParallelism(mlir::acc::LoopOp &op, bool isOrphan, + OpenACCDirectiveKind dk); + public: mlir::LogicalResult emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s); @@ -1104,6 +1180,17 @@ public: void emitOpenACCDeclare(const OpenACCDeclareDecl &d); void emitOpenACCRoutine(const OpenACCRoutineDecl &d); + /// Create a temporary memory object for the given aggregate type. + AggValueSlot createAggTemp(QualType ty, mlir::Location loc, + const Twine &name = "tmp", + Address *alloca = nullptr) { + assert(!cir::MissingFeatures::aggValueSlot()); + return AggValueSlot::forAddr( + createMemTemp(ty, loc, name, alloca), ty.getQualifiers(), + AggValueSlot::IsNotDestructed, AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap); + } + private: QualType getVarArgType(const Expr *arg); }; diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index fdd8b63fb6da..cd9096a0188a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -20,7 +20,9 @@ #include "CIRGenCXXABI.h" #include "CIRGenFunction.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/GlobalDecl.h" +#include "clang/CIR/MissingFeatures.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -35,8 +37,13 @@ public: assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI()); } - void emitInstanceFunctionProlog(SourceLocation Loc, - CIRGenFunction &CGF) override; + bool needsVTTParameter(clang::GlobalDecl gd) override; + + void emitInstanceFunctionProlog(SourceLocation loc, + CIRGenFunction &cgf) override; + + void emitCXXConstructors(const clang::CXXConstructorDecl *d) override; + void emitCXXStructor(clang::GlobalDecl gd) override; }; } // namespace @@ -72,6 +79,60 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, } } +void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + auto *cd = dyn_cast(md); + + if (!cd) { + cgm.errorNYI(md->getSourceRange(), "CXCABI emit destructor"); + return; + } + + if (cgm.getCodeGenOpts().CXXCtorDtorAliases) + cgm.errorNYI(md->getSourceRange(), "Ctor/Dtor aliases"); + + auto fn = cgm.codegenCXXStructor(gd); + + cgm.maybeSetTrivialComdat(*md, fn); +} + +void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) { + // Just make sure we're in sync with TargetCXXABI. + assert(cgm.getTarget().getCXXABI().hasConstructorVariants()); + + // The constructor used for constructing this as a base class; + // ignores virtual bases. + cgm.emitGlobal(GlobalDecl(d, Ctor_Base)); + + // The constructor used for constructing this as a complete class; + // constructs the virtual bases, then calls the base constructor. + if (!d->getParent()->isAbstract()) { + // We don't need to emit the complete ctro if the class is abstract. + cgm.emitGlobal(GlobalDecl(d, Ctor_Complete)); + } +} + +/// Return whether the given global decl needs a VTT (virtual table table) +/// parameter, which it does if it's a base constructor or destructor with +/// virtual bases. +bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + // We don't have any virtual bases, just return early. + if (!md->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa(md) && gd.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa(md) && gd.getDtorType() == Dtor_Base) + return true; + + return false; +} + CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) { switch (cgm.getASTContext().getCXXABIKind()) { case TargetCXXABI::GenericItanium: diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 8407f8fad06b..434dd376208e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -226,11 +226,9 @@ mlir::Operation * CIRGenModule::getAddrOfGlobal(GlobalDecl gd, ForDefinition_t isForDefinition) { const Decl *d = gd.getDecl(); - if (isa(d) || isa(d)) { - errorNYI(d->getSourceRange(), - "getAddrOfGlobal: C++ constructor/destructor"); - return nullptr; - } + if (isa(d) || isa(d)) + return getAddrOfCXXStructor(gd, /*FnInfo=*/nullptr, /*FnType=*/nullptr, + /*DontDefer=*/false, isForDefinition); if (isa(d)) { const CIRGenFunctionInfo &fi = @@ -411,6 +409,7 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, cgf.generateCode(gd, funcOp, funcType); } curCGF = nullptr; + assert(!cir::MissingFeatures::opFuncAttributesForDefinition()); } mlir::Operation *CIRGenModule::getGlobalValue(StringRef name) { @@ -771,7 +770,7 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, // Make sure to emit the definition(s) before we emit the thunks. This is // necessary for the generation of certain thunks. if (isa(method) || isa(method)) - errorNYI(method->getSourceRange(), "C++ ctor/dtor"); + abi->emitCXXStructor(gd); else if (fd->isMultiVersion()) errorNYI(method->getSourceRange(), "multiversion functions"); else @@ -1173,6 +1172,10 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { case Decl::Empty: break; + case Decl::CXXConstructor: + getCXXABI().emitCXXConstructors(cast(decl)); + break; + // C++ Decls case Decl::LinkageSpec: case Decl::Namespace: diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 9748c0b3ed43..71806e3c5de2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H #include "CIRGenBuilder.h" +#include "CIRGenCall.h" #include "CIRGenTypeCache.h" #include "CIRGenTypes.h" #include "CIRGenValue.h" @@ -113,8 +114,21 @@ public: mlir::Operation *lastGlobalOp = nullptr; + llvm::DenseMap staticLocalDeclMap; + mlir::Operation *getGlobalValue(llvm::StringRef ref); + cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d) { + return staticLocalDeclMap[d]; + } + + void setStaticLocalDeclAddress(const VarDecl *d, cir::GlobalOp c) { + staticLocalDeclMap[d] = c; + } + + cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &d, + cir::GlobalLinkageKind linkage); + /// If the specified mangled name is not in the module, create and return an /// mlir::GlobalOp value cir::GlobalOp getOrCreateCIRGlobal(llvm::StringRef mangledName, mlir::Type ty, @@ -145,6 +159,15 @@ public: const CXXRecordDecl *derivedClass, llvm::iterator_range path); + /// Get the CIR attributes and calling convention to use for a particular + /// function type. + /// + /// \param calleeInfo - The callee information these attributes are being + /// constructed for. If valid, the attributes applied to this decl may + /// contribute to the function attributes and calling convention. + void constructAttributeList(CIRGenCalleeInfo calleeInfo, + cir::SideEffect &sideEffect); + /// Return a constant array for the given string. mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e); @@ -267,6 +290,11 @@ public: // Make sure that this type is translated. void updateCompletedType(const clang::TagDecl *td); + // Produce code for this constructor/destructor. This method doesn't try to + // apply any ABI rules about which other constructors/destructors are needed + // or if they are alias to each other. + cir::FuncOp codegenCXXStructor(clang::GlobalDecl gd); + bool supportsCOMDAT() const; void maybeSetTrivialComdat(const clang::Decl &d, mlir::Operation *op); @@ -283,6 +311,10 @@ public: cir::FuncType funcType, const clang::FunctionDecl *funcDecl); + /// Given a builtin id for a function like "__builtin_fabsf", return a + /// Function* for "fabsf". + cir::FuncOp getBuiltinLibFunction(const FunctionDecl *fd, unsigned builtinID); + mlir::IntegerAttr getSize(CharUnits size) { return builder.getSizeFromCharUnits(size); } diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h index ac8832b8c9b2..3b51ab784d37 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h @@ -14,6 +14,106 @@ namespace clang::CIRGen { +/// Record with information about how a bitfield should be accessed. This is +/// very similar to what LLVM codegen does, once CIR evolves it's possible we +/// can use a more higher level representation. +/// +/// Often we lay out a sequence of bitfields as a contiguous sequence of bits. +/// When the AST record layout does this, we represent it in CIR as a +/// `!cir.record` type, which directly reflects the structure's layout, +/// including bitfield packing and padding, using CIR types such as +/// `!cir.bool`, `!s8i`, `!u16i`. +/// +/// To access a particular bitfield in CIR, we use the operations +/// `cir.get_bitfield` (`GetBitfieldOp`) or `cir.set_bitfield` +/// (`SetBitfieldOp`). These operations rely on the `bitfield_info` +/// attribute, which provides detailed metadata required for access, +/// such as the size and offset of the bitfield, the type and size of +/// the underlying storage, and whether the value is signed. +/// The CIRGenRecordLayout also has a bitFields map which encodes which +/// byte-sequence this bitfield falls within. Let's assume the following C +/// struct: +/// +/// struct S { +/// char a, b, c; +/// unsigned bits : 3; +/// unsigned more_bits : 4; +/// unsigned still_more_bits : 7; +/// }; +/// +/// This will end up as the following cir.record. The bitfield members are +/// represented by one !u16i value, and the array provides padding to align the +/// struct to a 4-byte alignment. +/// +/// !rec_S = !cir.record}> +/// +/// When generating code to access more_bits, we'll generate something +/// essentially like this: +/// +/// #bfi_more_bits = #cir.bitfield_info +/// +/// cir.func @store_field() { +/// %0 = cir.alloca !rec_S, !cir.ptr, ["s"] {alignment = 4 : i64} +/// %1 = cir.const #cir.int<2> : !s32i +/// %2 = cir.cast(integral, %1 : !s32i), !u32i +/// %3 = cir.get_member %0[3] {name = "more_bits"} : !cir.ptr -> +/// !cir.ptr +/// %4 = cir.set_bitfield(#bfi_more_bits, %3 : +/// !cir.ptr, %2 : !u32i) -> !u32i +/// cir.return +/// } +/// +struct CIRGenBitFieldInfo { + /// The offset within a contiguous run of bitfields that are represented as + /// a single "field" within the cir.record type. This offset is in bits. + unsigned offset : 16; + + /// The total size of the bit-field, in bits. + unsigned size : 15; + + /// Whether the bit-field is signed. + unsigned isSigned : 1; + + /// The storage size in bits which should be used when accessing this + /// bitfield. + unsigned storageSize; + + /// The offset of the bitfield storage from the start of the record. + clang::CharUnits storageOffset; + + /// The offset within a contiguous run of bitfields that are represented as a + /// single "field" within the cir.record type, taking into account the AAPCS + /// rules for volatile bitfields. This offset is in bits. + unsigned volatileOffset : 16; + + /// The storage size in bits which should be used when accessing this + /// bitfield. + unsigned volatileStorageSize; + + /// The offset of the bitfield storage from the start of the record. + clang::CharUnits volatileStorageOffset; + + /// The name of a bitfield + llvm::StringRef name; + + // The actual storage type for the bitfield + mlir::Type storageType; + + CIRGenBitFieldInfo() + : offset(), size(), isSigned(), storageSize(), volatileOffset(), + volatileStorageSize() {} + + CIRGenBitFieldInfo(unsigned offset, unsigned size, bool isSigned, + unsigned storageSize, clang::CharUnits storageOffset) + : offset(offset), size(size), isSigned(isSigned), + storageSize(storageSize), storageOffset(storageOffset) {} + + void print(llvm::raw_ostream &os) const; + LLVM_DUMP_METHOD void dump() const; +}; + /// This class handles record and union layout info while lowering AST types /// to CIR types. /// @@ -41,6 +141,10 @@ private: // for both virtual and non-virtual bases. llvm::DenseMap nonVirtualBases; + /// Map from (bit-field) record field to the corresponding CIR record type + /// field no. This info is populated by record builder. + llvm::DenseMap bitFields; + /// False if any direct or indirect subobject of this class, when considered /// as a complete object, requires a non-zero bitpattern when /// zero-initialized. @@ -83,6 +187,16 @@ public: /// Check whether this struct can be C++ zero-initialized /// with a zeroinitializer when considered as a base subobject. bool isZeroInitializableAsBase() const { return zeroInitializableAsBase; } + + /// Return the BitFieldInfo that corresponds to the field FD. + const CIRGenBitFieldInfo &getBitFieldInfo(const clang::FieldDecl *fd) const { + fd = fd->getCanonicalDecl(); + assert(fd->isBitField() && "Invalid call for non-bit-field decl!"); + llvm::DenseMap::const_iterator + it = bitFields.find(fd); + assert(it != bitFields.end() && "Unable to find bitfield info"); + return it->second; + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index 0aeef7fd89ae..8dbf1b36a93b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -20,6 +20,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDataLayout.h" +#include "clang/CIR/MissingFeatures.h" #include "llvm/Support/Casting.h" #include @@ -66,6 +67,10 @@ struct CIRRecordLowering final { return MemberInfo(offset, MemberInfo::InfoKind::Field, data); } + // Layout routines. + void setBitFieldInfo(const FieldDecl *fd, CharUnits startOffset, + mlir::Type storageType); + void lower(); void lowerUnion(); @@ -77,6 +82,9 @@ struct CIRRecordLowering final { void accumulateBases(const CXXRecordDecl *cxxRecordDecl); void accumulateVPtrs(); void accumulateFields(); + RecordDecl::field_iterator + accumulateBitFields(RecordDecl::field_iterator field, + RecordDecl::field_iterator fieldEnd); CharUnits bitsToCharUnits(uint64_t bitOffset) { return astContext.toCharUnitsFromBits(bitOffset); @@ -87,6 +95,9 @@ struct CIRRecordLowering final { CharUnits getSize(mlir::Type Ty) { return CharUnits::fromQuantity(dataLayout.layout.getTypeSize(Ty)); } + CharUnits getSizeInBits(mlir::Type ty) { + return CharUnits::fromQuantity(dataLayout.layout.getTypeSizeInBits(ty)); + } CharUnits getAlignment(mlir::Type Ty) { return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty)); } @@ -124,6 +135,17 @@ struct CIRRecordLowering final { mlir::Type getStorageType(const CXXRecordDecl *RD) { return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType(); } + // This is different from LLVM traditional codegen because CIRGen uses arrays + // of bytes instead of arbitrary-sized integers. This is important for packed + // structures support. + mlir::Type getBitfieldStorageType(unsigned numBits) { + unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth()); + if (cir::isValidFundamentalIntWidth(alignedBits)) + return builder.getUIntNTy(alignedBits); + + mlir::Type type = getCharType(); + return cir::ArrayType::get(type, alignedBits / astContext.getCharWidth()); + } mlir::Type getStorageType(const FieldDecl *fieldDecl) { mlir::Type type = cirGenTypes.convertTypeForMem(fieldDecl->getType()); @@ -157,6 +179,7 @@ struct CIRRecordLowering final { std::vector members; // Output fields, consumed by CIRGenTypes::computeRecordLayout llvm::SmallVector fieldTypes; + llvm::DenseMap bitFields; llvm::DenseMap fieldIdxMap; llvm::DenseMap nonVirtualBases; cir::CIRDataLayout dataLayout; @@ -186,6 +209,32 @@ CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes, zeroInitializable(true), zeroInitializableAsBase(true), packed(packed), padded(false) {} +void CIRRecordLowering::setBitFieldInfo(const FieldDecl *fd, + CharUnits startOffset, + mlir::Type storageType) { + CIRGenBitFieldInfo &info = bitFields[fd->getCanonicalDecl()]; + info.isSigned = fd->getType()->isSignedIntegerOrEnumerationType(); + info.offset = + (unsigned)(getFieldBitOffset(fd) - astContext.toBits(startOffset)); + info.size = fd->getBitWidthValue(); + info.storageSize = getSizeInBits(storageType).getQuantity(); + info.storageOffset = startOffset; + info.storageType = storageType; + info.name = fd->getName(); + + if (info.size > info.storageSize) + info.size = info.storageSize; + // Reverse the bit offsets for big endian machines. Since bitfields are laid + // out as packed bits within an integer-sized unit, we can imagine the bits + // counting from the most-significant-bit instead of the + // least-significant-bit. + assert(!cir::MissingFeatures::isBigEndian()); + + info.volatileStorageSize = 0; + info.volatileOffset = 0; + info.volatileStorageOffset = CharUnits::Zero(); +} + void CIRRecordLowering::lower() { if (recordDecl->isUnion()) { lowerUnion(); @@ -233,6 +282,8 @@ void CIRRecordLowering::fillOutputFields() { fieldTypes.size() - 1; // A field without storage must be a bitfield. assert(!cir::MissingFeatures::bitfields()); + if (!member.data) + setBitFieldInfo(member.fieldDecl, member.offset, fieldTypes.back()); } else if (member.kind == MemberInfo::InfoKind::Base) { nonVirtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1; } @@ -240,16 +291,217 @@ void CIRRecordLowering::fillOutputFields() { } } -void CIRRecordLowering::accumulateFields() { - for (const FieldDecl *field : recordDecl->fields()) { - if (field->isBitField()) { - cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(), - "accumulate bitfields"); +RecordDecl::field_iterator +CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field, + RecordDecl::field_iterator fieldEnd) { + assert(!cir::MissingFeatures::isDiscreteBitFieldABI()); + + CharUnits regSize = + bitsToCharUnits(astContext.getTargetInfo().getRegisterWidth()); + unsigned charBits = astContext.getCharWidth(); + + // Data about the start of the span we're accumulating to create an access + // unit from. 'Begin' is the first bitfield of the span. If 'begin' is + // 'fieldEnd', we've not got a current span. The span starts at the + // 'beginOffset' character boundary. 'bitSizeSinceBegin' is the size (in bits) + // of the span -- this might include padding when we've advanced to a + // subsequent bitfield run. + RecordDecl::field_iterator begin = fieldEnd; + CharUnits beginOffset; + uint64_t bitSizeSinceBegin; + + // The (non-inclusive) end of the largest acceptable access unit we've found + // since 'begin'. If this is 'begin', we're gathering the initial set of + // bitfields of a new span. 'bestEndOffset' is the end of that acceptable + // access unit -- it might extend beyond the last character of the bitfield + // run, using available padding characters. + RecordDecl::field_iterator bestEnd = begin; + CharUnits bestEndOffset; + bool bestClipped; // Whether the representation must be in a byte array. + + for (;;) { + // atAlignedBoundary is true if 'field' is the (potential) start of a new + // span (or the end of the bitfields). When true, limitOffset is the + // character offset of that span and barrier indicates whether the new + // span cannot be merged into the current one. + bool atAlignedBoundary = false; + bool barrier = false; // a barrier can be a zero Bit Width or non bit member + if (field != fieldEnd && field->isBitField()) { + uint64_t bitOffset = getFieldBitOffset(*field); + if (begin == fieldEnd) { + // Beginning a new span. + begin = field; + bestEnd = begin; + + assert((bitOffset % charBits) == 0 && "Not at start of char"); + beginOffset = bitsToCharUnits(bitOffset); + bitSizeSinceBegin = 0; + } else if ((bitOffset % charBits) != 0) { + // Bitfield occupies the same character as previous bitfield, it must be + // part of the same span. This can include zero-length bitfields, should + // the target not align them to character boundaries. Such non-alignment + // is at variance with the standards, which require zero-length + // bitfields be a barrier between access units. But of course we can't + // achieve that in the middle of a character. + assert(bitOffset == + astContext.toBits(beginOffset) + bitSizeSinceBegin && + "Concatenating non-contiguous bitfields"); + } else { + // Bitfield potentially begins a new span. This includes zero-length + // bitfields on non-aligning targets that lie at character boundaries + // (those are barriers to merging). + if (field->isZeroLengthBitField()) + barrier = true; + atAlignedBoundary = true; + } + } else { + // We've reached the end of the bitfield run. Either we're done, or this + // is a barrier for the current span. + if (begin == fieldEnd) + break; + + barrier = true; + atAlignedBoundary = true; + } + + // 'installBest' indicates whether we should create an access unit for the + // current best span: fields ['begin', 'bestEnd') occupying characters + // ['beginOffset', 'bestEndOffset'). + bool installBest = false; + if (atAlignedBoundary) { + // 'field' is the start of a new span or the end of the bitfields. The + // just-seen span now extends to 'bitSizeSinceBegin'. + + // Determine if we can accumulate that just-seen span into the current + // accumulation. + CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1); + if (bestEnd == begin) { + // This is the initial run at the start of a new span. By definition, + // this is the best seen so far. + bestEnd = field; + bestEndOffset = beginOffset + accessSize; + // Assume clipped until proven not below. + bestClipped = true; + if (!bitSizeSinceBegin) + // A zero-sized initial span -- this will install nothing and reset + // for another. + installBest = true; + } else if (accessSize > regSize) { + // Accumulating the just-seen span would create a multi-register access + // unit, which would increase register pressure. + installBest = true; + } + + if (!installBest) { + // Determine if accumulating the just-seen span will create an expensive + // access unit or not. + mlir::Type type = getUIntNType(astContext.toBits(accessSize)); + if (!astContext.getTargetInfo().hasCheapUnalignedBitFieldAccess()) + cirGenTypes.getCGModule().errorNYI( + field->getSourceRange(), "NYI CheapUnalignedBitFieldAccess"); + + if (!installBest) { + // Find the next used storage offset to determine what the limit of + // the current span is. That's either the offset of the next field + // with storage (which might be field itself) or the end of the + // non-reusable tail padding. + CharUnits limitOffset; + for (auto probe = field; probe != fieldEnd; ++probe) + if (!isEmptyFieldForLayout(astContext, *probe)) { + // A member with storage sets the limit. + assert((getFieldBitOffset(*probe) % charBits) == 0 && + "Next storage is not byte-aligned"); + limitOffset = bitsToCharUnits(getFieldBitOffset(*probe)); + goto FoundLimit; + } + assert(!cir::MissingFeatures::cxxSupport()); + limitOffset = astRecordLayout.getDataSize(); + FoundLimit: + CharUnits typeSize = getSize(type); + if (beginOffset + typeSize <= limitOffset) { + // There is space before limitOffset to create a naturally-sized + // access unit. + bestEndOffset = beginOffset + typeSize; + bestEnd = field; + bestClipped = false; + } + if (barrier) { + // The next field is a barrier that we cannot merge across. + installBest = true; + } else if (cirGenTypes.getCGModule() + .getCodeGenOpts() + .FineGrainedBitfieldAccesses) { + assert(!cir::MissingFeatures::nonFineGrainedBitfields()); + cirGenTypes.getCGModule().errorNYI(field->getSourceRange(), + "NYI FineGrainedBitfield"); + } else { + // Otherwise, we're not installing. Update the bit size + // of the current span to go all the way to limitOffset, which is + // the (aligned) offset of next bitfield to consider. + bitSizeSinceBegin = astContext.toBits(limitOffset - beginOffset); + } + } + } + } + + if (installBest) { + assert((field == fieldEnd || !field->isBitField() || + (getFieldBitOffset(*field) % charBits) == 0) && + "Installing but not at an aligned bitfield or limit"); + CharUnits accessSize = bestEndOffset - beginOffset; + if (!accessSize.isZero()) { + // Add the storage member for the access unit to the record. The + // bitfields get the offset of their storage but come afterward and + // remain there after a stable sort. + mlir::Type type; + if (bestClipped) { + assert(getSize(getUIntNType(astContext.toBits(accessSize))) > + accessSize && + "Clipped access need not be clipped"); + type = getByteArrayType(accessSize); + } else { + type = getUIntNType(astContext.toBits(accessSize)); + assert(getSize(type) == accessSize && + "Unclipped access must be clipped"); + } + members.push_back(makeStorageInfo(beginOffset, type)); + for (; begin != bestEnd; ++begin) + if (!begin->isZeroLengthBitField()) + members.push_back(MemberInfo( + beginOffset, MemberInfo::InfoKind::Field, nullptr, *begin)); + } + // Reset to start a new span. + field = bestEnd; + begin = fieldEnd; + } else { + assert(field != fieldEnd && field->isBitField() && + "Accumulating past end of bitfields"); + assert(!barrier && "Accumulating across barrier"); + // Accumulate this bitfield into the current (potential) span. + bitSizeSinceBegin += field->getBitWidthValue(); ++field; + } + } + + return field; +} + +void CIRRecordLowering::accumulateFields() { + for (RecordDecl::field_iterator field = recordDecl->field_begin(), + fieldEnd = recordDecl->field_end(); + field != fieldEnd;) { + if (field->isBitField()) { + RecordDecl::field_iterator start = field; + // Iterate to gather the list of bitfields. + for (++field; field != fieldEnd && field->isBitField(); ++field) + ; + field = accumulateBitFields(start, field); + assert((field == fieldEnd || !field->isBitField()) && + "Failed to accumulate all the bitfields"); } else if (!field->isZeroSize(astContext)) { - members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(field)), + members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)), MemberInfo::InfoKind::Field, - getStorageType(field), field)); + getStorageType(*field), *field)); ++field; } else { // TODO(cir): do we want to do anything special about zero size members? @@ -383,6 +635,8 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) { // Add all the field numbers. rl->fieldIdxMap.swap(lowering.fieldIdxMap); + rl->bitFields.swap(lowering.bitFields); + // Dump the layout, if requested. if (getASTContext().getLangOpts().DumpRecordLayouts) { cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: dump layout"); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 019a44636ce3..9193f6f1cd99 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -391,8 +391,7 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) { // If this function returns a reference, take the address of the // expression rather than the value. RValue result = emitReferenceBindingToExpr(rv); - builder.CIRBaseBuilderTy::createStore(loc, result.getScalarVal(), - *fnRetAlloca); + builder.CIRBaseBuilderTy::createStore(loc, result.getValue(), *fnRetAlloca); } else { mlir::Value value = nullptr; switch (CIRGenFunction::getEvaluationKind(rv->getType())) { diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp index 2aab9cecf93d..1feefa55eb27 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp @@ -102,6 +102,8 @@ mlir::LogicalResult CIRGenFunction::emitOpenACCOpCombinedConstruct( emitOpenACCClauses(computeOp, loopOp, dirKind, dirLoc, clauses); + updateLoopOpParallelism(loopOp, /*isOrphan=*/false, dirKind); + builder.create(end); } diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp index 24cd1d399de6..71f3ccb8e040 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp @@ -22,6 +22,36 @@ using namespace clang::CIRGen; using namespace cir; using namespace mlir::acc; +void CIRGenFunction::updateLoopOpParallelism(mlir::acc::LoopOp &op, + bool isOrphan, + OpenACCDirectiveKind dk) { + // Check that at least one of auto, independent, or seq is present + // for the device-independent default clauses. + if (op.hasParallelismFlag(mlir::acc::DeviceType::None)) + return; + + switch (dk) { + default: + llvm_unreachable("Invalid parent directive kind"); + case OpenACCDirectiveKind::Invalid: + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::ParallelLoop: + op.addIndependent(builder.getContext(), {}); + return; + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::KernelsLoop: + op.addAuto(builder.getContext(), {}); + return; + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::SerialLoop: + if (op.hasDefaultGangWorkerVector()) + op.addAuto(builder.getContext(), {}); + else + op.addSeq(builder.getContext(), {}); + return; + }; +} + mlir::LogicalResult CIRGenFunction::emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s) { mlir::Location start = getLoc(s.getSourceRange().getBegin()); @@ -90,6 +120,9 @@ CIRGenFunction::emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s) { emitOpenACCClauses(op, s.getDirectiveKind(), s.getDirectiveLoc(), s.clauses()); + updateLoopOpParallelism(op, s.isOrphanedLoopConstruct(), + s.getParentComputeConstructKind()); + mlir::LogicalResult stmtRes = mlir::success(); // Emit body. { diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index eaba3dfd1105..621eb66962bf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -416,9 +416,34 @@ mlir::Type CIRGenTypes::convertType(QualType type) { break; } + case Type::IncompleteArray: { + const IncompleteArrayType *arrTy = cast(ty); + if (arrTy->getIndexTypeCVRQualifiers() != 0) + cgm.errorNYI(SourceLocation(), "non trivial array types", type); + + mlir::Type elemTy = convertTypeForMem(arrTy->getElementType()); + // int X[] -> [0 x int], unless the element type is not sized. If it is + // unsized (e.g. an incomplete record) just use [0 x i8]. + if (!builder.isSized(elemTy)) { + elemTy = cgm.SInt8Ty; + } + + resultType = cir::ArrayType::get(elemTy, 0); + break; + } + case Type::ConstantArray: { const ConstantArrayType *arrTy = cast(ty); mlir::Type elemTy = convertTypeForMem(arrTy->getElementType()); + + // TODO(CIR): In LLVM, "lower arrays of undefined struct type to arrays of + // i8 just to have a concrete type" + if (!builder.isSized(elemTy)) { + cgm.errorNYI(SourceLocation(), "arrays of undefined struct type", type); + resultType = cgm.UInt32Ty; + break; + } + resultType = cir::ArrayType::get(elemTy, arrTy->getSize().getZExtValue()); break; } @@ -432,8 +457,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } case Type::Enum: { - const EnumDecl *ED = cast(ty)->getDecl(); - if (auto integerType = ED->getIntegerType(); !integerType.isNull()) + const EnumDecl *ed = cast(ty)->getDecl(); + if (auto integerType = ed->getIntegerType(); !integerType.isNull()) return convertType(integerType); // Return a placeholder 'i32' type. This can be changed later when the // type is defined (see UpdateCompletedType), but is likely to be the diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 208247e16e53..a5a457ddafa9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -33,11 +33,7 @@ class RValue { enum Flavor { Scalar, Complex, Aggregate }; union { - // Stores first and second value. - struct { - mlir::Value first; - mlir::Value second; - } vals; + mlir::Value value; // Stores aggregate address. Address aggregateAddr; @@ -47,7 +43,7 @@ class RValue { unsigned flavor : 2; public: - RValue() : vals{nullptr, nullptr}, flavor(Scalar) {} + RValue() : value(nullptr), flavor(Scalar) {} bool isScalar() const { return flavor == Scalar; } bool isComplex() const { return flavor == Complex; } @@ -56,14 +52,9 @@ public: bool isVolatileQualified() const { return isVolatile; } /// Return the value of this scalar value. - mlir::Value getScalarVal() const { + mlir::Value getValue() const { assert(isScalar() && "Not a scalar!"); - return vals.first; - } - - /// Return the real/imag components of this complex value. - std::pair getComplexVal() const { - return std::make_pair(vals.first, vals.second); + return value; } /// Return the value of the address of the aggregate. @@ -83,23 +74,20 @@ public: static RValue get(mlir::Value v) { RValue er; - er.vals.first = v; + er.value = v; er.flavor = Scalar; er.isVolatile = false; return er; } - static RValue getComplex(mlir::Value v1, mlir::Value v2) { + static RValue getComplex(mlir::Value v) { RValue er; - er.vals = {v1, v2}; + er.value = v; er.flavor = Complex; er.isVolatile = false; return er; } - static RValue getComplex(const std::pair &c) { - return getComplex(c.first, c.second); - } - // FIXME: Aggregate rvalues need to retain information about whether they are + // volatile or not. Remove default to find all places that probably get this // wrong. @@ -194,9 +182,7 @@ public: bool isSimple() const { return lvType == Simple; } bool isVectorElt() const { return lvType == VectorElt; } bool isBitField() const { return lvType == BitField; } - - // TODO: Add support for volatile - bool isVolatile() const { return false; } + bool isVolatile() const { return quals.hasVolatile(); } unsigned getVRQualifiers() const { return quals.getCVRQualifiers() & ~clang::Qualifiers::Const; @@ -267,23 +253,71 @@ class AggValueSlot { Address addr; clang::Qualifiers quals; + /// This is set to true if some external code is responsible for setting up a + /// destructor for the slot. Otherwise the code which constructs it should + /// push the appropriate cleanup. + LLVM_PREFERRED_TYPE(bool) + LLVM_ATTRIBUTE_UNUSED unsigned destructedFlag : 1; + /// This is set to true if the memory in the slot is known to be zero before /// the assignment into it. This means that zero fields don't need to be set. - bool zeroedFlag : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned zeroedFlag : 1; + + /// This is set to true if the slot might be aliased and it's not undefined + /// behavior to access it through such an alias. Note that it's always + /// undefined behavior to access a C++ object that's under construction + /// through an alias derived from outside the construction process. + /// + /// This flag controls whether calls that produce the aggregate + /// value may be evaluated directly into the slot, or whether they + /// must be evaluated into an unaliased temporary and then memcpy'ed + /// over. Since it's invalid in general to memcpy a non-POD C++ + /// object, it's important that this flag never be set when + /// evaluating an expression which constructs such an object. + LLVM_PREFERRED_TYPE(bool) + LLVM_ATTRIBUTE_UNUSED unsigned aliasedFlag : 1; + + /// This is set to true if the tail padding of this slot might overlap + /// another object that may have already been initialized (and whose + /// value must be preserved by this initialization). If so, we may only + /// store up to the dsize of the type. Otherwise we can widen stores to + /// the size of the type. + LLVM_PREFERRED_TYPE(bool) + LLVM_ATTRIBUTE_UNUSED unsigned overlapFlag : 1; public: + enum IsDestructed_t { IsNotDestructed, IsDestructed }; enum IsZeroed_t { IsNotZeroed, IsZeroed }; + enum IsAliased_t { IsNotAliased, IsAliased }; + enum Overlap_t { MayOverlap, DoesNotOverlap }; - AggValueSlot(Address addr, clang::Qualifiers quals, bool zeroedFlag) - : addr(addr), quals(quals), zeroedFlag(zeroedFlag) {} - - static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, - IsZeroed_t isZeroed = IsNotZeroed) { - return AggValueSlot(addr, quals, isZeroed); + /// Returns an aggregate value slot indicating that the aggregate + /// value is being ignored. + static AggValueSlot ignored() { + return forAddr(Address::invalid(), clang::Qualifiers(), IsNotDestructed, + IsNotAliased, DoesNotOverlap); } - static AggValueSlot forLValue(const LValue &lv) { - return forAddr(lv.getAddress(), lv.getQuals()); + AggValueSlot(Address addr, clang::Qualifiers quals, bool destructedFlag, + bool zeroedFlag, bool aliasedFlag, bool overlapFlag) + : addr(addr), quals(quals), destructedFlag(destructedFlag), + zeroedFlag(zeroedFlag), aliasedFlag(aliasedFlag), + overlapFlag(overlapFlag) {} + + static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, + IsDestructed_t isDestructed, + IsAliased_t isAliased, Overlap_t mayOverlap, + IsZeroed_t isZeroed = IsNotZeroed) { + return AggValueSlot(addr, quals, isDestructed, isZeroed, isAliased, + mayOverlap); + } + + static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, + IsAliased_t isAliased, Overlap_t mayOverlap, + IsZeroed_t isZeroed = IsNotZeroed) { + return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, isAliased, + mayOverlap, isZeroed); } clang::Qualifiers getQualifiers() const { return quals; } @@ -292,7 +326,16 @@ public: bool isIgnored() const { return !addr.isValid(); } + mlir::Value getPointer() const { return addr.getPointer(); } + IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); } + + RValue asRValue() const { + if (isIgnored()) + return RValue::getIgnored(); + assert(!cir::MissingFeatures::aggValueSlot()); + return RValue::getAggregate(getAddress()); + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 8bfcd2773d07..385bea066c61 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -11,12 +11,15 @@ add_clang_library(clangCIR CIRGenBuilder.cpp CIRGenCall.cpp CIRGenClass.cpp + CIRGenCXX.cpp CIRGenCXXABI.cpp CIRGenCXXExpr.cpp + CIRGenBuiltin.cpp CIRGenDecl.cpp CIRGenDeclOpenACC.cpp CIRGenExpr.cpp CIRGenExprAggregate.cpp + CIRGenExprComplex.cpp CIRGenExprConstant.cpp CIRGenExprScalar.cpp CIRGenFunction.cpp diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 551341ff20c0..d2d32bbd9403 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -3,6 +3,43 @@ using namespace clang; using namespace clang::CIRGen; + +bool clang::CIRGen::isEmptyRecordForLayout(const ASTContext &context, + QualType t) { + const RecordType *rt = t->getAs(); + if (!rt) + return false; + + const RecordDecl *rd = rt->getDecl(); + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *cxxrd = dyn_cast(rd)) { + if (cxxrd->isDynamicClass()) + return false; + + for (const auto &I : cxxrd->bases()) + if (!isEmptyRecordForLayout(context, I.getType())) + return false; + } + + for (const auto *I : rd->fields()) + if (!isEmptyFieldForLayout(context, I)) + return false; + + return true; +} + +bool clang::CIRGen::isEmptyFieldForLayout(const ASTContext &context, + const FieldDecl *fd) { + if (fd->isZeroLengthBitField()) + return true; + + if (fd->isUnnamedBitField()) + return false; + + return isEmptyRecordForLayout(context, fd->getType()); +} + namespace { class X8664ABIInfo : public ABIInfo { diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index d31d1ee82d90..a5c548aa2c7c 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -22,6 +22,16 @@ namespace clang::CIRGen { +/// isEmptyFieldForLayout - Return true if the field is "empty", that is, +/// either a zero-width bit-field or an isEmptyRecordForLayout. +bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd); + +/// isEmptyRecordForLayout - Return true if a structure contains only empty +/// base classes (per isEmptyRecordForLayout) and fields (per +/// isEmptyFieldForLayout). Note, C++ record fields are considered empty +/// if the [[no_unique_address]] attribute would have made them empty. +bool isEmptyRecordForLayout(const ASTContext &context, QualType t); + class TargetCIRGenInfo { std::unique_ptr info; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index a6cf0a6b5d75..16248059c497 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -92,6 +92,46 @@ Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder, // Helpers //===----------------------------------------------------------------------===// +// Parses one of the keywords provided in the list `keywords` and returns the +// position of the parsed keyword in the list. If none of the keywords from the +// list is parsed, returns -1. +static int parseOptionalKeywordAlternative(AsmParser &parser, + ArrayRef keywords) { + for (auto en : llvm::enumerate(keywords)) { + if (succeeded(parser.parseOptionalKeyword(en.value()))) + return en.index(); + } + return -1; +} + +namespace { +template struct EnumTraits {}; + +#define REGISTER_ENUM_TYPE(Ty) \ + template <> struct EnumTraits { \ + static llvm::StringRef stringify(cir::Ty value) { \ + return stringify##Ty(value); \ + } \ + static unsigned getMaxEnumVal() { return cir::getMaxEnumValFor##Ty(); } \ + } + +REGISTER_ENUM_TYPE(SideEffect); +} // namespace + +/// Parse an enum from the keyword, return failure if the keyword is not found. +template +static ParseResult parseCIRKeyword(AsmParser &parser, RetTy &result) { + llvm::SmallVector names; + for (unsigned i = 0, e = EnumTraits::getMaxEnumVal(); i <= e; ++i) + names.push_back(EnumTraits::stringify(static_cast(i))); + + int index = parseOptionalKeywordAlternative(parser, names); + if (index == -1) + return failure(); + result = static_cast(index); + return success(); +} + // Check if a region's termination omission is valid and, if so, creates and // inserts the omitted terminator into the region. static LogicalResult ensureRegionTerm(OpAsmParser &parser, Region ®ion, @@ -534,6 +574,18 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser, if (parser.parseRParen()) return mlir::failure(); + if (parser.parseOptionalKeyword("side_effect").succeeded()) { + if (parser.parseLParen().failed()) + return failure(); + cir::SideEffect sideEffect; + if (parseCIRKeyword(parser, sideEffect).failed()) + return failure(); + if (parser.parseRParen().failed()) + return failure(); + auto attr = cir::SideEffectAttr::get(parser.getContext(), sideEffect); + result.addAttribute("side_effect", attr); + } + if (parser.parseOptionalAttrDict(result.attributes)) return ::mlir::failure(); @@ -556,7 +608,8 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser, static void printCallCommon(mlir::Operation *op, mlir::FlatSymbolRefAttr calleeSym, mlir::Value indirectCallee, - mlir::OpAsmPrinter &printer) { + mlir::OpAsmPrinter &printer, + cir::SideEffect sideEffect) { printer << ' '; auto callLikeOp = mlir::cast(op); @@ -572,7 +625,13 @@ static void printCallCommon(mlir::Operation *op, } printer << "(" << ops << ")"; - printer.printOptionalAttrDict(op->getAttrs(), {"callee"}); + if (sideEffect != cir::SideEffect::All) { + printer << " side_effect("; + printer << stringifySideEffect(sideEffect); + printer << ")"; + } + + printer.printOptionalAttrDict(op->getAttrs(), {"callee", "side_effect"}); printer << " : "; printer.printFunctionalType(op->getOperands().getTypes(), @@ -586,7 +645,8 @@ mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser, void cir::CallOp::print(mlir::OpAsmPrinter &p) { mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr; - printCallCommon(*this, getCalleeAttr(), indirectCallee, p); + cir::SideEffect sideEffect = getSideEffect(); + printCallCommon(*this, getCalleeAttr(), indirectCallee, p, sideEffect); } static LogicalResult @@ -1533,6 +1593,16 @@ LogicalResult cir::GetMemberOp::verify() { // VecCreateOp //===----------------------------------------------------------------------===// +OpFoldResult cir::VecCreateOp::fold(FoldAdaptor adaptor) { + if (llvm::any_of(getElements(), [](mlir::Value value) { + return !mlir::isa(value.getDefiningOp()); + })) + return {}; + + return cir::ConstVectorAttr::get( + getType(), mlir::ArrayAttr::get(getContext(), adaptor.getElements())); +} + LogicalResult cir::VecCreateOp::verify() { // Verify that the number of arguments matches the number of elements in the // vector, and that the type of all the arguments matches the type of the @@ -1579,6 +1649,104 @@ OpFoldResult cir::VecExtractOp::fold(FoldAdaptor adaptor) { return elements[index]; } +//===----------------------------------------------------------------------===// +// VecCmpOp +//===----------------------------------------------------------------------===// + +OpFoldResult cir::VecCmpOp::fold(FoldAdaptor adaptor) { + auto lhsVecAttr = + mlir::dyn_cast_if_present(adaptor.getLhs()); + auto rhsVecAttr = + mlir::dyn_cast_if_present(adaptor.getRhs()); + if (!lhsVecAttr || !rhsVecAttr) + return {}; + + mlir::Type inputElemTy = + mlir::cast(lhsVecAttr.getType()).getElementType(); + if (!isAnyIntegerOrFloatingPointType(inputElemTy)) + return {}; + + cir::CmpOpKind opKind = adaptor.getKind(); + mlir::ArrayAttr lhsVecElhs = lhsVecAttr.getElts(); + mlir::ArrayAttr rhsVecElhs = rhsVecAttr.getElts(); + uint64_t vecSize = lhsVecElhs.size(); + + SmallVector elements(vecSize); + bool isIntAttr = vecSize && mlir::isa(lhsVecElhs[0]); + for (uint64_t i = 0; i < vecSize; i++) { + mlir::Attribute lhsAttr = lhsVecElhs[i]; + mlir::Attribute rhsAttr = rhsVecElhs[i]; + int cmpResult = 0; + switch (opKind) { + case cir::CmpOpKind::lt: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() < + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() < + mlir::cast(rhsAttr).getValue(); + } + break; + } + case cir::CmpOpKind::le: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() <= + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() <= + mlir::cast(rhsAttr).getValue(); + } + break; + } + case cir::CmpOpKind::gt: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() > + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() > + mlir::cast(rhsAttr).getValue(); + } + break; + } + case cir::CmpOpKind::ge: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() >= + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() >= + mlir::cast(rhsAttr).getValue(); + } + break; + } + case cir::CmpOpKind::eq: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() == + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() == + mlir::cast(rhsAttr).getValue(); + } + break; + } + case cir::CmpOpKind::ne: { + if (isIntAttr) { + cmpResult = mlir::cast(lhsAttr).getSInt() != + mlir::cast(rhsAttr).getSInt(); + } else { + cmpResult = mlir::cast(lhsAttr).getValue() != + mlir::cast(rhsAttr).getValue(); + } + break; + } + } + + elements[i] = cir::IntAttr::get(getType().getElementType(), cmpResult); + } + + return cir::ConstVectorAttr::get( + getType(), mlir::ArrayAttr::get(getContext(), elements)); +} + //===----------------------------------------------------------------------===// // VecShuffleOp //===----------------------------------------------------------------------===// @@ -1633,6 +1801,15 @@ LogicalResult cir::VecShuffleOp::verify() { << " and " << getResult().getType() << " don't match"; } + const uint64_t maxValidIndex = + getVec1().getType().getSize() + getVec2().getType().getSize() - 1; + if (llvm::any_of( + getIndices().getAsRange(), [&](cir::IntAttr idxAttr) { + return idxAttr.getSInt() != -1 && idxAttr.getUInt() > maxValidIndex; + })) { + return emitOpError() << ": index for __builtin_shufflevector must be " + "less than the total number of vector elements"; + } return success(); } @@ -1729,6 +1906,33 @@ OpFoldResult cir::VecTernaryOp::fold(FoldAdaptor adaptor) { vecTy, mlir::ArrayAttr::get(getContext(), elements)); } +//===----------------------------------------------------------------------===// +// ComplexCreateOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::ComplexCreateOp::verify() { + if (getType().getElementType() != getReal().getType()) { + emitOpError() + << "operand type of cir.complex.create does not match its result type"; + return failure(); + } + + return success(); +} + +OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) { + mlir::Attribute real = adaptor.getReal(); + mlir::Attribute imag = adaptor.getImag(); + if (!real || !imag) + return {}; + + // When both of real and imag are constants, we can fold the operation into an + // `#cir.const_complex` operation. + auto realAttr = mlir::cast(real); + auto imagAttr = mlir::cast(imag); + return cir::ConstComplexAttr::get(realAttr, imagAttr); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp index 29f994263896..f07e234e5e84 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp @@ -134,7 +134,6 @@ void CIRCanonicalizePass::runOnOperation() { getOperation()->walk([&](Operation *op) { assert(!cir::MissingFeatures::switchOp()); assert(!cir::MissingFeatures::tryOp()); - assert(!cir::MissingFeatures::complexCreateOp()); assert(!cir::MissingFeatures::complexRealOp()); assert(!cir::MissingFeatures::complexImagOp()); assert(!cir::MissingFeatures::callOp()); @@ -142,7 +141,8 @@ void CIRCanonicalizePass::runOnOperation() { // Many operations are here to perform a manual `fold` in // applyOpPatternsGreedily. if (isa(op)) + ComplexCreateOp, VecCmpOp, VecCreateOp, VecExtractOp, VecShuffleOp, + VecShuffleDynamicOp, VecTernaryOp>(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp index 67ed4124f26c..3b7f08c44140 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp @@ -260,6 +260,31 @@ struct SimplifySwitch : public OpRewritePattern { } }; +struct SimplifyVecSplat : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + LogicalResult matchAndRewrite(VecSplatOp op, + PatternRewriter &rewriter) const override { + mlir::Value splatValue = op.getValue(); + auto constant = + mlir::dyn_cast_if_present(splatValue.getDefiningOp()); + if (!constant) + return mlir::failure(); + + auto value = constant.getValue(); + if (!mlir::isa_and_nonnull(value) && + !mlir::isa_and_nonnull(value)) + return mlir::failure(); + + cir::VectorType resultType = op.getResult().getType(); + SmallVector elements(resultType.getSize(), value); + auto constVecAttr = cir::ConstVectorAttr::get( + resultType, mlir::ArrayAttr::get(getContext(), elements)); + + rewriter.replaceOpWithNewOp(op, constVecAttr); + return mlir::success(); + } +}; + //===----------------------------------------------------------------------===// // CIRSimplifyPass //===----------------------------------------------------------------------===// @@ -275,7 +300,8 @@ void populateMergeCleanupPatterns(RewritePatternSet &patterns) { patterns.add< SimplifyTernary, SimplifySelect, - SimplifySwitch + SimplifySwitch, + SimplifyVecSplat >(patterns.getContext()); // clang-format on } @@ -288,7 +314,7 @@ void CIRSimplifyPass::runOnOperation() { // Collect operations to apply patterns. llvm::SmallVector ops; getOperation()->walk([&](Operation *op) { - if (isa(op)) + if (isa(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4fdf8f9ec269..5f41e340e247 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -220,6 +220,39 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, return value; } +void convertSideEffectForCall(mlir::Operation *callOp, + cir::SideEffect sideEffect, + mlir::LLVM::MemoryEffectsAttr &memoryEffect, + bool &noUnwind, bool &willReturn) { + using mlir::LLVM::ModRefInfo; + + switch (sideEffect) { + case cir::SideEffect::All: + memoryEffect = {}; + noUnwind = false; + willReturn = false; + break; + + case cir::SideEffect::Pure: + memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( + callOp->getContext(), /*other=*/ModRefInfo::Ref, + /*argMem=*/ModRefInfo::Ref, + /*inaccessibleMem=*/ModRefInfo::Ref); + noUnwind = true; + willReturn = true; + break; + + case cir::SideEffect::Const: + memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( + callOp->getContext(), /*other=*/ModRefInfo::NoModRef, + /*argMem=*/ModRefInfo::NoModRef, + /*inaccessibleMem=*/ModRefInfo::NoModRef); + noUnwind = true; + willReturn = true; + break; + } +} + /// IntAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) { mlir::Location loc = parentOp->getLoc(); @@ -407,6 +440,14 @@ struct ConvertCIRToLLVMPass StringRef getArgument() const override { return "cir-flat-to-llvm"; } }; +mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite( + cir::AssumeOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto cond = adaptor.getPredicate(); + rewriter.replaceOpWithNewOp(op, cond); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite( cir::BrCondOp brOp, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -737,12 +778,18 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, mlir::FlatSymbolRefAttr calleeAttr) { llvm::SmallVector llvmResults; mlir::ValueTypeRange cirResults = op->getResultTypes(); + auto call = cast(op); if (converter->convertTypes(cirResults, llvmResults).failed()) return mlir::failure(); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); + + mlir::LLVM::MemoryEffectsAttr memoryEffects; + bool noUnwind = false; + bool willReturn = false; + convertSideEffectForCall(op, call.getSideEffect(), memoryEffects, noUnwind, + willReturn); mlir::LLVM::LLVMFunctionType llvmFnTy; if (calleeAttr) { // direct call @@ -767,10 +814,14 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands, assert(!cir::MissingFeatures::opCallLandingPad()); assert(!cir::MissingFeatures::opCallContinueBlock()); assert(!cir::MissingFeatures::opCallCallConv()); - assert(!cir::MissingFeatures::opCallSideEffect()); - rewriter.replaceOpWithNewOp(op, llvmFnTy, calleeAttr, - callOperands); + auto newOp = rewriter.replaceOpWithNewOp( + op, llvmFnTy, calleeAttr, callOperands); + if (memoryEffects) + newOp.setMemoryEffectsAttr(memoryEffects); + newOp.setNoUnwind(noUnwind); + newOp.setWillReturn(willReturn); + return mlir::success(); } @@ -901,6 +952,33 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( rewriter.eraseOp(op); return mlir::success(); } + } else if (const auto vecTy = mlir::dyn_cast(op.getType())) { + rewriter.replaceOp(op, lowerCirAttrAsValue(op, op.getValue(), rewriter, + getTypeConverter())); + return mlir::success(); + } else if (auto complexTy = mlir::dyn_cast(op.getType())) { + auto complexAttr = mlir::cast(op.getValue()); + mlir::Type complexElemTy = complexTy.getElementType(); + mlir::Type complexElemLLVMTy = typeConverter->convertType(complexElemTy); + + mlir::Attribute components[2]; + if (mlir::isa(complexElemTy)) { + components[0] = rewriter.getIntegerAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getReal()).getValue()); + components[1] = rewriter.getIntegerAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getImag()).getValue()); + } else { + components[0] = rewriter.getFloatAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getReal()).getValue()); + components[1] = rewriter.getFloatAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getImag()).getValue()); + } + + attr = rewriter.getArrayAttr(components); } else { return op.emitError() << "unsupported constant type " << op.getType(); } @@ -1782,6 +1860,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { dl); patterns.add< // clang-format off + CIRToLLVMAssumeOpLowering, CIRToLLVMBaseClassAddrOpLowering, CIRToLLVMBinOpLowering, CIRToLLVMBrCondOpLowering, @@ -1803,9 +1882,11 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMVecExtractOpLowering, CIRToLLVMVecInsertOpLowering, CIRToLLVMVecCmpOpLowering, + CIRToLLVMVecSplatOpLowering, CIRToLLVMVecShuffleOpLowering, CIRToLLVMVecShuffleDynamicOpLowering, - CIRToLLVMVecTernaryOpLowering + CIRToLLVMVecTernaryOpLowering, + CIRToLLVMComplexCreateOpLowering // clang-format on >(converter, patterns.getContext()); @@ -1956,6 +2037,56 @@ mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMVecSplatOpLowering::matchAndRewrite( + cir::VecSplatOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + // Vector splat can be implemented with an `insertelement` and a + // `shufflevector`, which is better than an `insertelement` for each + // element in the vector. Start with an undef vector. Insert the value into + // the first element. Then use a `shufflevector` with a mask of all 0 to + // fill out the entire vector with that value. + cir::VectorType vecTy = op.getType(); + mlir::Type llvmTy = typeConverter->convertType(vecTy); + mlir::Location loc = op.getLoc(); + mlir::Value poison = rewriter.create(loc, llvmTy); + + mlir::Value elementValue = adaptor.getValue(); + if (mlir::isa(elementValue.getDefiningOp())) { + // If the splat value is poison, then we can just use poison value + // for the entire vector. + rewriter.replaceOp(op, poison); + return mlir::success(); + } + + if (auto constValue = + dyn_cast(elementValue.getDefiningOp())) { + if (auto intAttr = dyn_cast(constValue.getValue())) { + mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get( + mlir::cast(llvmTy), intAttr.getValue()); + rewriter.replaceOpWithNewOp( + op, denseVec.getType(), denseVec); + return mlir::success(); + } + + if (auto fpAttr = dyn_cast(constValue.getValue())) { + mlir::DenseFPElementsAttr denseVec = mlir::DenseFPElementsAttr::get( + mlir::cast(llvmTy), fpAttr.getValue()); + rewriter.replaceOpWithNewOp( + op, denseVec.getType(), denseVec); + return mlir::success(); + } + } + + mlir::Value indexValue = + rewriter.create(loc, rewriter.getI64Type(), 0); + mlir::Value oneElement = rewriter.create( + loc, poison, elementValue, indexValue); + SmallVector zeroValues(vecTy.getSize(), 0); + rewriter.replaceOpWithNewOp(op, oneElement, + poison, zeroValues); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite( cir::VecShuffleOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -2041,6 +2172,24 @@ mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite( + cir::ComplexCreateOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type complexLLVMTy = + getTypeConverter()->convertType(op.getResult().getType()); + auto initialComplex = + rewriter.create(op->getLoc(), complexLLVMTy); + + auto realComplex = rewriter.create( + op->getLoc(), initialComplex, adaptor.getReal(), 0); + + auto complex = rewriter.create( + op->getLoc(), realComplex, adaptor.getImag(), 1); + + rewriter.replaceOp(op, complex); + return mlir::success(); +} + std::unique_ptr createConvertCIRToLLVMPass() { return std::make_unique(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 22d8a1e7c22e..ae7247332c66 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -29,6 +29,21 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr, mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage); +void convertSideEffectForCall(mlir::Operation *callOp, + cir::SideEffect sideEffect, + mlir::LLVM::MemoryEffectsAttr &memoryEffect, + bool &noUnwind, bool &willReturn); + +class CIRToLLVMAssumeOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::AssumeOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMBrCondOpLowering : public mlir::OpConversionPattern { public: @@ -367,6 +382,16 @@ public: mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVecSplatOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VecSplatOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMVecShuffleOpLowering : public mlir::OpConversionPattern { public: @@ -398,6 +423,16 @@ public: mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMComplexCreateOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexCreateOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 88b3a4943e0d..7e0a3cf5591c 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -124,17 +124,10 @@ namespace clang { extern llvm::cl::opt ClSanitizeGuardChecks; } -// Default filename used for profile generation. -static std::string getDefaultProfileGenName() { - return DebugInfoCorrelate || ProfileCorrelate != InstrProfCorrelator::NONE - ? "default_%m.proflite" - : "default_%m.profraw"; -} - // Path and name of file used for profile generation static std::string getProfileGenName(const CodeGenOptions &CodeGenOpts) { std::string FileName = CodeGenOpts.InstrProfileOutput.empty() - ? getDefaultProfileGenName() + ? llvm::driver::getDefaultProfileGenName() : CodeGenOpts.InstrProfileOutput; if (CodeGenOpts.ContinuousProfileSync) FileName = "%c" + FileName; diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 729758ddce56..f3ddf7bf9a46 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -1415,10 +1415,10 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( // Arrange for local static and local extern declarations to appear // to be local to this function as well, in case they're directly // referenced in a block. - for (DeclMapTy::const_iterator i = ldm.begin(), e = ldm.end(); i != e; ++i) { - const auto *var = dyn_cast(i->first); + for (const auto &KV : ldm) { + const auto *var = dyn_cast(KV.first); if (var && !var->hasLocalStorage()) - setAddrOfLocalVar(var, i->second); + setAddrOfLocalVar(var, KV.second); } // Begin building the function declaration. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c0b02a104d95..2c011a951986 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -17,7 +17,6 @@ #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" -#include "CGPointerAuthInfo.h" #include "CGRecordLayout.h" #include "CGValue.h" #include "CodeGenFunction.h" @@ -2033,7 +2032,7 @@ Value *CodeGenFunction::EmitCheckedArgForAssume(const Expr *E) { std::make_pair(ArgValue, CheckOrdinal), CheckHandler, {EmitCheckSourceLocation(E->getExprLoc()), llvm::ConstantInt::get(Builder.getInt8Ty(), BCK_AssumePassedFalse)}, - std::nullopt); + {}); return ArgValue; } diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 38f514304df5..dd26be74e561 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -1280,7 +1280,8 @@ llvm::Function *CGNVCUDARuntime::finalizeModule() { return nullptr; } if (CGM.getLangOpts().OffloadViaLLVM || - (CGM.getLangOpts().OffloadingNewDriver && RelocatableDeviceCode)) + (CGM.getLangOpts().OffloadingNewDriver && + (CGM.getLangOpts().HIP || RelocatableDeviceCode))) createOffloadingEntries(); else return makeModuleCtorFunction(); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a06455d25b1e..fd75de42515d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -83,17 +83,8 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { return llvm::CallingConv::AArch64_SVE_VectorCall; case CC_SpirFunction: return llvm::CallingConv::SPIR_FUNC; - case CC_DeviceKernel: { - if (CGM.getLangOpts().OpenCL) - return CGM.getTargetCodeGenInfo().getOpenCLKernelCallingConv(); - if (CGM.getTriple().isSPIROrSPIRV()) - return llvm::CallingConv::SPIR_KERNEL; - if (CGM.getTriple().isAMDGPU()) - return llvm::CallingConv::AMDGPU_KERNEL; - if (CGM.getTriple().isNVPTX()) - return llvm::CallingConv::PTX_Kernel; - llvm_unreachable("Unknown kernel calling convention"); - } + case CC_DeviceKernel: + return CGM.getTargetCodeGenInfo().getDeviceKernelCallingConv(); case CC_PreserveMost: return llvm::CallingConv::PreserveMost; case CC_PreserveAll: diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index 4ed2c5183c47..28ac9bf39635 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -962,8 +962,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough, // Append the prepared cleanup prologue from above. llvm::BasicBlock *NormalExit = Builder.GetInsertBlock(); - for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I) - InstsToAppend[I]->insertInto(NormalExit, NormalExit->end()); + for (llvm::Instruction *Inst : InstsToAppend) + Inst->insertInto(NormalExit, NormalExit->end()); // Optimistically hope that any fixups will continue falling through. for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 69d77f283db3..7ae99935c8ad 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -1121,9 +1121,9 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, EmitObjCAutoreleasePoolCleanup(token); } - for (unsigned i = 0, e = Decls.size(); i != e; ++i) - if (Decls[i]) - EmitRuntimeCall(Decls[i]); + for (llvm::Function *Decl : Decls) + if (Decl) + EmitRuntimeCall(Decl); Scope.ForceCleanup(); diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index e0367282355c..ad138b9876e8 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -319,9 +319,9 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { llvm::Function *F = dyn_cast(U); if (!F) return false; - for (auto BB = F->begin(), E = F->end(); BB != E; ++BB) { - if (BB->isLandingPad()) - if (!LandingPadHasOnlyCXXUses(BB->getLandingPadInst())) + for (llvm::BasicBlock &BB : *F) { + if (BB.isLandingPad()) + if (!LandingPadHasOnlyCXXUses(BB.getLandingPadInst())) return false; } } @@ -937,8 +937,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { filterTypes[0]->getType() : Int8PtrTy, filterTypes.size()); - for (unsigned i = 0, e = filterTypes.size(); i != e; ++i) - Filters.push_back(cast(filterTypes[i])); + for (llvm::Value *filterType : filterTypes) + Filters.push_back(cast(filterType)); llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters); LPadInst->addClause(FilterArray); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 3655e57bb8c4..b22e4ecdfe02 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3803,8 +3803,8 @@ void CodeGenFunction::EmitCheck( ArgTypes.push_back(Args.back()->getType()); } - for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) { - Args.push_back(EmitCheckValue(DynamicArgs[i])); + for (llvm::Value *DynamicArg : DynamicArgs) { + Args.push_back(EmitCheckValue(DynamicArg)); ArgTypes.push_back(IntPtrTy); } } @@ -4934,8 +4934,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Constant *BaseElts = Base.getExtVectorElts(); SmallVector CElts; - for (unsigned i = 0, e = Indices.size(); i != e; ++i) - CElts.push_back(BaseElts->getAggregateElement(Indices[i])); + for (unsigned Index : Indices) + CElts.push_back(BaseElts->getAggregateElement(Index)); llvm::Constant *CV = llvm::ConstantVector::get(CElts); return LValue::MakeExtVectorElt(Base.getExtVectorAddress(), CV, type, Base.getBaseInfo(), TBAAAccessInfo()); @@ -6662,8 +6662,8 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF, } // Unbind all the opaques now. - for (unsigned i = 0, e = opaques.size(); i != e; ++i) - opaques[i].unbind(CGF); + for (CodeGenFunction::OpaqueValueMappingData &opaque : opaques) + opaque.unbind(CGF); return result; } diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index caf67cfd7ed4..aba7fd03bee4 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -873,9 +873,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, } llvm::stable_sort(Bases); - for (unsigned I = 0, N = Bases.size(); I != N; ++I) { - BaseInfo &Base = Bases[I]; - + for (const BaseInfo &Base : Bases) { bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl; Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase, VTableClass, Offset + Base.Offset); diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index abebc201808b..58165185b671 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -12,6 +12,7 @@ #include "CGBuiltin.h" #include "CGHLSLRuntime.h" +#include "CodeGenFunction.h" using namespace clang; using namespace CodeGen; @@ -214,6 +215,44 @@ static Intrinsic::ID getWaveActiveMaxIntrinsic(llvm::Triple::ArchType Arch, } } +// Returns the mangled name for a builtin function that the SPIR-V backend +// will expand into a spec Constant. +static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType, + ASTContext &Context) { + // The parameter types for our conceptual intrinsic function. + QualType ClangParamTypes[] = {Context.IntTy, SpecConstantType}; + + // Create a temporary FunctionDecl for the builtin fuction. It won't be + // added to the AST. + FunctionProtoType::ExtProtoInfo EPI; + QualType FnType = + Context.getFunctionType(SpecConstantType, ClangParamTypes, EPI); + DeclarationName FuncName = &Context.Idents.get("__spirv_SpecConstant"); + FunctionDecl *FnDeclForMangling = FunctionDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), FuncName, FnType, /*TSI=*/nullptr, SC_Extern); + + // Attach the created parameter declarations to the function declaration. + SmallVector ParamDecls; + for (QualType ParamType : ClangParamTypes) { + ParmVarDecl *PD = ParmVarDecl::Create( + Context, FnDeclForMangling, SourceLocation(), SourceLocation(), + /*IdentifierInfo*/ nullptr, ParamType, /*TSI*/ nullptr, SC_None, + /*DefaultArg*/ nullptr); + ParamDecls.push_back(PD); + } + FnDeclForMangling->setParams(ParamDecls); + + // Get the mangled name. + std::string Name; + llvm::raw_string_ostream MangledNameStream(Name); + std::unique_ptr Mangler(Context.createMangleContext()); + Mangler->mangleName(FnDeclForMangling, MangledNameStream); + MangledNameStream.flush(); + + return Name; +} + Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -295,17 +334,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *SpaceOp = EmitScalarExpr(E->getArg(2)); Value *RangeOp = EmitScalarExpr(E->getArg(3)); Value *IndexOp = EmitScalarExpr(E->getArg(4)); + Value *Name = EmitScalarExpr(E->getArg(5)); // FIXME: NonUniformResourceIndex bit is not yet implemented // (llvm/llvm-project#135452) Value *NonUniform = llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false); - auto [IntrinsicID, HasNameArg] = + llvm::Intrinsic::ID IntrinsicID = CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(); - SmallVector Args{SpaceOp, RegisterOp, RangeOp, IndexOp, - NonUniform}; - if (HasNameArg) - Args.push_back(EmitScalarExpr(E->getArg(5))); + SmallVector Args{SpaceOp, RegisterOp, RangeOp, + IndexOp, NonUniform, Name}; return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args); } case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: { @@ -314,16 +352,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *RangeOp = EmitScalarExpr(E->getArg(2)); Value *IndexOp = EmitScalarExpr(E->getArg(3)); Value *OrderID = EmitScalarExpr(E->getArg(4)); + Value *Name = EmitScalarExpr(E->getArg(5)); // FIXME: NonUniformResourceIndex bit is not yet implemented // (llvm/llvm-project#135452) Value *NonUniform = llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false); - auto [IntrinsicID, HasNameArg] = + llvm::Intrinsic::ID IntrinsicID = CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic(); - SmallVector Args{OrderID, SpaceOp, RangeOp, IndexOp, NonUniform}; - if (HasNameArg) - Args.push_back(EmitScalarExpr(E->getArg(5))); + SmallVector Args{OrderID, SpaceOp, RangeOp, + IndexOp, NonUniform, Name}; return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args); } case Builtin::BI__builtin_hlsl_all: { @@ -638,35 +676,23 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, case Builtin::BI__builtin_hlsl_wave_active_sum: { // Due to the use of variadic arguments, explicitly retreive argument Value *OpExpr = EmitScalarExpr(E->getArg(0)); - llvm::FunctionType *FT = llvm::FunctionType::get( - OpExpr->getType(), ArrayRef{OpExpr->getType()}, false); Intrinsic::ID IID = getWaveActiveSumIntrinsic( getTarget().getTriple().getArch(), CGM.getHLSLRuntime(), E->getArg(0)->getType()); - // Get overloaded name - std::string Name = - Intrinsic::getName(IID, ArrayRef{OpExpr->getType()}, &CGM.getModule()); - return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, - /*Local=*/false, - /*AssumeConvergent=*/true), + return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration( + &CGM.getModule(), IID, {OpExpr->getType()}), ArrayRef{OpExpr}, "hlsl.wave.active.sum"); } case Builtin::BI__builtin_hlsl_wave_active_max: { // Due to the use of variadic arguments, explicitly retreive argument Value *OpExpr = EmitScalarExpr(E->getArg(0)); - llvm::FunctionType *FT = llvm::FunctionType::get( - OpExpr->getType(), ArrayRef{OpExpr->getType()}, false); Intrinsic::ID IID = getWaveActiveMaxIntrinsic( getTarget().getTriple().getArch(), CGM.getHLSLRuntime(), E->getArg(0)->getType()); - // Get overloaded name - std::string Name = - Intrinsic::getName(IID, ArrayRef{OpExpr->getType()}, &CGM.getModule()); - return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, - /*Local=*/false, - /*AssumeConvergent=*/true), + return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration( + &CGM.getModule(), IID, {OpExpr->getType()}), ArrayRef{OpExpr}, "hlsl.wave.active.max"); } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { @@ -701,18 +727,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, // create our function type. Value *OpExpr = EmitScalarExpr(E->getArg(0)); Value *OpIndex = EmitScalarExpr(E->getArg(1)); - llvm::FunctionType *FT = llvm::FunctionType::get( - OpExpr->getType(), ArrayRef{OpExpr->getType(), OpIndex->getType()}, - false); - - // Get overloaded name - std::string Name = - Intrinsic::getName(CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(), - ArrayRef{OpExpr->getType()}, &CGM.getModule()); - return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {}, - /*Local=*/false, - /*AssumeConvergent=*/true), - ArrayRef{OpExpr, OpIndex}, "hlsl.wave.readlane"); + return EmitRuntimeCall( + Intrinsic::getOrInsertDeclaration( + &CGM.getModule(), CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(), + {OpExpr->getType()}), + ArrayRef{OpExpr, OpIndex}, "hlsl.wave.readlane"); } case Builtin::BI__builtin_hlsl_elementwise_sign: { auto *Arg0 = E->getArg(0); @@ -774,6 +793,42 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return EmitRuntimeCall( Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID)); } + case Builtin::BI__builtin_get_spirv_spec_constant_bool: + case Builtin::BI__builtin_get_spirv_spec_constant_short: + case Builtin::BI__builtin_get_spirv_spec_constant_ushort: + case Builtin::BI__builtin_get_spirv_spec_constant_int: + case Builtin::BI__builtin_get_spirv_spec_constant_uint: + case Builtin::BI__builtin_get_spirv_spec_constant_longlong: + case Builtin::BI__builtin_get_spirv_spec_constant_ulonglong: + case Builtin::BI__builtin_get_spirv_spec_constant_half: + case Builtin::BI__builtin_get_spirv_spec_constant_float: + case Builtin::BI__builtin_get_spirv_spec_constant_double: { + llvm::Function *SpecConstantFn = getSpecConstantFunction(E->getType()); + llvm::Value *SpecId = EmitScalarExpr(E->getArg(0)); + llvm::Value *DefaultVal = EmitScalarExpr(E->getArg(1)); + llvm::Value *Args[] = {SpecId, DefaultVal}; + return Builder.CreateCall(SpecConstantFn, Args); + } } return nullptr; } + +llvm::Function *clang::CodeGen::CodeGenFunction::getSpecConstantFunction( + const clang::QualType &SpecConstantType) { + + // Find or create the declaration for the function. + llvm::Module *M = &CGM.getModule(); + std::string MangledName = + getSpecConstantFunctionName(SpecConstantType, getContext()); + llvm::Function *SpecConstantFn = M->getFunction(MangledName); + + if (!SpecConstantFn) { + llvm::Type *IntType = ConvertType(getContext().IntTy); + llvm::Type *RetTy = ConvertType(SpecConstantType); + llvm::Type *ArgTypes[] = {IntType, RetTy}; + llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, ArgTypes, false); + SpecConstantFn = llvm::Function::Create( + FnTy, llvm::GlobalValue::ExternalLinkage, MangledName, M); + } + return SpecConstantFn; +} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 720dac8383c0..3103f1798e14 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -35,7 +35,6 @@ #include "llvm/Support/Alignment.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" -#include using namespace clang; using namespace CodeGen; @@ -73,12 +72,17 @@ void addRootSignature(ArrayRef Elements, llvm::hlsl::rootsig::MetadataBuilder Builder(Ctx, Elements); MDNode *RootSignature = Builder.BuildRootSignature(); - MDNode *FnPairing = - MDNode::get(Ctx, {ValueAsMetadata::get(Fn), RootSignature}); + + // TODO: We need to wire the root signature version up through the frontend + // rather than hardcoding it. + ConstantAsMetadata *Version = + ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 2)); + MDNode *MDVals = + MDNode::get(Ctx, {ValueAsMetadata::get(Fn), RootSignature, Version}); StringRef RootSignatureValKey = "dx.rootsignatures"; auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey); - RootSignatureValMD->addOperand(FnPairing); + RootSignatureValMD->addOperand(MDVals); } } // namespace @@ -237,35 +241,6 @@ static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl, } } -std::pair -CGHLSLRuntime::getCreateHandleFromBindingIntrinsic() { - switch (getArch()) { - case llvm::Triple::dxil: - return std::pair(llvm::Intrinsic::dx_resource_handlefrombinding, true); - case llvm::Triple::spirv: - return std::pair(llvm::Intrinsic::spv_resource_handlefrombinding, false); - default: - llvm_unreachable("Intrinsic resource_handlefrombinding not supported by " - "target architecture"); - } -} - -std::pair -CGHLSLRuntime::getCreateHandleFromImplicitBindingIntrinsic() { - switch (getArch()) { - case llvm::Triple::dxil: - return std::pair(llvm::Intrinsic::dx_resource_handlefromimplicitbinding, - true); - case llvm::Triple::spirv: - return std::pair(llvm::Intrinsic::spv_resource_handlefromimplicitbinding, - false); - default: - llvm_unreachable( - "Intrinsic resource_handlefromimplicitbinding not supported by " - "target architecture"); - } -} - // Codegen for HLSLBufferDecl void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { @@ -405,6 +380,7 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::GlobalVariable::GeneralDynamicTLSModel, /* AddressSpace */ 7, /* isExternallyInitialized= */ true); addSPIRVBuiltinDecoration(GV, BuiltInID); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return B.CreateLoad(Ty, GV); } @@ -501,14 +477,6 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, } } -void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl *FD, - llvm::Function *Fn) { - if (FD->isInExportDeclContext()) { - const StringRef ExportAttrKindStr = "hlsl.export"; - Fn->addFnAttr(ExportAttrKindStr); - } -} - static void gatherFunctions(SmallVectorImpl &Fns, llvm::Module &M, bool CtorOrDtor) { const auto *GV = @@ -625,31 +593,27 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::ConstantInt::get(CGM.IntTy, RBA ? RBA->getSpaceNumber() : 0); Value *Name = nullptr; - auto [IntrinsicID, HasNameArg] = + llvm::Intrinsic::ID IntrinsicID = RBA->hasRegisterSlot() ? CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic() : CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic(); - if (HasNameArg) { - std::string Str(BufDecl->getName()); - std::string GlobalName(Str + ".str"); - Name = CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer(); - } + std::string Str(BufDecl->getName()); + std::string GlobalName(Str + ".str"); + Name = CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer(); // buffer with explicit binding if (RBA->hasRegisterSlot()) { auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber()); - SmallVector Args{Space, RegSlot, RangeSize, Index, NonUniform}; - if (Name) - Args.push_back(Name); + SmallVector Args{Space, RegSlot, RangeSize, + Index, NonUniform, Name}; initializeBuffer(CGM, GV, IntrinsicID, Args); } else { // buffer with implicit binding auto *OrderID = llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID()); - SmallVector Args{OrderID, Space, RangeSize, Index, NonUniform}; - if (Name) - Args.push_back(Name); + SmallVector Args{OrderID, Space, RangeSize, + Index, NonUniform, Name}; initializeBuffer(CGM, GV, IntrinsicID, Args); } } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb2b82fa1f5a..89d2aff85d91 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -118,6 +118,10 @@ public: GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer, resource_getpointer) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, + resource_handlefrombinding) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding, + resource_handlefromimplicitbinding) GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync, group_memory_barrier_with_group_sync) @@ -126,15 +130,6 @@ public: // End of reserved area for HLSL intrinsic getters. //===----------------------------------------------------------------------===// - // Returns ID of the intrinsic that initializes resource handle from binding - // and a bool value indicating whether the last argument of the intrinsic is - // the resource name (not all targets need that). - std::pair getCreateHandleFromBindingIntrinsic(); - - // Same as above but for implicit binding. - std::pair - getCreateHandleFromImplicitBindingIntrinsic(); - protected: CodeGenModule &CGM; diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 8a1b44a0c157..6f87444d3f67 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -3173,8 +3173,8 @@ ARCExprEmitter::visitPseudoObjectExpr(const PseudoObjectExpr *E) { } // Unbind all the opaques now. - for (unsigned i = 0, e = opaques.size(); i != e; ++i) - opaques[i].unbind(CGF); + for (CodeGenFunction::OpaqueValueMappingData &opaque : opaques) + opaque.unbind(CGF); return result; } diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 3fc837c12a92..d828702cbb87 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -1103,8 +1103,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { bool isNamed = !isNonASCII; if (isNamed) { StringName = ".objc_str_"; - for (int i=0,e=Str.size() ; i &Types = SelectorTable[Sel]; llvm::GlobalAlias *SelValue = nullptr; - for (SmallVectorImpl::iterator i = Types.begin(), - e = Types.end() ; i!=e ; i++) { - if (i->first == TypeEncoding) { - SelValue = i->second; + for (const TypedSelector &Type : Types) { + if (Type.first == TypeEncoding) { + SelValue = Type.second; break; } } @@ -3333,13 +3331,12 @@ CGObjCGNU::GenerateProtocolList(ArrayRef Protocols) { ProtocolList.addInt(LongTy, Protocols.size()); auto Elements = ProtocolList.beginArray(PtrToInt8Ty); - for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); - iter != endIter ; iter++) { + for (const std::string &Protocol : Protocols) { llvm::Constant *protocol = nullptr; - llvm::StringMap::iterator value = - ExistingProtocols.find(*iter); + llvm::StringMap::iterator value = + ExistingProtocols.find(Protocol); if (value == ExistingProtocols.end()) { - protocol = GenerateEmptyProtocol(*iter); + protocol = GenerateEmptyProtocol(Protocol); } else { protocol = value->getValue(); } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 1c23a8b4db91..a52c92cdbc83 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -2702,8 +2702,8 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0; Layout.push_back(inst); std::string BitMap; - for (unsigned i = 0, e = Layout.size(); i != e; i++) - BitMap += Layout[i]; + for (unsigned char C : Layout) + BitMap += C; if (CGM.getLangOpts().ObjCGCBitmapPrint) { if (ComputeByrefLayout) @@ -4225,9 +4225,8 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) { return; // Collect all the blocks in the function. - for (llvm::Function::iterator I = CGF.CurFn->begin(), E = CGF.CurFn->end(); - I != E; ++I) - BlocksBeforeTry.insert(&*I); + for (llvm::BasicBlock &BB : *CGF.CurFn) + BlocksBeforeTry.insert(&BB); llvm::FunctionType *AsmFnTy = GetAsmFnType(); @@ -4299,9 +4298,7 @@ void FragileHazards::emitHazardsInNewBlocks() { CGBuilderTy Builder(CGF, CGF.getLLVMContext()); // Iterate through all blocks, skipping those prior to the try. - for (llvm::Function::iterator FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); - FI != FE; ++FI) { - llvm::BasicBlock &BB = *FI; + for (llvm::BasicBlock &BB : *CGF.CurFn) { if (BlocksBeforeTry.count(&BB)) continue; @@ -4348,10 +4345,9 @@ void FragileHazards::collectLocals() { // Collect all the allocas currently in the function. This is // probably way too aggressive. llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock(); - for (llvm::BasicBlock::iterator I = Entry.begin(), E = Entry.end(); I != E; - ++I) - if (isa(*I) && !AllocasToIgnore.count(&*I)) - Locals.push_back(&*I); + for (llvm::Instruction &I : Entry) + if (isa(I) && !AllocasToIgnore.count(&I)) + Locals.push_back(&I); } llvm::FunctionType *FragileHazards::GetAsmFnType() { diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index dfb0fd14d93a..6e2f32022a01 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -220,9 +220,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); // Emit the handlers. - for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { - CatchHandler &Handler = Handlers[I]; - + for (CatchHandler &Handler : Handlers) { CGF.EmitBlock(Handler.Block); CodeGenFunction::LexicalScope Cleanups(CGF, Handler.Body->getSourceRange()); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 4173355491fd..8ccc37ef98a7 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4168,8 +4168,7 @@ void CGOpenMPRuntime::emitDepobjElements(CodeGenFunction &CGF, CGF, cast_or_null( Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts() : nullptr)); - for (unsigned I = 0, End = Data.DepExprs.size(); I < End; ++I) { - const Expr *E = Data.DepExprs[I]; + for (const Expr *E : Data.DepExprs) { llvm::Value *NumDeps; LValue Base; LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts()); @@ -4289,31 +4288,26 @@ std::pair CGOpenMPRuntime::emitDependClause( /*isSigned=*/false); } unsigned Pos = 0; - for (unsigned I = 0, End = Dependencies.size(); I < End; ++I) { - if (Dependencies[I].DepKind == OMPC_DEPEND_depobj || - Dependencies[I].IteratorExpr) + for (const OMPTaskDataTy::DependData &Dep : Dependencies) { + if (Dep.DepKind == OMPC_DEPEND_depobj || Dep.IteratorExpr) continue; - emitDependData(CGF, KmpDependInfoTy, &Pos, Dependencies[I], - DependenciesArray); + emitDependData(CGF, KmpDependInfoTy, &Pos, Dep, DependenciesArray); } // Copy regular dependencies with iterators. LValue PosLVal = CGF.MakeAddrLValue( CGF.CreateMemTemp(C.getSizeType(), "dep.counter.addr"), C.getSizeType()); CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal); - for (unsigned I = 0, End = Dependencies.size(); I < End; ++I) { - if (Dependencies[I].DepKind == OMPC_DEPEND_depobj || - !Dependencies[I].IteratorExpr) + for (const OMPTaskDataTy::DependData &Dep : Dependencies) { + if (Dep.DepKind == OMPC_DEPEND_depobj || !Dep.IteratorExpr) continue; - emitDependData(CGF, KmpDependInfoTy, &PosLVal, Dependencies[I], - DependenciesArray); + emitDependData(CGF, KmpDependInfoTy, &PosLVal, Dep, DependenciesArray); } // Copy final depobj arrays without iterators. if (HasDepobjDeps) { - for (unsigned I = 0, End = Dependencies.size(); I < End; ++I) { - if (Dependencies[I].DepKind != OMPC_DEPEND_depobj) + for (const OMPTaskDataTy::DependData &Dep : Dependencies) { + if (Dep.DepKind != OMPC_DEPEND_depobj) continue; - emitDepobjElements(CGF, KmpDependInfoTy, PosLVal, Dependencies[I], - DependenciesArray); + emitDepobjElements(CGF, KmpDependInfoTy, PosLVal, Dep, DependenciesArray); } } DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 9e27e634676d..2bc9cd549f01 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -2331,6 +2331,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(const OMPRequiresDecl *D) { case OffloadArch::GFX12_GENERIC: case OffloadArch::GFX1200: case OffloadArch::GFX1201: + case OffloadArch::GFX1250: case OffloadArch::AMDGCNSPIRV: case OffloadArch::Generic: case OffloadArch::GRANITERAPIDS: diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 232e2d8b43ca..e1310aed818a 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -972,18 +972,16 @@ void CGRecordLowering::determinePacked(bool NVBaseType) { CharUnits NVAlignment = CharUnits::One(); CharUnits NVSize = !NVBaseType && RD ? Layout.getNonVirtualSize() : CharUnits::Zero(); - for (std::vector::const_iterator Member = Members.begin(), - MemberEnd = Members.end(); - Member != MemberEnd; ++Member) { - if (!Member->Data) + for (const MemberInfo &Member : Members) { + if (!Member.Data) continue; // If any member falls at an offset that it not a multiple of its alignment, // then the entire record must be packed. - if (Member->Offset % getAlignment(Member->Data)) + if (Member.Offset % getAlignment(Member.Data)) Packed = true; - if (Member->Offset < NVSize) - NVAlignment = std::max(NVAlignment, getAlignment(Member->Data)); - Alignment = std::max(Alignment, getAlignment(Member->Data)); + if (Member.Offset < NVSize) + NVAlignment = std::max(NVAlignment, getAlignment(Member.Data)); + Alignment = std::max(Alignment, getAlignment(Member.Data)); } // If the size of the record (the capstone's offset) is not a multiple of the // record's alignment, it must be packed. @@ -1002,45 +1000,39 @@ void CGRecordLowering::determinePacked(bool NVBaseType) { void CGRecordLowering::insertPadding() { std::vector > Padding; CharUnits Size = CharUnits::Zero(); - for (std::vector::const_iterator Member = Members.begin(), - MemberEnd = Members.end(); - Member != MemberEnd; ++Member) { - if (!Member->Data) + for (const MemberInfo &Member : Members) { + if (!Member.Data) continue; - CharUnits Offset = Member->Offset; + CharUnits Offset = Member.Offset; assert(Offset >= Size); // Insert padding if we need to. if (Offset != - Size.alignTo(Packed ? CharUnits::One() : getAlignment(Member->Data))) + Size.alignTo(Packed ? CharUnits::One() : getAlignment(Member.Data))) Padding.push_back(std::make_pair(Size, Offset - Size)); - Size = Offset + getSize(Member->Data); + Size = Offset + getSize(Member.Data); } if (Padding.empty()) return; // Add the padding to the Members list and sort it. - for (std::vector >::const_iterator - Pad = Padding.begin(), PadEnd = Padding.end(); - Pad != PadEnd; ++Pad) - Members.push_back(StorageInfo(Pad->first, getByteArrayType(Pad->second))); + for (const auto &Pad : Padding) + Members.push_back(StorageInfo(Pad.first, getByteArrayType(Pad.second))); llvm::stable_sort(Members); } void CGRecordLowering::fillOutputFields() { - for (std::vector::const_iterator Member = Members.begin(), - MemberEnd = Members.end(); - Member != MemberEnd; ++Member) { - if (Member->Data) - FieldTypes.push_back(Member->Data); - if (Member->Kind == MemberInfo::Field) { - if (Member->FD) - Fields[Member->FD->getCanonicalDecl()] = FieldTypes.size() - 1; + for (const MemberInfo &Member : Members) { + if (Member.Data) + FieldTypes.push_back(Member.Data); + if (Member.Kind == MemberInfo::Field) { + if (Member.FD) + Fields[Member.FD->getCanonicalDecl()] = FieldTypes.size() - 1; // A field without storage must be a bitfield. - if (!Member->Data) - setBitFieldInfo(Member->FD, Member->Offset, FieldTypes.back()); - } else if (Member->Kind == MemberInfo::Base) - NonVirtualBases[Member->RD] = FieldTypes.size() - 1; - else if (Member->Kind == MemberInfo::VBase) - VirtualBases[Member->RD] = FieldTypes.size() - 1; + if (!Member.Data) + setBitFieldInfo(Member.FD, Member.Offset, FieldTypes.back()); + } else if (Member.Kind == MemberInfo::Base) + NonVirtualBases[Member.RD] = FieldTypes.size() - 1; + else if (Member.Kind == MemberInfo::VBase) + VirtualBases[Member.RD] = FieldTypes.size() - 1; } } @@ -1224,20 +1216,18 @@ void CGRecordLayout::print(raw_ostream &OS) const { // Print bit-field infos in declaration order. std::vector > BFIs; - for (llvm::DenseMap::const_iterator - it = BitFields.begin(), ie = BitFields.end(); - it != ie; ++it) { - const RecordDecl *RD = it->first->getParent(); + for (const auto &BitField : BitFields) { + const RecordDecl *RD = BitField.first->getParent(); unsigned Index = 0; - for (RecordDecl::field_iterator - it2 = RD->field_begin(); *it2 != it->first; ++it2) + for (RecordDecl::field_iterator it2 = RD->field_begin(); + *it2 != BitField.first; ++it2) ++Index; - BFIs.push_back(std::make_pair(Index, &it->second)); + BFIs.push_back(std::make_pair(Index, &BitField.second)); } llvm::array_pod_sort(BFIs.begin(), BFIs.end()); - for (unsigned i = 0, e = BFIs.size(); i != e; ++i) { + for (auto &BFI : BFIs) { OS.indent(4); - BFIs[i].second->print(OS); + BFI.second->print(OS); OS << "\n"; } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 4d3273e6de1f..883c13dd0218 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -765,10 +765,9 @@ void CodeGenFunction::LexicalScope::rescopeLabels() { = CGF.EHStack.getInnermostNormalCleanup(); // Change the scope depth of all the labels. - for (SmallVectorImpl::const_iterator - i = Labels.begin(), e = Labels.end(); i != e; ++i) { - assert(CGF.LabelMap.count(*i)); - JumpDest &dest = CGF.LabelMap.find(*i)->second; + for (const LabelDecl *Label : Labels) { + assert(CGF.LabelMap.count(Label)); + JumpDest &dest = CGF.LabelMap.find(Label)->second; assert(dest.getScopeDepth().isValid()); assert(innermostScope.encloses(dest.getScopeDepth())); dest.setScopeDepth(innermostScope); @@ -2358,8 +2357,8 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { // Okay, we can dead code eliminate everything except this case. Emit the // specified series of statements and we're good. - for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i) - EmitStmt(CaseStmts[i]); + for (const Stmt *CaseStmt : CaseStmts) + EmitStmt(CaseStmt); incrementProfileCounter(&S); PGO->markStmtMaybeUsed(S.getBody()); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 1f5eb427b566..5493cc92bd8b 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -273,8 +273,8 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) { std::unique_ptr OptRecordFile = std::move(*OptRecordFileOrErr); - if (OptRecordFile && - CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone) + if (OptRecordFile && CodeGenOpts.getProfileUse() != + llvm::driver::ProfileInstrKind::ProfileNone) Ctx.setDiagnosticsHotnessRequested(true); if (CodeGenOpts.MisExpect) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 25d207ad6000..4023022bca16 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -943,7 +943,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } - if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) { + if (CGM.getCodeGenOpts().getProfileInstr() != + llvm::driver::ProfileInstrKind::ProfileNone) { switch (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc)) { case ProfileList::Skip: Fn->addFnAttr(llvm::Attribute::SkipProfile); @@ -1266,7 +1267,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (FD->hasAttr()) { CGM.getHLSLRuntime().emitEntryFunction(FD, Fn); } - CGM.getHLSLRuntime().setHLSLFunctionAttributes(FD, Fn); } EmitFunctionProlog(*CurFnInfo, CurFn, Args); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ea7aa3bfdfcd..e209ea0f31e5 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4853,6 +4853,12 @@ public: llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + + // Returns a builtin function that the SPIR-V backend will expand into a spec + // constant. + llvm::Function * + getSpecConstantFunction(const clang::QualType &SpecConstantType); + llvm::Value *EmitDirectXBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 26c2d31381b2..cd20b2340acf 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -414,6 +414,11 @@ CodeGenModule::CodeGenModule(ASTContext &C, CodeGenOpts.CoverageNotesFile.size() || CodeGenOpts.CoverageDataFile.size()) DebugInfo.reset(new CGDebugInfo(*this)); + else if (getTriple().isOSWindows()) + // On Windows targets, we want to emit compiler info even if debug info is + // otherwise disabled. Use a temporary CGDebugInfo instance to emit only + // basic compiler metadata. + CGDebugInfo(*this); Block.GlobalUniqueCount = 0; @@ -964,7 +969,7 @@ void CodeGenModule::Release() { llvm::ConstantArray::get(ATy, UsedArray), "__clang_gpu_used_external"); addCompilerUsedGlobal(GV); } - if (LangOpts.HIP && !getLangOpts().OffloadingNewDriver) { + if (LangOpts.HIP) { // Emit a unique ID so that host and device binaries from the same // compilation unit can be associated. auto *GV = new llvm::GlobalVariable( @@ -1051,7 +1056,7 @@ void CodeGenModule::Release() { "StrictVTablePointersRequirement", llvm::MDNode::get(VMContext, Ops)); } - if (getModuleDebugInfo()) + if (getModuleDebugInfo() || getTriple().isOSWindows()) // We support a single version in the linked module. The LLVM // parser will drop debug info with a different version number // (and warn about it, too). @@ -1314,8 +1319,10 @@ void CodeGenModule::Release() { 1); // Enable unwind v2 (epilog). - if (CodeGenOpts.WinX64EHUnwindV2) - getModule().addModuleFlag(llvm::Module::Warning, "winx64-eh-unwindv2", 1); + if (CodeGenOpts.getWinX64EHUnwindV2() != llvm::WinX64EHUnwindV2Mode::Disabled) + getModule().addModuleFlag( + llvm::Module::Warning, "winx64-eh-unwindv2", + static_cast(CodeGenOpts.getWinX64EHUnwindV2())); // Indicate whether this Module was compiled with -fopenmp if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd) @@ -1661,6 +1668,11 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, return; } + if (Context.getLangOpts().HLSL && !D->isInExportDeclContext()) { + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + return; + } + if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) { // Reject incompatible dlllstorage and visibility annotations. if (!LV.isVisibilityExplicit()) @@ -3608,7 +3620,7 @@ CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn, // If the profile list is empty, then instrument everything. if (ProfileList.isEmpty()) return ProfileList::Allow; - CodeGenOptions::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr(); + llvm::driver::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr(); // First, check the function name. if (auto V = ProfileList.isFunctionExcluded(Fn->getName(), Kind)) return *V; diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 514cc1d9015e..a18155983429 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1836,9 +1836,9 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, // Create all the vftables at once in order to make sure each vftable has // a unique mangled name. llvm::StringSet<> ObservedMangledNames; - for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { + for (const auto &VFPtr : VFPtrs) { SmallString<256> Name; - mangleVFTableName(getMangleContext(), RD, *VFPtrs[J], Name); + mangleVFTableName(getMangleContext(), RD, *VFPtr, Name); if (!ObservedMangledNames.insert(Name.str()).second) llvm_unreachable("Already saw this mangling before?"); } diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 09a7d79ae4af..8c1fee8c974f 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -186,8 +186,8 @@ namespace { HandlingTopLevelDeclRAII HandlingDecl(*this); // Make sure to emit all elements of a Decl. - for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) - Builder->EmitTopLevelDecl(*I); + for (auto &I : DG) + Builder->EmitTopLevelDecl(I); return true; } diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index dab311903f6d..6738d4be6dd2 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -4560,10 +4560,10 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID, Ops.insert(&Ops[1], Builder.getInt32(/*SV_ALL*/ 31)); // Predicates must match the main datatype. - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (auto PredTy = dyn_cast(Ops[i]->getType())) + for (Value *&Op : Ops) + if (auto PredTy = dyn_cast(Op->getType())) if (PredTy->getElementType()->isIntegerTy(1)) - Ops[i] = EmitSVEPredicateCast(Ops[i], getSVEType(TypeFlags)); + Op = EmitSVEPredicateCast(Op, getSVEType(TypeFlags)); // Splat scalar operand to vector (intrinsics with _n infix) if (TypeFlags.hasSplatOperand()) { @@ -4936,10 +4936,10 @@ Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID, } // Predicates must match the main datatype. - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (auto PredTy = dyn_cast(Ops[i]->getType())) + for (Value *&Op : Ops) + if (auto PredTy = dyn_cast(Op->getType())) if (PredTy->getElementType()->isIntegerTy(1)) - Ops[i] = EmitSVEPredicateCast(Ops[i], getSVEType(TypeFlags)); + Op = EmitSVEPredicateCast(Op, getSVEType(TypeFlags)); Function *F = TypeFlags.isOverloadNone() @@ -8036,8 +8036,8 @@ BuildVector(ArrayRef Ops) { // If this is a constant vector, create a ConstantVector. if (AllConstants) { SmallVector CstOps; - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - CstOps.push_back(cast(Ops[i])); + for (llvm::Value *Op : Ops) + CstOps.push_back(cast(Op)); return llvm::ConstantVector::get(CstOps); } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index f3df92c44bb6..277d69daf493 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -103,18 +103,21 @@ TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, Opt += Lib; } -unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { - // OpenCL kernels are called via an explicit runtime API with arguments - // set with clSetKernelArg(), not as normal sub-functions. - // Return SPIR_KERNEL by default as the kernel calling convention to - // ensure the fingerprint is fixed such way that each OpenCL argument - // gets one matching argument in the produced kernel function argument - // list to enable feasible implementation of clSetKernelArg() with - // aggregates etc. In case we would use the default C calling conv here, - // clSetKernelArg() might break depending on the target-specific - // conventions; different targets might split structs passed as values - // to multiple function arguments etc. - return llvm::CallingConv::SPIR_KERNEL; +unsigned TargetCodeGenInfo::getDeviceKernelCallingConv() const { + if (getABIInfo().getContext().getLangOpts().OpenCL) { + // Device kernels are called via an explicit runtime API with arguments, + // such as set with clSetKernelArg() for OpenCL, not as normal + // sub-functions. Return SPIR_KERNEL by default as the kernel calling + // convention to ensure the fingerprint is fixed such way that each kernel + // argument gets one matching argument in the produced kernel function + // argument list to enable feasible implementation of clSetKernelArg() with + // aggregates etc. In case we would use the default C calling conv here, + // clSetKernelArg() might break depending on the target-specific + // conventions; different targets might split structs passed as values + // to multiple function arguments etc. + return llvm::CallingConv::SPIR_KERNEL; + } + llvm_unreachable("Unknown kernel calling convention"); } void TargetCodeGenInfo::setOCLKernelStubCallingConvention( diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 2783e222eb80..b4057d369f98 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -298,8 +298,8 @@ public: llvm::StringRef Value, llvm::SmallString<32> &Opt) const {} - /// Get LLVM calling convention for OpenCL kernel. - virtual unsigned getOpenCLKernelCallingConv() const; + /// Get LLVM calling convention for device kernels. + virtual unsigned getDeviceKernelCallingConv() const; /// Get target specific null pointer. /// \param T is the LLVM type of the null pointer. diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index 3efe6ab4ea9c..b82c46966cf0 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -507,7 +507,8 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, if (FDTy->isArrayType()) FDTy = getContext().getBaseElementType(FDTy); return (FDTy->isPointerOrReferenceType() && - getContext().getTypeSize(FDTy) == 64) || + getContext().getTypeSize(FDTy) == 64 && + !FDTy->getPointeeType().hasAddressSpace()) || Self(Self, FDTy); }); }; diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 8660373c3927..47a552a7bf49 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -304,7 +304,7 @@ public: void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; - unsigned getOpenCLKernelCallingConv() const override; + unsigned getDeviceKernelCallingConv() const override; llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const override; @@ -431,7 +431,7 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( F->addFnAttr("amdgpu-ieee", "false"); } -unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned AMDGPUTargetCodeGenInfo::getDeviceKernelCallingConv() const { return llvm::CallingConv::AMDGPU_KERNEL; } diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index ad802c9131de..82bdfe2666b5 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -78,7 +78,7 @@ public: return true; } - unsigned getOpenCLKernelCallingConv() const override { + unsigned getDeviceKernelCallingConv() const override { return llvm::CallingConv::PTX_Kernel; } diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index 2f1e43cdc8cc..afa23bffcd07 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -51,7 +51,7 @@ public: getABIInfo().getDataLayout().getAllocaAddrSpace()); } - unsigned getOpenCLKernelCallingConv() const override; + unsigned getDeviceKernelCallingConv() const override; llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override; llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *Ty, @@ -219,7 +219,7 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { } } -unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned CommonSPIRTargetCodeGenInfo::getDeviceKernelCallingConv() const { return llvm::CallingConv::SPIR_KERNEL; } diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b36a6e139665..0f59caac2323 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -1462,9 +1462,8 @@ public: // defines varargs anyway. if (fnType->getCallConv() == CC_C) { bool HasAVXType = false; - for (CallArgList::const_iterator - it = args.begin(), ie = args.end(); it != ie; ++it) { - if (getABIInfo().isPassedUsingAVXType(it->Ty)) { + for (const CallArg &arg : args) { + if (getABIInfo().isPassedUsingAVXType(arg.Ty)) { HasAVXType = true; break; } diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 44e16edfb1cc..3cfd671e9d8f 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -66,6 +66,7 @@ add_clang_library(clangDriver ToolChains/HLSL.cpp ToolChains/Hurd.cpp ToolChains/Linux.cpp + ToolChains/Managarm.cpp ToolChains/MipsLinux.cpp ToolChains/MinGW.cpp ToolChains/MSP430.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index eb60d907d221..2d055ffa17a8 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -33,6 +33,7 @@ #include "ToolChains/Linux.h" #include "ToolChains/MSP430.h" #include "ToolChains/MSVC.h" +#include "ToolChains/Managarm.h" #include "ToolChains/MinGW.h" #include "ToolChains/MipsLinux.h" #include "ToolChains/NaCl.h" @@ -4330,6 +4331,14 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, YcArg = YuArg = nullptr; } + if (Args.hasArg(options::OPT_include_pch) && + Args.hasArg(options::OPT_ignore_pch)) { + // If -ignore-pch is used, -include-pch is disabled. Since -emit-pch is + // CC1option, it will not be added to command argments if -ignore-pch is + // used. + Args.eraseArg(options::OPT_include_pch); + } + bool LinkOnly = phases::Link == FinalPhase && Inputs.size() > 0; for (auto &I : Inputs) { types::ID InputType = I.first; @@ -4423,6 +4432,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, options::OPT_no_offload_new_driver, C.isOffloadingHostKind(Action::OFK_Cuda)); + bool HIPNoRDC = + C.isOffloadingHostKind(Action::OFK_HIP) && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); + // Builder to be used to build offloading actions. std::unique_ptr OffloadBuilder = !UseNewOffloadingDriver @@ -4556,7 +4569,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Check if this Linker Job should emit a static library. if (ShouldEmitStaticLibrary(Args)) { LA = C.MakeAction(LinkerInputs, types::TY_Image); - } else if (UseNewOffloadingDriver || + } else if ((UseNewOffloadingDriver && !HIPNoRDC) || Args.hasArg(options::OPT_offload_link)) { LA = C.MakeAction(LinkerInputs, types::TY_Image); LA->propagateHostOffloadInfo(C.getActiveOffloadKinds(), @@ -4867,10 +4880,31 @@ Action *Driver::BuildOffloadingActions(Compilation &C, const InputTy &Input, StringRef CUID, Action *HostAction) const { // Don't build offloading actions if explicitly disabled or we do not have a - // valid source input and compile action to embed it in. If preprocessing only - // ignore embedding. - if (offloadHostOnly() || !types::isSrcFile(Input.first) || - !(isa(HostAction) || + // valid source input. + if (offloadHostOnly() || !types::isSrcFile(Input.first)) + return HostAction; + + bool HIPNoRDC = + C.isOffloadingHostKind(Action::OFK_HIP) && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); + + // For HIP non-rdc non-device-only compilation, create a linker wrapper + // action for each host object to link, bundle and wrap device files in + // it. + if ((isa(HostAction) || + (isa(HostAction) && + HostAction->getType() == types::TY_LTO_BC)) && + HIPNoRDC && !offloadDeviceOnly()) { + ActionList AL{HostAction}; + HostAction = C.MakeAction(AL, types::TY_Object); + HostAction->propagateHostOffloadInfo(C.getActiveOffloadKinds(), + /*BoundArch=*/nullptr); + return HostAction; + } + + // Don't build offloading actions if we do not have a compile action. If + // preprocessing only ignore embedding. + if (!(isa(HostAction) || getFinalPhase(Args) == phases::Preprocess)) return HostAction; @@ -4966,12 +5000,12 @@ Action *Driver::BuildOffloadingActions(Compilation &C, } } - // Compiling HIP in non-RDC mode requires linking each action individually. + // Compiling HIP in device-only non-RDC mode requires linking each action + // individually. for (Action *&A : DeviceActions) { if ((A->getType() != types::TY_Object && A->getType() != types::TY_LTO_BC) || - Kind != Action::OFK_HIP || - Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) + !HIPNoRDC || !offloadDeviceOnly()) continue; ActionList LinkerInput = {A}; A = C.MakeAction(LinkerInput, types::TY_Image); @@ -4995,12 +5029,12 @@ Action *Driver::BuildOffloadingActions(Compilation &C, } } - // HIP code in non-RDC mode will bundle the output if it invoked the linker. + // HIP code in device-only non-RDC mode will bundle the output if it invoked + // the linker. bool ShouldBundleHIP = - C.isOffloadingHostKind(Action::OFK_HIP) && + HIPNoRDC && offloadDeviceOnly() && Args.hasFlag(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output, true) && - !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) && !llvm::any_of(OffloadActions, [](Action *A) { return A->getType() != types::TY_Image; }); @@ -5020,11 +5054,9 @@ Action *Driver::BuildOffloadingActions(Compilation &C, C.MakeAction(OffloadActions, types::TY_CUDA_FATBIN); DDep.add(*FatbinAction, *C.getSingleOffloadToolChain(), nullptr, Action::OFK_Cuda); - } else if (C.isOffloadingHostKind(Action::OFK_HIP) && - !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, - false)) { - // If we are not in RDC-mode we just emit the final HIP fatbinary for each - // translation unit, linking each input individually. + } else if (HIPNoRDC && offloadDeviceOnly()) { + // If we are in device-only non-RDC-mode we just emit the final HIP + // fatbinary for each translation unit, linking each input individually. Action *FatbinAction = C.MakeAction(OffloadActions, types::TY_HIP_FATBIN); DDep.add(*FatbinAction, *C.getSingleOffloadToolChain(), @@ -5177,8 +5209,11 @@ Action *Driver::ConstructPhaseAction( (((Input->getOffloadingToolChain() && Input->getOffloadingToolChain()->getTriple().isAMDGPU()) || TargetDeviceOffloadKind == Action::OFK_HIP) && - (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, - false) || + ((Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false) || + (Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false) && + !offloadDeviceOnly())) || TargetDeviceOffloadKind == Action::OFK_OpenMP))) { types::ID Output = Args.hasArg(options::OPT_S) && @@ -6816,6 +6851,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Fuchsia: TC = std::make_unique(*this, Target, Args); break; + case llvm::Triple::Managarm: + TC = std::make_unique(*this, Target, Args); + break; case llvm::Triple::Solaris: TC = std::make_unique(*this, Target, Args); break; @@ -6823,11 +6861,17 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = std::make_unique(*this, Target, Args); break; case llvm::Triple::AMDHSA: { - bool DL = - usesInput(Args, types::isOpenCL) || usesInput(Args, types::isLLVMIR); - TC = DL ? std::make_unique(*this, Target, Args) - : std::make_unique(*this, Target, - Args); + if (Target.getArch() == llvm::Triple::spirv64) { + TC = std::make_unique(*this, Target, + Args); + } else { + bool DL = usesInput(Args, types::isOpenCL) || + usesInput(Args, types::isLLVMIR); + TC = DL ? std::make_unique(*this, Target, + Args) + : std::make_unique(*this, Target, + Args); + } break; } case llvm::Triple::AMDPAL: diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index cf9c24f1e1cd..b7564a0495da 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -525,7 +525,8 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, "hipstdpar_lib.hpp"}); }; - if (DriverArgs.hasArg(options::OPT_nogpuinc)) { + if (!DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true)) { if (HasHipStdPar) HandleHipStdPar(); diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index b0523a7f4e40..731076d9754a 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -326,8 +326,78 @@ constexpr struct { {"attiny1624", "avrxmega3", "avrxmega3", 0x803800}, {"attiny1626", "avrxmega3", "avrxmega3", 0x803800}, {"attiny1627", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny3224", "avrxmega3", "avrxmega3", 0x803400}, + {"attiny3226", "avrxmega3", "avrxmega3", 0x803400}, + {"attiny3227", "avrxmega3", "avrxmega3", 0x803400}, {"attiny3216", "avrxmega3", "avrxmega3", 0x803800}, {"attiny3217", "avrxmega3", "avrxmega3", 0x803800}, + + // gcc 14 additions: + + {"avr64da28", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64da32", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64da48", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64da64", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64db28", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64db32", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64db48", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64db64", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64dd14", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64dd20", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64dd28", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64dd32", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64du28", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64du32", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64ea28", "avrxmega2", "avrxmega2", 0x806800}, + {"avr64ea32", "avrxmega2", "avrxmega2", 0x806800}, + {"avr64ea48", "avrxmega2", "avrxmega2", 0x806800}, + {"avr64sd28", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64sd32", "avrxmega2", "avrxmega2", 0x806000}, + {"avr64sd48", "avrxmega2", "avrxmega2", 0x806000}, + + {"avr16dd20", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16dd28", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16dd32", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16du14", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16du20", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16du28", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16du32", "avrxmega3", "avrxmega3", 0x807800}, + {"avr32da28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32da32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32da48", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32db28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32db32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32db48", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32dd14", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32dd20", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32dd28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32dd32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32du14", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32du20", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32du28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32du32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr16eb14", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16eb20", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16eb28", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16eb32", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16ea28", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16ea32", "avrxmega3", "avrxmega3", 0x807800}, + {"avr16ea48", "avrxmega3", "avrxmega3", 0x807800}, + {"avr32ea28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32ea32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32ea48", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32sd20", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32sd28", "avrxmega3", "avrxmega3", 0x807000}, + {"avr32sd32", "avrxmega3", "avrxmega3", 0x807000}, + {"avr128da28", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128da32", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128da48", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128da64", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128db28", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128db32", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128db48", "avrxmega4", "avrxmega4", 0x804000}, + {"avr128db64", "avrxmega4", "avrxmega4", 0x804000}, + }; std::string GetMCUSubPath(StringRef MCUName) { diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp index 3318e498a74f..33a655870b01 100644 --- a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp +++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -252,6 +252,7 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, Features.push_back("+lsx"); } else /*-mno-lsx*/ { Features.push_back("-lsx"); + Features.push_back("-lasx"); } } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index d561d3b61c2e..74f2dd52da6b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -939,7 +939,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && !Args.hasArg(options::OPT_nostdinc) && - !Args.hasArg(options::OPT_nogpuinc) && + Args.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true) && getToolChain().getTriple().isGPU()) { if (!Args.hasArg(options::OPT_nobuiltininc)) { // Add openmp_wrappers/* to our system include path. This lets us wrap @@ -1122,7 +1123,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // TODO: This should be moved to `AddClangSystemIncludeArgs` by passing the // OffloadKind as an argument. if (!Args.hasArg(options::OPT_nostdinc) && - !Args.hasArg(options::OPT_nogpuinc) && + Args.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true) && !Args.hasArg(options::OPT_nobuiltininc)) { // Without an offloading language we will include these headers directly. // Offloading languages will instead only use the declarations stored in @@ -2833,8 +2835,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef Float16ExcessPrecision = ""; StringRef BFloat16ExcessPrecision = ""; LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None; - std::string ComplexRangeStr = ""; - std::string GccRangeComplexOption = ""; + std::string ComplexRangeStr; + std::string GccRangeComplexOption; + std::string LastComplexRangeOption; auto setComplexRange = [&](LangOptions::ComplexRangeKind NewRange) { // Warn if user expects to perform full implementation of complex @@ -2918,6 +2921,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, EmitComplexRangeDiag(D, GccRangeComplexOption, "-fcx-limited-range"); } GccRangeComplexOption = "-fcx-limited-range"; + LastComplexRangeOption = A->getSpelling(); Range = LangOptions::ComplexRangeKind::CX_Basic; break; case options::OPT_fno_cx_limited_range: @@ -2931,6 +2935,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, "-fno-cx-limited-range"); } GccRangeComplexOption = "-fno-cx-limited-range"; + LastComplexRangeOption = A->getSpelling(); Range = LangOptions::ComplexRangeKind::CX_Full; break; case options::OPT_fcx_fortran_rules: @@ -2940,6 +2945,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, else EmitComplexRangeDiag(D, GccRangeComplexOption, "-fcx-fortran-rules"); GccRangeComplexOption = "-fcx-fortran-rules"; + LastComplexRangeOption = A->getSpelling(); Range = LangOptions::ComplexRangeKind::CX_Improved; break; case options::OPT_fno_cx_fortran_rules: @@ -2952,6 +2958,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, "-fno-cx-fortran-rules"); } GccRangeComplexOption = "-fno-cx-fortran-rules"; + LastComplexRangeOption = A->getSpelling(); Range = LangOptions::ComplexRangeKind::CX_Full; break; case options::OPT_fcomplex_arithmetic_EQ: { @@ -2986,6 +2993,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ComplexArithmeticStr(RangeVal)); } } + LastComplexRangeOption = + Args.MakeArgString(A->getSpelling() + A->getValue()); Range = RangeVal; break; } @@ -3039,6 +3048,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } else D.Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << Val; + LastComplexRangeOption = A->getSpelling(); break; } @@ -3224,6 +3234,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, [[fallthrough]]; case options::OPT_ffast_math: applyFastMath(true); + LastComplexRangeOption = A->getSpelling(); if (A->getOption().getID() == options::OPT_Ofast) LastFpContractOverrideOption = "-Ofast"; else @@ -3241,6 +3252,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ApproxFunc = false; SignedZeros = true; restoreFPContractState(); + // If the last specified option related to complex range is not + // -ffast-math or -ffp-model=, emit warning. + if (LastComplexRangeOption != "-ffast-math" && + LastComplexRangeOption != "-ffp-model=" && + Range != LangOptions::ComplexRangeKind::CX_Full) + EmitComplexRangeDiag(D, LastComplexRangeOption, "-fno-fast-math"); + Range = LangOptions::ComplexRangeKind::CX_None; + LastComplexRangeOption = ""; + GccRangeComplexOption = ""; LastFpContractOverrideOption = ""; break; } // End switch (A->getOption().getID()) @@ -5186,7 +5206,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-module-interface"); else if (JA.getType() == types::TY_HeaderUnit) CmdArgs.push_back("-emit-header-unit"); - else + else if (!Args.hasArg(options::OPT_ignore_pch)) CmdArgs.push_back("-emit-pch"); } else if (isa(JA)) { CmdArgs.push_back("-verify-pch"); @@ -5243,7 +5263,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { - CmdArgs.push_back("-emit-pch"); + if (!Args.hasArg(options::OPT_ignore_pch)) + CmdArgs.push_back("-emit-pch"); } else if (JA.getType() == types::TY_ModuleFile) { CmdArgs.push_back("-module-file-info"); } else if (JA.getType() == types::TY_RewrittenObjC) { @@ -5685,11 +5706,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Triple.getArch() != llvm::Triple::x86_64) D.Diag(diag::err_drv_unsupported_opt_for_target) << Name << Triple.getArchName(); - } else if (Name == "libmvec" || Name == "AMDLIBM") { + } else if (Name == "AMDLIBM") { if (Triple.getArch() != llvm::Triple::x86 && Triple.getArch() != llvm::Triple::x86_64) D.Diag(diag::err_drv_unsupported_opt_for_target) << Name << Triple.getArchName(); + } else if (Name == "libmvec") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64 && + Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); } else if (Name == "SLEEF" || Name == "ArmPL") { if (Triple.getArch() != llvm::Triple::aarch64 && Triple.getArch() != llvm::Triple::aarch64_be && @@ -6891,9 +6919,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign, options::OPT_mno_stackrealign); - if (Args.hasArg(options::OPT_mstack_alignment)) { - StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); - CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); + if (const Arg *A = Args.getLastArg(options::OPT_mstack_alignment)) { + StringRef Value = A->getValue(); + int64_t Alignment = 0; + if (Value.getAsInteger(10, Alignment) || Alignment < 0) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + else if (Alignment & (Alignment - 1)) + D.Diag(diag::err_drv_alignment_not_power_of_two) + << A->getAsString(Args) << Value; + else + CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + Value)); } if (Args.hasArg(options::OPT_mstack_probe_size)) { @@ -7349,8 +7385,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Unwind v2 (epilog) information for x64 Windows. - Args.addOptInFlag(CmdArgs, options::OPT_fwinx64_eh_unwindv2, - options::OPT_fno_winx64_eh_unwindv2); + Args.AddLastArg(CmdArgs, options::OPT_winx64_eh_unwindv2); // C++ "sane" operator new. Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, @@ -7555,7 +7590,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) CmdArgs.push_back("-fretain-comments-from-system-headers"); - Args.AddLastArg(CmdArgs, options::OPT_fextend_variable_liveness_EQ); + if (Arg *A = Args.getLastArg(options::OPT_fextend_variable_liveness_EQ)) { + A->render(Args, CmdArgs); + } else if (Arg *A = Args.getLastArg(options::OPT_O_Group); + A && A->containsValue("g")) { + // Set -fextend-variable-liveness=all by default at -Og. + CmdArgs.push_back("-fextend-variable-liveness=all"); + } // Forward -fcomment-block-commands to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); @@ -7717,7 +7758,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fcuda-include-gpubinary"); CmdArgs.push_back(CudaDeviceInput->getFilename()); } else if (!HostOffloadingInputs.empty()) { - if ((IsCuda || IsHIP) && !IsRDCMode) { + if (IsCuda && !IsRDCMode) { assert(HostOffloadingInputs.size() == 1 && "Only one input expected"); CmdArgs.push_back("-fcuda-include-gpubinary"); CmdArgs.push_back(HostOffloadingInputs.front().getFilename()); @@ -8425,8 +8466,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fms-kernel"); // Unwind v2 (epilog) information for x64 Windows. - if (Args.hasArg(options::OPT__SLASH_d2epilogunwind)) - CmdArgs.push_back("-fwinx64-eh-unwindv2"); + if (Args.hasArg(options::OPT__SLASH_d2epilogunwindrequirev2)) + CmdArgs.push_back("-fwinx64-eh-unwindv2=required"); + else if (Args.hasArg(options::OPT__SLASH_d2epilogunwind)) + CmdArgs.push_back("-fwinx64-eh-unwindv2=best-effort"); for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); @@ -8945,7 +8988,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, std::nullopt, Output)); + CmdArgs, ArrayRef(), Output)); } void OffloadBundler::ConstructJobMultipleOutputs( @@ -9032,7 +9075,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, std::nullopt, Outputs)); + CmdArgs, ArrayRef(), Outputs)); } void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA, @@ -9184,6 +9227,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString("--device-linker=" + TC->getTripleString() + "=-plugin-opt=-avail-extern-to-local")); + CmdArgs.push_back(Args.MakeArgString( + "--device-linker=" + TC->getTripleString() + + "=-plugin-opt=-avail-extern-gv-in-addrspace-to-local=3")); if (Kind == Action::OFK_OpenMP) { CmdArgs.push_back( Args.MakeArgString("--device-linker=" + TC->getTripleString() + @@ -9264,8 +9310,20 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, // Add the linker arguments to be forwarded by the wrapper. CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") + LinkCommand->getExecutable())); - for (const char *LinkArg : LinkCommand->getArguments()) - CmdArgs.push_back(LinkArg); + + // We use action type to differentiate two use cases of the linker wrapper. + // TY_Image for normal linker wrapper work. + // TY_Object for HIP fno-gpu-rdc embedding device binary in a relocatable + // object. + assert(JA.getType() == types::TY_Object || JA.getType() == types::TY_Image); + if (JA.getType() == types::TY_Object) { + CmdArgs.append({"-o", Output.getFilename()}); + for (auto Input : Inputs) + CmdArgs.push_back(Input.getFilename()); + CmdArgs.push_back("-r"); + } else + for (const char *LinkArg : LinkCommand->getArguments()) + CmdArgs.push_back(LinkArg); addOffloadCompressArgs(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index a91e4de41c8d..b92c18f1b60f 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -302,7 +302,8 @@ void CudaInstallationDetector::AddCudaIncludeArgs( CC1Args.push_back(DriverArgs.MakeArgString(P)); } - if (DriverArgs.hasArg(options::OPT_nogpuinc)) + if (!DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true)) return; if (!isValid()) { @@ -928,7 +929,8 @@ llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType( void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // Check our CUDA version if we're going to include the CUDA headers. - if (!DriverArgs.hasArg(options::OPT_nogpuinc) && + if (DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true) && !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); assert(!Arch.empty() && "Must have an explicit GPU arch."); @@ -1001,7 +1003,9 @@ void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); - if (!DriverArgs.hasArg(options::OPT_nogpuinc) && CudaInstallation.isValid()) + if (DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true) && + CudaInstallation.isValid()) CC1Args.append( {"-internal-isystem", DriverArgs.MakeArgString(CudaInstallation.getIncludePath())}); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index e987ef78920e..e5075cbcaf66 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1793,16 +1793,23 @@ struct DarwinPlatform { case TargetArg: case MTargetOSArg: case OSVersionArg: - case InferredFromSDK: - case InferredFromArch: assert(Arg && "OS version argument not yet inferred"); return Arg->getAsString(Args); case DeploymentTargetEnv: return (llvm::Twine(EnvVarName) + "=" + OSVersionStr).str(); + case InferredFromSDK: + case InferredFromArch: + llvm_unreachable("Cannot print arguments for inferred OS version"); } llvm_unreachable("Unsupported Darwin Source Kind"); } + // Returns the inferred source of how the OS version was resolved. + std::string getInferredSource() { + assert(!isExplicitlySpecified() && "OS version was not inferred"); + return InferredSource.str(); + } + void setEnvironment(llvm::Triple::EnvironmentType EnvType, const VersionTuple &OSVersion, const std::optional &SDKInfo) { @@ -1876,7 +1883,8 @@ struct DarwinPlatform { Result.EnvVarName = EnvVarName; return Result; } - static DarwinPlatform createFromSDK(DarwinPlatformKind Platform, + static DarwinPlatform createFromSDK(StringRef SDKRoot, + DarwinPlatformKind Platform, StringRef Value, bool IsSimulator = false) { DarwinPlatform Result(InferredFromSDK, Platform, @@ -1884,11 +1892,15 @@ struct DarwinPlatform { if (IsSimulator) Result.Environment = DarwinEnvironmentKind::Simulator; Result.InferSimulatorFromArch = false; + Result.InferredSource = SDKRoot; return Result; } - static DarwinPlatform createFromArch(llvm::Triple::OSType OS, + static DarwinPlatform createFromArch(StringRef Arch, llvm::Triple::OSType OS, VersionTuple Version) { - return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS), Version); + auto Result = + DarwinPlatform(InferredFromArch, getPlatformFromOS(OS), Version); + Result.InferredSource = Arch; + return Result; } /// Constructs an inferred SDKInfo value based on the version inferred from @@ -1975,6 +1987,9 @@ private: bool InferSimulatorFromArch = true; std::pair Arguments; StringRef EnvVarName; + // If the DarwinPlatform information is derived from an inferred source, this + // captures what that source input was for error reporting. + StringRef InferredSource; // When compiling for a zippered target, this value represents the target // triple encoded in the target variant. std::optional TargetVariantTriple; @@ -2143,26 +2158,27 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, [&](StringRef SDK) -> std::optional { if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator")) return DarwinPlatform::createFromSDK( - Darwin::IPhoneOS, Version, + isysroot, Darwin::IPhoneOS, Version, /*IsSimulator=*/SDK.starts_with("iPhoneSimulator")); else if (SDK.starts_with("MacOSX")) - return DarwinPlatform::createFromSDK(Darwin::MacOS, + return DarwinPlatform::createFromSDK(isysroot, Darwin::MacOS, getSystemOrSDKMacOSVersion(Version)); else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator")) return DarwinPlatform::createFromSDK( - Darwin::WatchOS, Version, + isysroot, Darwin::WatchOS, Version, /*IsSimulator=*/SDK.starts_with("WatchSimulator")); else if (SDK.starts_with("AppleTVOS") || SDK.starts_with("AppleTVSimulator")) return DarwinPlatform::createFromSDK( - Darwin::TvOS, Version, + isysroot, Darwin::TvOS, Version, /*IsSimulator=*/SDK.starts_with("AppleTVSimulator")); else if (SDK.starts_with("XR")) return DarwinPlatform::createFromSDK( - Darwin::XROS, Version, + isysroot, Darwin::XROS, Version, /*IsSimulator=*/SDK.contains("Simulator")); else if (SDK.starts_with("DriverKit")) - return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version); + return DarwinPlatform::createFromSDK(isysroot, Darwin::DriverKit, + Version); return std::nullopt; }; if (auto Result = CreatePlatformFromSDKName(SDK)) @@ -2236,7 +2252,7 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, if (OSTy == llvm::Triple::UnknownOS) return std::nullopt; return DarwinPlatform::createFromArch( - OSTy, getInferredOSVersion(OSTy, Triple, TheDriver)); + MachOArchName, OSTy, getInferredOSVersion(OSTy, Triple, TheDriver)); } /// Returns the deployment target that's specified using the -target option. @@ -2455,9 +2471,15 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } assert(PlatformAndVersion && "Unable to infer Darwin variant"); - if (!PlatformAndVersion->isValidOSVersion()) - getDriver().Diag(diag::err_drv_invalid_version_number) - << PlatformAndVersion->getAsString(Args, Opts); + if (!PlatformAndVersion->isValidOSVersion()) { + if (PlatformAndVersion->isExplicitlySpecified()) + getDriver().Diag(diag::err_drv_invalid_version_number) + << PlatformAndVersion->getAsString(Args, Opts); + else + getDriver().Diag(diag::err_drv_invalid_version_number_inferred) + << PlatformAndVersion->getOSVersion().getAsString() + << PlatformAndVersion->getInferredSource(); + } // After the deployment OS version has been resolved, set it to the canonical // version before further error detection and converting to a proper target // triple. diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index a20879dad94d..47d0e345086b 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -887,6 +887,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption Args.AddLastArg(CmdArgs, options::OPT_w); + // recognise options: fprofile-generate -fprofile-use= + Args.addAllArgs( + CmdArgs, {options::OPT_fprofile_generate, options::OPT_fprofile_use_EQ}); + // Forward flags for OpenMP. We don't do this if the current action is an // device offloading action other than OpenMP. if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index 1c165bbfe84f..146dc8bbd531 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -91,7 +91,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--execute-only"); std::string CPU = getCPUName(D, Args, Triple); - if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + if (Args.hasFlag(options::OPT_mfix_cortex_a53_843419, + options::OPT_mno_fix_cortex_a53_843419, true) && + (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")) CmdArgs.push_back("--fix-cortex-a53-843419"); } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 9c68c5c6de2b..afce4fffe1d5 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -226,6 +226,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf_iamcu"; return "elf_i386"; case llvm::Triple::aarch64: + if (T.isOSManagarm()) + return "aarch64managarm"; return "aarch64linux"; case llvm::Triple::aarch64_be: return "aarch64linuxb"; @@ -402,7 +404,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Most Android ARM64 targets should enable the linker fix for erratum // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. - if (Arch == llvm::Triple::aarch64 && (isAndroid || isOHOSFamily)) { + if (Arch == llvm::Triple::aarch64 && (isAndroid || isOHOSFamily) && + Args.hasFlag(options::OPT_mfix_cortex_a53_843419, + options::OPT_mno_fix_cortex_a53_843419, true)) { std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") CmdArgs.push_back("--fix-cortex-a53-843419"); diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp index a8f2b09b1b20..b8f3a70ee827 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.cpp +++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -102,6 +102,8 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, if (IsThinLTO) { LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all")); LldArgs.push_back(Args.MakeArgString("-plugin-opt=-avail-extern-to-local")); + LldArgs.push_back(Args.MakeArgString( + "-plugin-opt=-avail-extern-gv-in-addrspace-to-local=3")); } for (const Arg *A : Args.filtered(options::OPT_mllvm)) { @@ -417,3 +419,15 @@ void HIPAMDToolChain::checkTargetID( getDriver().Diag(clang::diag::err_drv_bad_target_id) << *PTID.OptionalTargetID; } + +SPIRVAMDToolChain::SPIRVAMDToolChain(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args) + : ROCMToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().Dir); +} + +Tool *SPIRVAMDToolChain::buildLinker() const { + assert(getTriple().getArch() == llvm::Triple::spirv64); + return new tools::AMDGCN::Linker(*this); +} diff --git a/clang/lib/Driver/ToolChains/HIPAMD.h b/clang/lib/Driver/ToolChains/HIPAMD.h index c31894e22c5c..3630b11cd8b1 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.h +++ b/clang/lib/Driver/ToolChains/HIPAMD.h @@ -97,6 +97,15 @@ protected: Tool *buildLinker() const override; }; +class LLVM_LIBRARY_VISIBILITY SPIRVAMDToolChain final : public ROCMToolChain { +public: + SPIRVAMDToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildLinker() const override; +}; + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp index ec29c62976e1..c86790f66a79 100644 --- a/clang/lib/Driver/ToolChains/HIPSPV.cpp +++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -187,7 +187,8 @@ void HIPSPVToolChain::AddIAMCUIncludeArgs(const ArgList &Args, void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nogpuinc)) + if (!DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc, + true)) return; StringRef hipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 151b2bfced81..8ac8d4eb9181 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -743,9 +743,11 @@ void Linux::AddHIPRuntimeLibArgs(const ArgList &Args, Args.MakeArgString(StringRef("-L") + RocmInstallation->getLibPath())); if (Args.hasFlag(options::OPT_frtlib_add_rpath, - options::OPT_fno_rtlib_add_rpath, false)) - CmdArgs.append( - {"-rpath", Args.MakeArgString(RocmInstallation->getLibPath())}); + options::OPT_fno_rtlib_add_rpath, false)) { + SmallString<0> p = RocmInstallation->getLibPath(); + llvm::sys::path::remove_dots(p, true); + CmdArgs.append({"-rpath", Args.MakeArgString(p)}); + } CmdArgs.push_back("-lamdhip64"); } diff --git a/clang/lib/Driver/ToolChains/Managarm.cpp b/clang/lib/Driver/ToolChains/Managarm.cpp new file mode 100644 index 000000000000..ff455f2c6ec7 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Managarm.cpp @@ -0,0 +1,218 @@ +//===----------------------------------------------------------------------===// +// +// 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 "Managarm.h" +#include "Arch/ARM.h" +#include "Arch/RISCV.h" +#include "clang/Config/config.h" +#include "clang/Driver/CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +std::string Managarm::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { + switch (TargetTriple.getArch()) { + default: + return TargetTriple.str(); + case llvm::Triple::x86_64: + return "x86_64-managarm-" + TargetTriple.getEnvironmentName().str(); + case llvm::Triple::aarch64: + return "aarch64-managarm-" + TargetTriple.getEnvironmentName().str(); + case llvm::Triple::riscv64: + return "riscv64-managarm-" + TargetTriple.getEnvironmentName().str(); + } +} + +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { + // It happens that only x86, PPC and SPARC use the 'lib32' variant of + // oslibdir, and using that variant while targeting other architectures causes + // problems because the libraries are laid out in shared system roots that + // can't cope with a 'lib32' library search path being considered. So we only + // enable them when we know we may need it. + // + // FIXME: This is a bit of a hack. We should really unify this code for + // reasoning about oslibdir spellings with the lib dir spellings in the + // GCCInstallationDetector, but that is a more significant refactoring. + if (Triple.getArch() == llvm::Triple::x86 || Triple.isPPC32() || + Triple.getArch() == llvm::Triple::sparc) + return "lib32"; + + if (Triple.getArch() == llvm::Triple::x86_64 && Triple.isX32()) + return "libx32"; + + if (Triple.getArch() == llvm::Triple::riscv32) + return "lib32"; + + return Triple.isArch32Bit() ? "lib" : "lib64"; +} + +Managarm::Managarm(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); + std::string SysRoot = computeSysRoot(); + + ToolChain::path_list &PPaths = getProgramPaths(); + + Generic_GCC::PushPPaths(PPaths); + +#ifdef ENABLE_LINKER_BUILD_ID + ExtraOpts.push_back("--build-id"); +#endif + + // The selection of paths to try here is designed to match the patterns which + // the GCC driver itself uses, as this is part of the GCC-compatible driver. + // This was determined by running GCC in a fake filesystem, creating all + // possible permutations of these directories, and seeing which ones it added + // to the link paths. + path_list &Paths = getFilePaths(); + + const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + + Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); + + addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths); + addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths); + addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths); + addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths); + + Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths); + + addPathIfExists(D, concat(SysRoot, "/lib"), Paths); + addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths); +} + +bool Managarm::HasNativeLLVMSupport() const { return true; } + +Tool *Managarm::buildLinker() const { + return new tools::gnutools::Linker(*this); +} + +Tool *Managarm::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +std::string Managarm::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + return std::string(); +} + +std::string Managarm::getDynamicLinker(const ArgList &Args) const { + switch (getTriple().getArch()) { + case llvm::Triple::aarch64: + return "/lib/aarch64-managarm/ld.so"; + case llvm::Triple::riscv64: { + StringRef ABIName = tools::riscv::getRISCVABI(Args, getTriple()); + return ("/lib/riscv64-managarm/ld-riscv64-" + ABIName + ".so").str(); + } + case llvm::Triple::x86_64: + return "/lib/x86_64-managarm/ld.so"; + default: + llvm_unreachable("unsupported architecture"); + } +} + +void Managarm::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + + // Add 'include' in the resource directory, which is similar to + // GCC_INCLUDE_DIR (private headers) in GCC. + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> ResourceDirInclude(D.ResourceDir); + llvm::sys::path::append(ResourceDirInclude, "include"); + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // TOOL_INCLUDE_DIR + AddMultilibIncludeArgs(DriverArgs, CC1Args); + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + // On systems using multiarch, add /usr/include/$triple before + // /usr/include. + std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot); + if (!MultiarchIncludeDir.empty()) + addExternCSystemInclude( + DriverArgs, CC1Args, + concat(SysRoot, "/usr/include", MultiarchIncludeDir)); + + // Add an include of '/include' directly. This isn't provided by default by + // system GCCs, but is often used with cross-compiling GCCs, and harmless to + // add even when Clang is acting as-if it were a system compiler. + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include")); + + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include")); +} + +void Managarm::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // We need a detected GCC installation on Managarm to provide libstdc++'s + // headers. + if (!GCCInstallation.isValid()) + return; + + StringRef TripleStr = GCCInstallation.getTriple().str(); + + // Try generic GCC detection. + Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, TripleStr); +} + +SanitizerMask Managarm::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::Vptr; + if (IsX86_64) + Res |= SanitizerKind::KernelMemory; + return Res; +} + +void Managarm::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { + for (const auto &Opt : ExtraOpts) + CmdArgs.push_back(Opt.c_str()); +} diff --git a/clang/lib/Driver/ToolChains/Managarm.h b/clang/lib/Driver/ToolChains/Managarm.h new file mode 100644 index 000000000000..2082e2c615f2 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Managarm.h @@ -0,0 +1,55 @@ +//===--- Managarm.h - Managarm ToolChain Implementations --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Managarm : public Generic_ELF { +public: + Managarm(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool HasNativeLLVMSupport() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + SanitizerMask getSupportedSanitizers() const override; + std::string computeSysRoot() const override; + + std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; + + void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override; + + std::vector ExtraOpts; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H diff --git a/clang/lib/Edit/EditedSource.cpp b/clang/lib/Edit/EditedSource.cpp index a3386b2489b0..398cce71d5e2 100644 --- a/clang/lib/Edit/EditedSource.cpp +++ b/clang/lib/Edit/EditedSource.cpp @@ -16,10 +16,8 @@ #include "clang/Edit/FileOffset.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include #include #include #include diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 764c345a9db9..1087eb300185 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -43,7 +43,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index e881d56258e5..d3df9eb604f2 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -19,14 +19,12 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" #include #include -#include using namespace clang; using namespace clang::extractapi; @@ -343,6 +341,22 @@ Object serializeNames(const APIRecord *Record) { serializeArray(Names, "subHeading", serializeDeclarationFragments(Record->SubHeading)); DeclarationFragments NavigatorFragments; + // The +/- prefix for Objective-C methods is important information, and + // should be included in the navigator fragment. The entire subheading is + // not included as it can contain too much information for other records. + switch (Record->getKind()) { + case APIRecord::RK_ObjCClassMethod: + NavigatorFragments.append("+ ", DeclarationFragments::FragmentKind::Text, + /*PreciseIdentifier*/ ""); + break; + case APIRecord::RK_ObjCInstanceMethod: + NavigatorFragments.append("- ", DeclarationFragments::FragmentKind::Text, + /*PreciseIdentifier*/ ""); + break; + default: + break; + } + NavigatorFragments.append(Record->Name, DeclarationFragments::FragmentKind::Identifier, /*PreciseIdentifier*/ ""); diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 424b6dbc0da7..b4745477b96e 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -329,9 +329,9 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // statement and we are aligning lambda blocks to their signatures. if (Previous.is(tok::l_brace) && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].NestedBlockInlined && - State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks && - Style.LambdaBodyIndentation == FormatStyle::LBI_Signature) { - return false; + State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks) { + return Style.isCpp() && + Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope; } // Don't break after very short return types (e.g. "void") as that is often @@ -706,42 +706,48 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, const FormatToken &Previous = *State.NextToken->Previous; auto &CurrentState = State.Stack.back(); - bool DisallowLineBreaksOnThisLine = - Style.LambdaBodyIndentation == FormatStyle::LBI_Signature && - // Deal with lambda arguments in C++. The aim here is to ensure that we - // don't over-indent lambda function bodies when lambdas are passed as - // arguments to function calls. We do this by ensuring that either all - // arguments (including any lambdas) go on the same line as the function - // call, or we break before the first argument. - Style.isCpp() && [&] { - // For example, `/*Newline=*/false`. - if (Previous.is(TT_BlockComment) && Current.SpacesRequiredBefore == 0) - return false; - const auto *PrevNonComment = Current.getPreviousNonComment(); - if (!PrevNonComment || PrevNonComment->isNot(tok::l_paren)) - return false; - if (Current.isOneOf(tok::comment, tok::l_paren, TT_LambdaLSquare)) - return false; - auto BlockParameterCount = PrevNonComment->BlockParameterCount; - if (BlockParameterCount == 0) - return false; + // Deal with lambda arguments in C++. The aim here is to ensure that we don't + // over-indent lambda function bodies when lambdas are passed as arguments to + // function calls. We do this by ensuring that either all arguments (including + // any lambdas) go on the same line as the function call, or we break before + // the first argument. + auto DisallowLineBreaks = [&] { + if (!Style.isCpp() || + Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope) { + return false; + } - // Multiple lambdas in the same function call. - if (BlockParameterCount > 1) - return true; + // For example, `/*Newline=*/false`. + if (Previous.is(TT_BlockComment) && Current.SpacesRequiredBefore == 0) + return false; - // A lambda followed by another arg. - if (!PrevNonComment->Role) - return false; - auto Comma = PrevNonComment->Role->lastComma(); - if (!Comma) - return false; - auto Next = Comma->getNextNonComment(); - return Next && - !Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret); - }(); + if (Current.isOneOf(tok::comment, tok::l_paren, TT_LambdaLSquare)) + return false; - if (DisallowLineBreaksOnThisLine) + const auto *Prev = Current.getPreviousNonComment(); + if (!Prev || Prev->isNot(tok::l_paren)) + return false; + + if (Prev->BlockParameterCount == 0) + return false; + + // Multiple lambdas in the same function call. + if (Prev->BlockParameterCount > 1) + return true; + + // A lambda followed by another arg. + if (!Prev->Role) + return false; + + const auto *Comma = Prev->Role->lastComma(); + if (!Comma) + return false; + + const auto *Next = Comma->getNextNonComment(); + return Next && !Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret); + }; + + if (DisallowLineBreaks()) State.NoLineBreak = true; if (Current.is(tok::equal) && diff --git a/clang/lib/Format/MacroCallReconstructor.cpp b/clang/lib/Format/MacroCallReconstructor.cpp index 116bbad320e1..895d9f93dfce 100644 --- a/clang/lib/Format/MacroCallReconstructor.cpp +++ b/clang/lib/Format/MacroCallReconstructor.cpp @@ -528,10 +528,10 @@ MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line, // 1. One level below the current line's level. // 2. At the correct level relative to each other. unsigned MinChildLevel = - std::min_element(N->Children.begin(), N->Children.end(), - [](const auto &E1, const auto &E2) { - return E1->Level < E2->Level; - }) + llvm::min_element(N->Children, + [](const auto &E1, const auto &E2) { + return E1->Level < E2->Level; + }) ->get() ->Level; for (const auto &Child : N->Children) { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index aed1672afac6..d2f8b2703a9a 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3978,7 +3978,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { for (auto *Tok = FirstNonComment && FirstNonComment->isNot(tok::kw_using) ? FirstNonComment->Next : nullptr; - Tok; Tok = Tok->Next) { + Tok && Tok->isNot(BK_BracedInit); Tok = Tok->Next) { if (Tok->is(TT_StartOfName)) SeenName = true; if (Tok->Previous->EndsCppAttributeGroup) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 587b0d1af9c8..09a66b652518 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1191,7 +1191,7 @@ std::unique_ptr CompilerInstance::cloneForModuleCompileImpl( FrontendOpts.OriginalModuleMap = std::string(OriginalModuleMapFile); // Force implicitly-built modules to hash the content of the module file. HSOpts.ModulesHashContent = true; - FrontendOpts.Inputs = {Input}; + FrontendOpts.Inputs = {std::move(Input)}; // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index aa344579743d..c50d0b6da965 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1502,11 +1502,11 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, // which is available (might be one or both). if (PGOReader->isIRLevelProfile() || PGOReader->hasMemoryProfile()) { if (PGOReader->hasCSIRLevelProfile()) - Opts.setProfileUse(CodeGenOptions::ProfileCSIRInstr); + Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileCSIRInstr); else - Opts.setProfileUse(CodeGenOptions::ProfileIRInstr); + Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileIRInstr); } else - Opts.setProfileUse(CodeGenOptions::ProfileClangInstr); + Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileClangInstr); } void CompilerInvocation::setDefaultPointerAuthOptions( @@ -4485,6 +4485,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.setClangABICompat(LangOptions::ClangABI::Ver18); else if (Major <= 19) Opts.setClangABICompat(LangOptions::ClangABI::Ver19); + else if (Major <= 20) + Opts.setClangABICompat(LangOptions::ClangABI::Ver20); } else if (Ver != "latest") { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); diff --git a/clang/lib/Headers/bmiintrin.h b/clang/lib/Headers/bmiintrin.h index 59c5ece3977f..8024da55379c 100644 --- a/clang/lib/Headers/bmiintrin.h +++ b/clang/lib/Headers/bmiintrin.h @@ -161,8 +161,6 @@ _mm_tzcnt_64(unsigned long long __X) { #undef __RELAXED_FN_ATTRS -#if !defined(__SCE__) || __has_feature(modules) || defined(__BMI__) - /* Define the default attributes for the functions in this file. */ #if defined(__cplusplus) && (__cplusplus >= 201103L) #define __DEFAULT_FN_ATTRS \ @@ -603,6 +601,4 @@ __blsr_u64(unsigned long long __X) { #undef __DEFAULT_FN_ATTRS -#endif /* !defined(__SCE__) || __has_feature(modules) || defined(__BMI__) */ - #endif /* __BMIINTRIN_H */ diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index 19c5987257a2..35f012cc7004 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -16,231 +16,112 @@ #include -#if !defined(__SCE__) || __has_feature(modules) || defined(__MMX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SSE__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SSE2__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SSE3__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SSSE3__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__SSE4_2__) || defined(__SSE4_1__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AES__) || defined(__PCLMUL__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CLFLUSHOPT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CLWB__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX2__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__F16C__) #include -#endif -/* No feature check desired due to internal checks */ #include -#if !defined(__SCE__) || __has_feature(modules) || defined(__BMI2__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__LZCNT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__POPCNT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__FMA__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512F__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512VL__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512BW__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512BITALG__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512CD__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512VPOPCNTDQ__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512VPOPCNTDQ__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512VNNI__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512VNNI__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVXVNNI__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512DQ__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512BITALG__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512BW__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512CD__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512DQ__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512IFMA__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512IFMA__) && defined(__AVX512VL__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVXIFMA__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512VBMI__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VBMI__) && defined(__AVX512VL__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512VBMI2__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VBMI2__) && defined(__AVX512VL__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512FP16__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512FP16__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512BF16__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512BF16__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__PKU__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__VPCLMULQDQ__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__VAES__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__GFNI__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVXVNNIINT8__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVXNECONVERT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SHA512__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SM3__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SM4__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVXVNNIINT16__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__RDPID__) /// Reads the value of the IA32_TSC_AUX MSR (0xc0000103). /// /// \headerfile @@ -252,9 +133,7 @@ static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __ _rdpid_u32(void) { return __builtin_ia32_rdpid(); } -#endif // __RDPID__ -#if !defined(__SCE__) || __has_feature(modules) || defined(__RDRND__) /// Returns a 16-bit hardware-generated random value. /// /// \headerfile @@ -314,9 +193,7 @@ _rdrand64_step(unsigned long long *__p) } #endif } -#endif /* __RDRND__ */ -#if !defined(__SCE__) || __has_feature(modules) || defined(__FSGSBASE__) #ifdef __x86_64__ /// Reads the FS base register. /// @@ -427,9 +304,6 @@ _writegsbase_u64(unsigned long long __V) } #endif -#endif /* __FSGSBASE__ */ - -#if !defined(__SCE__) || __has_feature(modules) || defined(__MOVBE__) /* The structs used below are to force the load/store to be unaligned. This * is accomplished with the __packed__ attribute. The __may_alias__ prevents @@ -543,172 +417,86 @@ _storebe_i64(void * __P, long long __D) { ((struct __storeu_i64*)__P)->__v = __builtin_bswap64((unsigned long long)__D); } #endif -#endif /* __MOVBE */ -#if !defined(__SCE__) || __has_feature(modules) || defined(__RTM__) #include #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SHA__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__FXSR__) #include -#endif /* No feature check desired due to internal MSC_VER checks */ #include -#if !defined(__SCE__) || __has_feature(modules) || defined(__XSAVEOPT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__XSAVEC__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__XSAVES__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SHSTK__) #include -#endif /* Intrinsics inside adcintrin.h are available at all times. */ #include -#if !defined(__SCE__) || __has_feature(modules) || defined(__ADX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__RDSEED__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__WBNOINVD__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CLDEMOTE__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__WAITPKG__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__MOVDIRI__) || \ - defined(__MOVDIR64B__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__MOVRS__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX10_2__) && defined(__MOVRS__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX10_2_512__) && defined(__MOVRS__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__PCONFIG__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SGX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__PTWRITE__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__INVPCID__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__KL__) || \ - defined(__WIDEKL__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_TILE__) || \ - defined(__AMX_INT8__) || defined(__AMX_BF16__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_FP16__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_COMPLEX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_FP8__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_TRANSPOSE__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_MOVRS__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AMX_MOVRS__) && defined(__AMX_TRANSPOSE__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_AVX512__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_TF32__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AMX_TF32__) && defined(__AMX_TRANSPOSE__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AMX_BF16__) && defined(__AMX_TRANSPOSE__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AMX_FP16__) && defined(__AMX_TRANSPOSE__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AMX_COMPLEX__) && defined(__AMX_TRANSPOSE__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - defined(__AVX512VP2INTERSECT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX512VL__) && defined(__AVX512VP2INTERSECT__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX10_2__) #include #include #include @@ -716,33 +504,21 @@ _storebe_i64(void * __P, long long __D) { #include #include #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX10_2_512__) #include #include #include #include #include #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || \ - (defined(__AVX10_2_512__) && defined(__SM4__)) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__ENQCMD__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SERIALIZE__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__TSXLDTRK__) #include -#endif #if defined(_MSC_VER) && __has_extension(gnu_asm) /* Define the default attributes for these intrinsics */ diff --git a/clang/lib/Headers/keylockerintrin.h b/clang/lib/Headers/keylockerintrin.h index f76e91b4d4b3..4e9e6bec20c0 100644 --- a/clang/lib/Headers/keylockerintrin.h +++ b/clang/lib/Headers/keylockerintrin.h @@ -28,8 +28,6 @@ #ifndef _KEYLOCKERINTRIN_H #define _KEYLOCKERINTRIN_H -#if !defined(__SCE__) || __has_feature(modules) || defined(__KL__) - /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS \ __attribute__((__always_inline__, __nodebug__, __target__("kl"),\ @@ -326,10 +324,6 @@ _mm_aesdec256kl_u8(__m128i* __odata, __m128i __idata, const void *__h) { #undef __DEFAULT_FN_ATTRS -#endif /* !defined(__SCE__ || __has_feature(modules) || defined(__KL__) */ - -#if !defined(__SCE__) || __has_feature(modules) || defined(__WIDEKL__) - /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS \ __attribute__((__always_inline__, __nodebug__, __target__("kl,widekl"),\ @@ -521,7 +515,4 @@ _mm_aesdecwide256kl_u8(__m128i __odata[8], const __m128i __idata[8], const void* #undef __DEFAULT_FN_ATTRS -#endif /* !defined(__SCE__) || __has_feature(modules) || defined(__WIDEKL__) \ - */ - #endif /* _KEYLOCKERINTRIN_H */ diff --git a/clang/lib/Headers/x86gprintrin.h b/clang/lib/Headers/x86gprintrin.h index 3d5cc606d7e6..8d513ceffb6d 100644 --- a/clang/lib/Headers/x86gprintrin.h +++ b/clang/lib/Headers/x86gprintrin.h @@ -10,33 +10,19 @@ #ifndef __X86GPRINTRIN_H #define __X86GPRINTRIN_H -#if !defined(__SCE__) || __has_feature(modules) || defined(__HRESET__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__UINTR__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__USERMSR__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CRC32__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__PRFCHI__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__RAOINT__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CMPCCXADD__) #include -#endif #if defined(__i386__) #define __SAVE_GPRBX "mov {%%ebx, %%eax |eax, ebx};" diff --git a/clang/lib/Headers/x86intrin.h b/clang/lib/Headers/x86intrin.h index f42e9e580f88..aaa84365ce3e 100644 --- a/clang/lib/Headers/x86intrin.h +++ b/clang/lib/Headers/x86intrin.h @@ -14,40 +14,22 @@ #include -#if !defined(__SCE__) || __has_feature(modules) || defined(__PRFCHW__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__SSE4A__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__FMA4__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__XOP__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__TBM__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__LWP__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__MWAITX__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__CLZERO__) #include -#endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__RDPRU__) #include -#endif #endif /* __X86INTRIN_H */ diff --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp index 2ed20df22bda..98ce6f73ec84 100644 --- a/clang/lib/Index/IndexBody.cpp +++ b/clang/lib/Index/IndexBody.cpp @@ -435,6 +435,13 @@ public: ParentDC, SymbolRoleSet(), /*Relations=*/{}, E); } + } else { + if (D.isArrayDesignator()) + TraverseStmt(E->getArrayIndex(D)); + else if (D.isArrayRangeDesignator()) { + TraverseStmt(E->getArrayRangeStart(D)); + TraverseStmt(E->getArrayRangeEnd(D)); + } } } return true; diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp index fd9db8113a41..37b428216c91 100644 --- a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp +++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp @@ -8,7 +8,6 @@ #include "DiagnosticBuilderWrappers.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TextAPI/Platform.h" diff --git a/clang/lib/InstallAPI/DirectoryScanner.cpp b/clang/lib/InstallAPI/DirectoryScanner.cpp index be43a96f3d97..f8f708fda4ca 100644 --- a/clang/lib/InstallAPI/DirectoryScanner.cpp +++ b/clang/lib/InstallAPI/DirectoryScanner.cpp @@ -9,7 +9,6 @@ #include "clang/InstallAPI/DirectoryScanner.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/TextAPI/DylibReader.h" using namespace llvm; using namespace llvm::MachO; diff --git a/clang/lib/InstallAPI/FileList.cpp b/clang/lib/InstallAPI/FileList.cpp index 65610903840a..8f8ed6e8a5db 100644 --- a/clang/lib/InstallAPI/FileList.cpp +++ b/clang/lib/InstallAPI/FileList.cpp @@ -6,8 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/InstallAPI/FileList.h" -#include "clang/Basic/DiagnosticFrontend.h" #include "clang/InstallAPI/FileList.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Error.h" diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp index 9e8c60fbda3d..cce0b19b5061 100644 --- a/clang/lib/InstallAPI/Frontend.cpp +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -9,7 +9,6 @@ #include "clang/InstallAPI/Frontend.h" #include "clang/AST/Availability.h" #include "clang/InstallAPI/FrontendRecords.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" using namespace llvm; diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index a73ea0b0d124..487be2c30088 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -13,7 +13,6 @@ #include "clang/Basic/Linkage.h" #include "clang/InstallAPI/DylibVerifier.h" #include "clang/InstallAPI/FrontendRecords.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Mangler.h" diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 05625ddedb72..9a25a264b2d5 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -151,7 +151,7 @@ llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() { llvm::StringRef(FatbinContent.data(), FatbinContent.size()), "", false)); - CodeGenOpts.CudaGpuBinaryFileName = FatbinFileName; + CodeGenOpts.CudaGpuBinaryFileName = std::move(FatbinFileName); FatbinContent.clear(); diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp index 3e3fbfd172ca..3e7e32b2e855 100644 --- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp +++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp @@ -18,7 +18,6 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" @@ -26,7 +25,6 @@ #include "llvm/Support/raw_ostream.h" #include -#include #include diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp index eb2ce9c9fd33..afdf406b3725 100644 --- a/clang/lib/Interpreter/Value.cpp +++ b/clang/lib/Interpreter/Value.cpp @@ -16,10 +16,7 @@ #include "clang/AST/Type.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_os_ostream.h" #include -#include #include namespace { diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index 4606b85d42fe..1b6b16c56114 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -323,10 +323,6 @@ static unsigned skipNewline(const char *&First, const char *End) { return Len; } -static bool wasLineContinuation(const char *First, unsigned EOLLen) { - return *(First - (int)EOLLen - 1) == '\\'; -} - static void skipToNewlineRaw(const char *&First, const char *const End) { for (;;) { if (First == End) @@ -336,13 +332,16 @@ static void skipToNewlineRaw(const char *&First, const char *const End) { if (Len) return; + char LastNonWhitespace = ' '; do { + if (!isHorizontalWhitespace(*First)) + LastNonWhitespace = *First; if (++First == End) return; Len = isEOL(First, End); } while (!Len); - if (First[-1] != '\\') + if (LastNonWhitespace != '\\') return; First += Len; @@ -394,6 +393,7 @@ static bool isQuoteCppDigitSeparator(const char *const Start, } void Scanner::skipLine(const char *&First, const char *const End) { + char LastNonWhitespace = ' '; for (;;) { assert(First <= End); if (First == End) @@ -419,6 +419,8 @@ void Scanner::skipLine(const char *&First, const char *const End) { // Iterate over comments correctly. if (*First != '/' || End - First < 2) { LastTokenPtr = First; + if (!isWhitespace(*First)) + LastNonWhitespace = *First; ++First; continue; } @@ -431,6 +433,8 @@ void Scanner::skipLine(const char *&First, const char *const End) { if (First[1] != '*') { LastTokenPtr = First; + if (!isWhitespace(*First)) + LastNonWhitespace = *First; ++First; continue; } @@ -442,8 +446,9 @@ void Scanner::skipLine(const char *&First, const char *const End) { return; // Skip over the newline. - unsigned Len = skipNewline(First, End); - if (!wasLineContinuation(First, Len)) // Continue past line-continuations. + skipNewline(First, End); + + if (LastNonWhitespace != '\\') break; } } @@ -468,9 +473,16 @@ static void skipWhitespace(const char *&First, const char *const End) { if (End - First < 2) return; - if (First[0] == '\\' && isVerticalWhitespace(First[1])) { - skipNewline(++First, End); - continue; + if (*First == '\\') { + const char *Ptr = First + 1; + while (Ptr < End && isHorizontalWhitespace(*Ptr)) + ++Ptr; + if (Ptr != End && isVerticalWhitespace(*Ptr)) { + skipNewline(Ptr, End); + First = Ptr; + continue; + } + return; } // Check for a non-comment character. diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp index 588b32ee9ca8..a7b670f00ac6 100644 --- a/clang/lib/Lex/HeaderMap.cpp +++ b/clang/lib/Lex/HeaderMap.cpp @@ -18,7 +18,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SystemZ/zOSSupport.h" #include #include #include diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index 641e3beebc08..3e22b4001bde 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -221,6 +221,7 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths( case llvm::Triple::Hurd: case llvm::Triple::Linux: case llvm::Triple::LiteOS: + case llvm::Triple::Managarm: case llvm::Triple::NaCl: case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index c2c4e68f2584..b37d8a3840ac 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -176,6 +176,8 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, ExtendedTokenMode = 0; NewLinePtr = nullptr; + + IsFirstPPToken = true; } /// Lexer constructor - Create a new lexer object for the specified buffer @@ -3727,6 +3729,11 @@ bool Lexer::Lex(Token &Result) { HasLeadingEmptyMacro = false; } + if (IsFirstPPToken) { + Result.setFlag(Token::FirstPPToken); + IsFirstPPToken = false; + } + bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine; IsAtPhysicalStartOfLine = false; bool isRawLex = isLexingRawMode(); @@ -3734,6 +3741,10 @@ bool Lexer::Lex(Token &Result) { bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine); // (After the LexTokenInternal call, the lexer might be destroyed.) assert((returnedToken || !isRawLex) && "Raw lex must succeed"); + + if (returnedToken && Result.isFirstPPToken() && PP && + !PP->hasSeenMainFileFirstPPToken()) + PP->HandleMainFileFirstPPToken(Result); return returnedToken; } @@ -4579,6 +4590,8 @@ const char *Lexer::convertDependencyDirectiveToken( Result.setFlag((Token::TokenFlags)DDTok.Flags); Result.setLength(DDTok.Length); BufferPtr = TokPtr + DDTok.Length; + if (PP && !PP->hasSeenMainFileFirstPPToken() && Result.isFirstPPToken()) + PP->HandleMainFileFirstPPToken(Result); return TokPtr; } diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 04a30f66fb73..70934b9b1dec 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1242,6 +1242,9 @@ void Preprocessor::HandleDirective(Token &Result) { // pp-directive. bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal(); + if (!hasSeenMainFileFirstPPToken()) + HandleMainFileFirstPPToken(Result); + // Save the '#' token in case we need to return it later. Token SavedHash = Result; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 37ac1bf07e9c..97bdeb873d69 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -469,6 +469,9 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // to disable the optimization in this case. if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro(); + if (!hasSeenMainFileFirstPPToken()) + HandleMainFileFirstPPToken(Identifier); + // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { if (Callbacks) diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 21fc7a2b6fae..18b2f5f02d6c 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -247,6 +247,8 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { llvm::errs() << " [LeadingSpace]"; if (Tok.isExpandDisabled()) llvm::errs() << " [ExpandDisabled]"; + if (Tok.isFirstPPToken()) + llvm::errs() << " [First pp-token]"; if (Tok.needsCleaning()) { const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength()) diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt index d931cf185321..0c94387086a9 100644 --- a/clang/lib/Parse/CMakeLists.txt +++ b/clang/lib/Parse/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + FrontendHLSL FrontendOpenMP MC MCParser diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index e215c64cccd1..9a010fb5f342 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -422,7 +422,6 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { DefArgResult = ParseBraceInitializer(); } else DefArgResult = ParseAssignmentExpression(); - DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult, Param); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, /*DefaultArg=*/nullptr); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 619595da3ec3..ed7220a14588 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -153,7 +153,7 @@ bool Parser::ParseSingleGNUAttribute(ParsedAttributes &Attrs, SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::GNU()); return false; } @@ -398,12 +398,12 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, return; if (T.isUsable()) - Attrs.addNewTypeAttr(&AttrName, - SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, T.get(), Form); + Attrs.addNewTypeAttr( + &AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), + AttributeScopeInfo(ScopeName, ScopeLoc), T.get(), Form); else Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, nullptr, 0, Form); + AttributeScopeInfo(ScopeName, ScopeLoc), nullptr, 0, Form); } ExprResult @@ -438,7 +438,6 @@ bool Parser::ParseAttributeArgumentList( } else { Expr = ParseAssignmentExpression(); } - Expr = Actions.CorrectDelayedTyposInExpr(Expr); if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); @@ -474,15 +473,6 @@ bool Parser::ParseAttributeArgumentList( Arg++; } - if (SawError) { - // Ensure typos get diagnosed when errors were encountered while parsing the - // expression list. - for (auto &E : Exprs) { - ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); - if (Expr.isUsable()) - E = Expr.get(); - } - } return SawError; } @@ -567,9 +557,7 @@ unsigned Parser::ParseAttributeArgsCommon( nullptr, Sema::ExpressionEvaluationContextRecord::EK_AttrArgument); - ExprResult ArgExpr( - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); - + ExprResult ArgExpr = ParseAssignmentExpression(); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return 0; @@ -623,10 +611,12 @@ unsigned Parser::ParseAttributeArgsCommon( if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) { Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen), - ScopeName, ScopeLoc, TheParsedType, Form); + AttributeScopeInfo(ScopeName, ScopeLoc), + TheParsedType, Form); } else { - Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, - ArgExprs.data(), ArgExprs.size(), Form); + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), + AttributeScopeInfo(ScopeName, ScopeLoc), ArgExprs.data(), + ArgExprs.size(), Form); } } @@ -868,7 +858,7 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, // Only add the property attribute if it was well-formed. if (!HasInvalidAccessor) - Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, nullptr, SourceLocation(), + Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, AttributeScopeInfo(), AccessorNames[AK_Get], AccessorNames[AK_Put], ParsedAttr::Form::Declspec()); T.skipToEnd(); @@ -954,7 +944,7 @@ void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { << AttrName->getName(); if (!AttrHandled) - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::Declspec()); } T.consumeClose(); @@ -982,7 +972,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { case tok::kw___uptr: { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); break; } @@ -1003,9 +993,8 @@ void Parser::ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, /*ScopeName=*/nullptr, - /*ScopeLoc=*/SourceLocation{}, /*Args=*/nullptr, /*numArgs=*/0, - tok::kw___funcref); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), /*Args=*/nullptr, + /*numArgs=*/0, tok::kw___funcref); } void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() { @@ -1049,7 +1038,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___pascal); } } @@ -1059,7 +1048,7 @@ void Parser::ParseOpenCLKernelAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___kernel); } } @@ -1068,7 +1057,7 @@ void Parser::ParseCUDAFunctionAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___noinline__)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___noinline__); } } @@ -1076,7 +1065,7 @@ void Parser::ParseCUDAFunctionAttributes(ParsedAttributes &attrs) { void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Tok.getKind()); } @@ -1088,7 +1077,7 @@ void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { @@ -1105,7 +1094,7 @@ void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { if (!getLangOpts().ObjC) Diag(AttrNameLoc, diag::ext_nullability) << AttrName; - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); break; } @@ -1449,10 +1438,11 @@ void Parser::ParseAvailabilityAttribute( // Record this attribute attrs.addNew(&Availability, - SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName, - ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated], - Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form, - StrictLoc, ReplacementExpr.get(), EnvironmentLoc); + SourceRange(AvailabilityLoc, T.getCloseLocation()), + AttributeScopeInfo(ScopeName, ScopeLoc), Platform, + Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], + UnavailableLoc, MessageExpr.get(), Form, StrictLoc, + ReplacementExpr.get(), EnvironmentLoc); } void Parser::ParseExternalSourceSymbolAttribute( @@ -1570,7 +1560,8 @@ void Parser::ParseExternalSourceSymbolAttribute( ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), GeneratedDeclaration, USR.get()}; Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, std::size(Args), Form); + AttributeScopeInfo(ScopeName, ScopeLoc), Args, std::size(Args), + Form); } void Parser::ParseObjCBridgeRelatedAttribute( @@ -1638,8 +1629,8 @@ void Parser::ParseObjCBridgeRelatedAttribute( // Record this attribute Attrs.addNew(&ObjCBridgeRelated, SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()), - ScopeName, ScopeLoc, RelatedClass, ClassMethod, InstanceMethod, - Form); + AttributeScopeInfo(ScopeName, ScopeLoc), RelatedClass, + ClassMethod, InstanceMethod, Form); } void Parser::ParseSwiftNewTypeAttribute( @@ -1680,7 +1671,8 @@ void Parser::ParseSwiftNewTypeAttribute( ArgsUnion Args[] = {SwiftType}; Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, std::size(Args), Form); + AttributeScopeInfo(ScopeName, ScopeLoc), Args, std::size(Args), + Form); } void Parser::ParseTypeTagForDatatypeAttribute( @@ -1733,9 +1725,9 @@ void Parser::ParseTypeTagForDatatypeAttribute( } if (!T.consumeClose()) { - Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, ScopeName, ScopeLoc, - ArgumentKind, MatchingCType.get(), - LayoutCompatible, MustBeNull, Form); + Attrs.addNewTypeTagForDatatype( + &AttrName, AttrNameLoc, AttributeScopeInfo(ScopeName, ScopeLoc), + ArgumentKind, MatchingCType.get(), LayoutCompatible, MustBeNull, Form); } if (EndLoc) @@ -1842,9 +1834,10 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, if (!AL.isStandardAttributeSyntax()) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { - if (WarnOnUnknownAttrs) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + if (WarnOnUnknownAttrs) { + Actions.DiagnoseUnknownAttribute(AL); + AL.setInvalid(); + } } else { Diag(AL.getLoc(), AttrDiagID) << AL; AL.setInvalid(); @@ -3164,12 +3157,12 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, *EndLoc = T.getCloseLocation(); if (IsType) { - Attrs.addNewTypeAttr(KWName, KWLoc, nullptr, KWLoc, TypeResult, Kind, + Attrs.addNewTypeAttr(KWName, KWLoc, AttributeScopeInfo(), TypeResult, Kind, EllipsisLoc); } else { ArgsVector ArgExprs; ArgExprs.push_back(ArgExpr.get()); - Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind, + Attrs.addNew(KWName, KWLoc, AttributeScopeInfo(), ArgExprs.data(), 1, Kind, EllipsisLoc); } } @@ -3188,7 +3181,7 @@ void Parser::ParseAnnotationSpecifier(ParsedAttributes &Attrs, ArgsVector ArgExprs; ArgExprs.push_back(AnnotExpr.get()); - Attrs.addNew(&Placeholder, EqLoc, nullptr, EqLoc, ArgExprs.data(), 1, + Attrs.addNew(&Placeholder, EqLoc, {}, ArgExprs.data(), 1, ParsedAttr::Form::Annotation()); if (EndLoc) @@ -3236,9 +3229,8 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) { return; } - Attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), - /*scope*/ nullptr, SourceLocation(), ArgExprs.data(), - ArgExprs.size(), + Attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), AttributeScopeInfo(), + ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::Keyword(/*IsAlignAs=*/false, /*IsRegularKeywordAttribute=*/false)); } @@ -3268,9 +3260,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr, ExpressionKind::EK_AttrArgument); - ExprResult ArgExpr( - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); - + ExprResult ArgExpr = ParseAssignmentExpression(); if (ArgExpr.isInvalid()) { Parens.skipToEnd(); return; @@ -3286,7 +3276,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, Ctx.getSizeType(), SourceLocation())); Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form); + AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), Form); } ExprResult Parser::ParseExtIntegerArgument() { @@ -4109,7 +4099,7 @@ void Parser::ParseDeclarationSpecifiers( isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - DS.getAttributes().addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, + DS.getAttributes().addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___forceinline); break; } @@ -4167,8 +4157,9 @@ void Parser::ParseDeclarationSpecifiers( // Objective-C 'kindof' types. case tok::kw___kindof: - DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, - nullptr, 0, tok::kw___kindof); + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, + AttributeScopeInfo(), nullptr, 0, + tok::kw___kindof); (void)ConsumeToken(); continue; @@ -6355,8 +6346,9 @@ void Parser::ParseTypeQualifierListOpt( // Objective-C 'kindof' types. case tok::kw___kindof: - DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, - nullptr, 0, tok::kw___kindof); + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, + AttributeScopeInfo(), nullptr, 0, + tok::kw___kindof); (void)ConsumeToken(); continue; @@ -6995,8 +6987,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // void (f()) requires true; Diag(Tok, diag::err_requires_clause_inside_parens); ConsumeToken(); - ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr( - ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + ExprResult TrailingRequiresClause = + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true); if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() && !D.hasTrailingRequiresClause()) // We're already ill-formed if we got here but we'll accept it anyway. @@ -7643,8 +7635,7 @@ void Parser::ParseParameterDeclarationClause( Diag(Tok, diag::err_requires_clause_on_declarator_not_declaring_a_function); ConsumeToken(); - Actions.CorrectDelayedTyposInExpr( - ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true); } // Remember this parsed parameter in ParamInfo. @@ -7758,7 +7749,6 @@ void Parser::ParseParameterDeclarationClause( } DefArgResult = ParseAssignmentExpression(); } - DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, /*DefaultArg=*/nullptr); @@ -7904,8 +7894,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { } else { EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - NumElements = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + NumElements = ParseAssignmentExpression(); } } else { if (StaticLoc.isValid()) { @@ -8042,8 +8031,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = Actions.CorrectDelayedTyposInExpr( - ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange)); + ExprResult Operand = + ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange); if (HasParens) DS.setTypeArgumentRange(CastRange); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5b57a89b9f4e..0b3cf4409072 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" +#include "clang/Sema/SemaHLSL.h" #include "llvm/Support/TimeProfiler.h" #include @@ -848,6 +849,10 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( Decl *AD = ParseAliasDeclarationAfterDeclarator( TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec); + + if (!AD) + return nullptr; + return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec); } @@ -1189,10 +1194,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Decltype); - Result = Actions.CorrectDelayedTyposInExpr( - ParseExpression(), /*InitDecl=*/nullptr, - /*RecoverUncorrectedTypos=*/false, - [](Expr *E) { return E->hasPlaceholderType() ? ExprError() : E; }); + Result = ParseExpression(); if (Result.isInvalid()) { DS.SetTypeSpecError(); if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { @@ -1556,7 +1558,7 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } } @@ -1565,7 +1567,7 @@ void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } } @@ -4604,8 +4606,7 @@ bool Parser::ParseCXXAssumeAttributeArg( Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); TentativeParsingAction TPA(*this); - ExprResult Res( - Actions.CorrectDelayedTyposInExpr(ParseConditionalExpression())); + ExprResult Res = ParseConditionalExpression(); if (Res.isInvalid()) { TPA.Commit(); SkipUntil(tok::r_paren, tok::r_square, StopAtSemi | StopBeforeMatch); @@ -4636,8 +4637,8 @@ bool Parser::ParseCXXAssumeAttributeArg( ArgsUnion Assumption = Res.get(); auto RParen = Tok.getLocation(); T.consumeClose(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), ScopeName, ScopeLoc, - &Assumption, 1, Form); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), + AttributeScopeInfo(ScopeName, ScopeLoc), &Assumption, 1, Form); if (EndLoc) *EndLoc = RParen; @@ -4717,7 +4718,7 @@ bool Parser::ParseCXX11AttributeArgs( // Ignore attributes that don't exist for the target. if (!Attr.existsInTarget(getTargetInfo())) { - Diag(LParenLoc, diag::warn_unknown_attribute_ignored) << AttrName; + Actions.DiagnoseUnknownAttribute(Attr); Attr.setInvalid(true); return true; } @@ -4772,7 +4773,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, /*ScopeName*/ nullptr, /*ScopeLoc*/ Loc, Form); } else - Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Form); + Attrs.addNew(AttrName, Loc, AttributeScopeInfo(), nullptr, 0, Form); return; } @@ -4890,12 +4891,15 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, ScopeName, ScopeLoc, OpenMPTokens); if (!AttrParsed) { - Attrs.addNew( - AttrName, - SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), - ScopeName, ScopeLoc, nullptr, 0, - getLangOpts().CPlusPlus ? ParsedAttr::Form::CXX11() - : ParsedAttr::Form::C23()); + Attrs.addNew(AttrName, + SourceRange(ScopeLoc.isValid() && CommonScopeLoc.isInvalid() + ? ScopeLoc + : AttrLoc, + AttrLoc), + AttributeScopeInfo(ScopeName, ScopeLoc, CommonScopeLoc), + nullptr, 0, + getLangOpts().CPlusPlus ? ParsedAttr::Form::CXX11() + : ParsedAttr::Form::C23()); AttrParsed = true; } @@ -5058,13 +5062,13 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { } if (!T.consumeClose()) { - Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr, - SourceLocation(), ArgExprs.data(), ArgExprs.size(), + Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), + AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::Microsoft()); } } -void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { +void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) { assert(Tok.is(tok::identifier) && "Expected an identifier to denote which MS attribute to consider"); IdentifierInfo *RootSignatureIdent = Tok.getIdentifierInfo(); @@ -5106,18 +5110,14 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { // Construct our identifier StringRef Signature = StrLiteral.value()->getString(); - auto Hash = llvm::hash_value(Signature); - std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash); - IdentifierInfo *DeclIdent = &(Actions.getASTContext().Idents.get(IdStr)); - - LookupResult R(Actions, DeclIdent, SourceLocation(), - Sema::LookupOrdinaryName); - // Check if we have already found a decl of the same name, if we haven't - // then parse the root signature string and construct the in-memory elements - if (!Actions.LookupQualifiedName(R, Actions.CurContext)) { + auto [DeclIdent, Found] = + Actions.HLSL().ActOnStartRootSignatureDecl(Signature); + // If we haven't found an already defined DeclIdent then parse the root + // signature string and construct the in-memory elements + if (!Found) { + // Offset location 1 to account for '"' SourceLocation SignatureLoc = - StrLiteral.value()->getExprLoc().getLocWithOffset( - 1); // offset 1 for '"' + StrLiteral.value()->getExprLoc().getLocWithOffset(1); // Invoke the root signature parser to construct the in-memory constructs hlsl::RootSignatureLexer Lexer(Signature, SignatureLoc); SmallVector RootElements; @@ -5127,12 +5127,9 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { return; } - // Create the Root Signature - auto *SignatureDecl = HLSLRootSignatureDecl::Create( - Actions.getASTContext(), /*DeclContext=*/Actions.CurContext, - RootSignatureLoc, DeclIdent, RootElements); - SignatureDecl->setImplicit(); - Actions.PushOnScopeChains(SignatureDecl, getCurScope()); + // Construct the declaration. + Actions.HLSL().ActOnFinishRootSignatureDecl(RootSignatureLoc, DeclIdent, + RootElements); } // Create the arg for the ParsedAttr @@ -5143,8 +5140,8 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { if (!T.consumeClose()) Attrs.addNew(RootSignatureIdent, - SourceRange(RootSignatureLoc, T.getCloseLocation()), nullptr, - SourceLocation(), Args.data(), Args.size(), + SourceRange(RootSignatureLoc, T.getCloseLocation()), + AttributeScopeInfo(), Args.data(), Args.size(), ParsedAttr::Form::Microsoft()); } @@ -5175,7 +5172,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) { if (Tok.getIdentifierInfo()->getName() == "uuid") ParseMicrosoftUuidAttributeArgs(Attrs); else if (Tok.getIdentifierInfo()->getName() == "RootSignature") - ParseMicrosoftRootSignatureAttributeArgs(Attrs); + ParseHLSLRootSignatureAttributeArgs(Attrs); else { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); @@ -5194,7 +5191,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) { ReplayOpenMPAttributeTokens(OpenMPTokens); } if (!AttrParsed) { - Attrs.addNew(II, NameLoc, nullptr, SourceLocation(), nullptr, 0, + Attrs.addNew(II, NameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::Microsoft()); } } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 593da28e5d37..a732bdbd9d31 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -185,7 +185,6 @@ ExprResult Parser::ParseConstraintExpression() { ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { - Actions.CorrectDelayedTyposInExpr(Res); return ExprError(); } return Res; @@ -246,7 +245,6 @@ Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { // the rest of the addition expression). Try to parse the rest of it here. if (PossibleNonPrimary) E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr); - Actions.CorrectDelayedTyposInExpr(E); return ExprError(); } return E; @@ -258,14 +256,11 @@ Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { SourceLocation LogicalAndLoc = ConsumeToken(); ExprResult RHS = ParsePrimary(); if (RHS.isInvalid()) { - Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc, tok::ampamp, LHS.get(), RHS.get()); if (!Op.isUsable()) { - Actions.CorrectDelayedTyposInExpr(RHS); - Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } LHS = Op; @@ -283,14 +278,11 @@ Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { ExprResult RHS = ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); if (!RHS.isUsable()) { - Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc, tok::pipepipe, LHS.get(), RHS.get()); if (!Op.isUsable()) { - Actions.CorrectDelayedTyposInExpr(RHS); - Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } LHS = Op; @@ -428,7 +420,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } if (TernaryMiddle.isInvalid()) { - Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); TernaryMiddle = nullptr; } @@ -486,11 +477,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { RHS = ParseCastExpression(CastParseKind::AnyCastExpr); if (RHS.isInvalid()) { - // FIXME: Errors generated by the delayed typo correction should be - // printed before errors from parsing the RHS, not after. - Actions.CorrectDelayedTyposInExpr(LHS); - if (TernaryMiddle.isUsable()) - TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } @@ -523,11 +509,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { RHSIsInitList = false; if (RHS.isInvalid()) { - // FIXME: Errors generated by the delayed typo correction should be - // printed before errors from ParseRHSOfBinaryExpression, not after. - Actions.CorrectDelayedTyposInExpr(LHS); - if (TernaryMiddle.isUsable()) - TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } @@ -552,7 +533,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } - ExprResult OrigLHS = LHS; if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { @@ -591,17 +571,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { LHS = CondOp; } - // In this case, ActOnBinOp or ActOnConditionalOp performed the - // CorrectDelayedTyposInExpr check. - if (!getLangOpts().CPlusPlus) - continue; - } - - // Ensure potential typos aren't left undiagnosed. - if (LHS.isInvalid()) { - Actions.CorrectDelayedTyposInExpr(OrigLHS); - Actions.CorrectDelayedTyposInExpr(TernaryMiddle); - Actions.CorrectDelayedTyposInExpr(RHS); } } } @@ -1794,7 +1763,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. if (CheckProhibitedCXX11Attribute()) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } BalancedDelimiterTracker T(*this, tok::l_square); @@ -1820,8 +1788,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } else { Idx = ParseExpression(); // May be a comma expression } - LHS = Actions.CorrectDelayedTyposInExpr(LHS); - Idx = Actions.CorrectDelayedTyposInExpr(Idx); if (Idx.isInvalid()) { HasError = true; } else { @@ -1829,7 +1795,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } else if (Tok.isNot(tok::r_square)) { if (ParseExpressionList(ArgExprs)) { - LHS = Actions.CorrectDelayedTyposInExpr(LHS); HasError = true; } } @@ -1845,7 +1810,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Consume ':' ColonLocFirst = ConsumeToken(); if (Tok.isNot(tok::r_square)) - Length = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + Length = ParseExpression(); } } else if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) { ColonProtectionRAIIObject RAII(*this); @@ -1856,7 +1821,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { (getLangOpts().OpenMP < 50 || ((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50)))) { Length = ParseExpression(); - Length = Actions.CorrectDelayedTyposInExpr(Length); } } if (getLangOpts().OpenMP >= 50 && @@ -1872,8 +1836,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } SourceLocation RLoc = Tok.getLocation(); - LHS = Actions.CorrectDelayedTyposInExpr(LHS); - if (!LHS.isInvalid() && !HasError && !Length.isInvalid() && !Stride.isInvalid() && Tok.is(tok::r_square)) { if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) { @@ -1921,7 +1883,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation OpenLoc = ConsumeToken(); if (ParseSimpleExpressionList(ExecConfigExprs)) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } @@ -1972,16 +1933,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); }))) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); // If we got an error when parsing expression list, we don't call // the CodeCompleteCall handler inside the parser. So call it here // to make sure we get overload suggestions even when we are in the // middle of a parameter. if (PP.isCodeCompletionReached() && !CalledSignatureHelp) RunSignatureHelp(); - } else if (LHS.isInvalid()) { - for (auto &E : ArgExprs) - Actions.CorrectDelayedTyposInExpr(E); } } } @@ -1996,16 +1953,16 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ArgExprs); SkipUntil(tok::r_paren, StopAtSemi); } else if (Tok.isNot(tok::r_paren)) { - bool HadDelayedTypo = false; - if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get()) - HadDelayedTypo = true; + bool HadErrors = false; + if (LHS.get()->containsErrors()) + HadErrors = true; for (auto &E : ArgExprs) - if (Actions.CorrectDelayedTyposInExpr(E).get() != E) - HadDelayedTypo = true; - // If there were delayed typos in the LHS or ArgExprs, call SkipUntil - // instead of PT.consumeClose() to avoid emitting extra diagnostics for - // the unmatched l_paren. - if (HadDelayedTypo) + if (E->containsErrors()) + HadErrors = true; + // If there were errors in the LHS or ArgExprs, call SkipUntil instead + // of PT.consumeClose() to avoid emitting extra diagnostics for the + // unmatched l_paren. + if (HadErrors) SkipUntil(tok::r_paren, StopAtSemi); else PT.consumeClose(); @@ -2156,7 +2113,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*AllowConstructorName=*/ getLangOpts().MicrosoftExt && SS.isNotEmpty(), /*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } @@ -3031,8 +2987,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, do { BalancedDelimiterTracker TS(*this, tok::l_square); TS.consumeOpen(); - ExprResult NumElements = - Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult NumElements = ParseExpression(); if (!NumElements.isUsable()) { ErrorFound = true; while (!SkipUntil(tok::r_square, tok::r_paren, @@ -3046,7 +3001,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Match the ')'. T.consumeClose(); RParenLoc = T.getCloseLocation(); - Result = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + Result = ParseAssignmentExpression(); if (ErrorFound) { Result = ExprError(); } else if (!Result.isInvalid()) { @@ -3058,12 +3013,6 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, InMessageExpressionRAIIObject InMessage(*this, false); Result = ParseExpression(TypeCastState::MaybeTypeCast); - if (!getLangOpts().CPlusPlus && Result.isUsable()) { - // Correct typos in non-C++ code earlier so that implicit-cast-like - // expressions are parsed correctly. - Result = Actions.CorrectDelayedTyposInExpr(Result); - } - if (ExprType >= ParenParseOption::FoldExpr && isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { ExprType = ParenParseOption::FoldExpr; @@ -3167,8 +3116,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { // not evaluated." EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); - ControllingExpr = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + ControllingExpr = ParseAssignmentExpression(); if (ControllingExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); @@ -3214,8 +3162,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { // FIXME: These expressions should be parsed in a potentially potentially // evaluated context. - ExprResult ER( - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); + ExprResult ER = ParseAssignmentExpression(); if (ER.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); @@ -3309,8 +3256,7 @@ void Parser::injectEmbedTokens() { bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, llvm::function_ref ExpressionStarts, - bool FailImmediatelyOnInvalidExpr, - bool EarlyTypoCorrection) { + bool FailImmediatelyOnInvalidExpr) { bool SawError = false; while (true) { if (ExpressionStarts) @@ -3323,9 +3269,6 @@ bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, } else Expr = ParseAssignmentExpression(); - if (EarlyTypoCorrection) - Expr = Actions.CorrectDelayedTyposInExpr(Expr); - if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); else if (Tok.is(tok::code_completion)) { @@ -3354,14 +3297,6 @@ bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, ConsumeToken(); checkPotentialAngleBracketDelimiter(Comma); } - if (SawError) { - // Ensure typos get diagnosed when errors were encountered while parsing the - // expression list. - for (auto &E : Exprs) { - ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); - if (Expr.isUsable()) E = Expr.get(); - } - } return SawError; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 38d7ac4cbe02..c4f509f82a96 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -507,8 +507,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // like we never saw it. Token Identifier = Tok; // Stash away the identifier. ConsumeToken(); // Eat the identifier, current token is now '::'. - Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected) - << tok::identifier; + ConsumeToken(); + Diag(getEndOfPreviousToken(), diag::err_expected) << tok::identifier; UnconsumeToken(Identifier); // Stick the identifier back. Next = NextToken(); // Point Next at the '{' token. } @@ -1058,8 +1058,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, SourceLocation StartLoc = Tok.getLocation(); InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true); Init = ParseInitializer(); - if (!Init.isInvalid()) - Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Tok.getLocation() != StartLoc) { // Back out the lexing of the token after the initializer. @@ -1151,8 +1149,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // enclosing the lambda-expression, rather than in the context of the // lambda-expression itself. ParsedType InitCaptureType; - if (Init.isUsable()) - Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Init.isUsable()) { NonTentativeAction([&] { // Get the pointer and store it in an lvalue, so we can use it as an @@ -1325,8 +1321,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( if (Tok.is(tok::kw___noinline__)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - Attributes.addNew(AttrName, AttrNameLoc, /*ScopeName=*/nullptr, - AttrNameLoc, /*ArgsUnion=*/nullptr, + Attributes.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), + /*ArgsUnion=*/nullptr, /*numArgs=*/0, tok::kw___noinline__); } else if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(Attributes, /*LatePArsedAttrList=*/nullptr, &D); @@ -3292,8 +3288,7 @@ ExprResult Parser::ParseRequiresExpression() { // cv-qualifier-seq[opt] abstract-declarator[opt] BalancedDelimiterTracker ExprBraces(*this, tok::l_brace); ExprBraces.consumeOpen(); - ExprResult Expression = - Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult Expression = ParseExpression(); if (!Expression.isUsable()) { ExprBraces.skipToEnd(); SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); @@ -3396,8 +3391,7 @@ ExprResult Parser::ParseRequiresExpression() { // C++ [expr.prim.req.nested] // nested-requirement: // 'requires' constraint-expression ';' - ExprResult ConstraintExpr = - Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + ExprResult ConstraintExpr = ParseConstraintExpression(); if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) { SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); @@ -3482,8 +3476,7 @@ ExprResult Parser::ParseRequiresExpression() { // simple-requirement: // expression ';' SourceLocation StartLoc = Tok.getLocation(); - ExprResult Expression = - Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult Expression = ParseExpression(); if (!Expression.isUsable()) { SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); break; diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 53d46465e336..e6caa81b309c 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -296,6 +296,6 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, break; } - Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(), - ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation()); + Attrs.addNew(II, Loc, AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), + ParsedAttr::Form::HLSLAnnotation()); } diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index feb052886247..d79cd8111e17 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -477,8 +477,6 @@ ExprResult Parser::ParseBraceInitializer() { if (Tok.is(tok::ellipsis)) SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); - SubElt = Actions.CorrectDelayedTyposInExpr(SubElt.get()); - // If we couldn't parse the subelement, bail out. if (SubElt.isUsable()) { InitExprs.push_back(SubElt.get()); @@ -527,8 +525,7 @@ ExprResult Parser::ParseExpansionInitList() { /// initializer. ExprVector InitExprs; - if (Tok.is(tok::r_brace) || !ParseExpressionList(InitExprs, []{}, - false, true)) + if (Tok.is(tok::r_brace) || !ParseExpressionList(InitExprs, []{}, true)) if (!T.consumeClose()) return Actions.ActOnCXXExpansionInitList(LBraceLoc, InitExprs, T.getCloseLocation()); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 6afb7809d3cd..291c70e7bad4 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -370,7 +370,7 @@ static void addContextSensitiveTypeNullability(Parser &P, // Create the attribute. auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * { return Pool.create(P.getNullabilityKeyword(nullability), - SourceRange(nullabilityLoc), nullptr, SourceLocation(), + SourceRange(nullabilityLoc), AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::ContextSensitiveKeyword()); }; @@ -2629,10 +2629,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { if (!Tok.isSimpleTypeSpecifier(getLangOpts())) { // objc-receiver: // expression - // Make sure any typos in the receiver are corrected or diagnosed, so that - // proper recovery can happen. FIXME: Perhaps filter the corrected expr to - // only the things that are valid ObjC receivers? - ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult Receiver = ParseExpression(); if (Receiver.isInvalid()) return true; @@ -2809,7 +2806,7 @@ ExprResult Parser::ParseObjCMessageExpression() { } // Otherwise, an arbitrary expression can be the receiver of a send. - ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult Res = ParseExpression(); if (Res.isInvalid()) { SkipUntil(tok::r_square, StopAtSemi); return Res; @@ -2930,8 +2927,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation commaLoc = ConsumeToken(); // Eat the ','. /// Parse the expression after ',' ExprResult Res(ParseAssignmentExpression()); - if (Tok.is(tok::colon)) - Res = Actions.CorrectDelayedTyposInExpr(Res); if (Res.isInvalid()) { if (Tok.is(tok::colon)) { Diag(commaLoc, diag::note_extra_comma_message_arg) << @@ -3078,10 +3073,6 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { return Res; } - Res = Actions.CorrectDelayedTyposInExpr(Res.get()); - if (Res.isInvalid()) - HasInvalidEltExpr = true; - // Parse the ellipsis that indicates a pack expansion. if (Tok.is(tok::ellipsis)) Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken()); @@ -3108,7 +3099,6 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { SmallVector Elements; // dictionary elements. ConsumeBrace(); // consume the l_square. - bool HasInvalidEltExpr = false; while (Tok.isNot(tok::r_brace)) { // Parse the comma separated key : value expressions. ExprResult KeyExpr; @@ -3138,12 +3128,6 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { return ValueExpr; } - // Check the key and value for possible typos - KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get()); - ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get()); - if (KeyExpr.isInvalid() || ValueExpr.isInvalid()) - HasInvalidEltExpr = true; - // Parse the ellipsis that designates this as a pack expansion. Do not // ActOnPackExpansion here, leave it to template instantiation time where // we can get better diagnostics. @@ -3163,9 +3147,6 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { } SourceLocation EndLoc = ConsumeBrace(); - if (HasInvalidEltExpr) - return ExprError(); - // Create the ObjCDictionaryLiteral. return Actions.ObjC().BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc), Elements); diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index ca4f878464c4..f2849c4eac7c 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -653,7 +653,7 @@ ExprResult Parser::ParseOpenACCConditionExpr() { // it does in an if/while/etc (See ParseCXXCondition), however as it was // written with Fortran/C in mind, we're going to assume it just means an // 'expression evaluating to boolean'. - ExprResult ER = getActions().CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult ER = ParseExpression(); if (!ER.isUsable()) return ER; @@ -761,12 +761,6 @@ Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, if (!ER.isUsable()) return {ER, OpenACCParseCanContinue::Cannot}; - // Parsing can continue after the initial assignment expression parsing, so - // even if there was a typo, we can continue. - ER = getActions().CorrectDelayedTyposInExpr(ER); - if (!ER.isUsable()) - return {ER, OpenACCParseCanContinue::Can}; - return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()), OpenACCParseCanContinue::Can}; } @@ -836,8 +830,7 @@ ExprResult Parser::ParseOpenACCSizeExpr(OpenACCClauseKind CK) { return getActions().OpenACC().ActOnOpenACCAsteriskSizeExpr(AsteriskLoc); } - ExprResult SizeExpr = - getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); + ExprResult SizeExpr = ParseConstantExpression(); if (!SizeExpr.isUsable()) return SizeExpr; @@ -891,8 +884,7 @@ Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) { ConsumeToken(); // Parse this as a const-expression, and we'll check its integer-ness/value // in CheckGangExpr. - ExprResult Res = - getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); + ExprResult Res = ParseConstantExpression(); return {OpenACCGangKind::Dim, Res}; } @@ -1089,8 +1081,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( case OpenACCClauseKind::Collapse: { bool HasForce = tryParseAndConsumeSpecialTokenKind( *this, OpenACCSpecialTokenKind::Force, ClauseKind); - ExprResult LoopCount = - getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); + ExprResult LoopCount = ParseConstantExpression(); if (LoopCount.isInvalid()) { Parens.skipToEnd(); return OpenACCCanContinue(); @@ -1387,7 +1378,7 @@ ExprResult Parser::ParseOpenACCIDExpression() { /*isAddressOfOperand=*/false); } - return getActions().CorrectDelayedTyposInExpr(Res); + return Res; } std::variant @@ -1414,9 +1405,8 @@ Parser::ParseOpenACCBindClauseArgument() { return std::monostate{}; } - ExprResult Res = - getActions().CorrectDelayedTyposInExpr(ParseStringLiteralExpression( - /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true)); + ExprResult Res = ParseStringLiteralExpression( + /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true); if (!Res.isUsable()) return std::monostate{}; return cast(Res.get()); @@ -1430,10 +1420,6 @@ Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCDirectiveKind DK, if (!Res.isUsable()) return {Res, OpenACCParseCanContinue::Cannot}; - Res = getActions().CorrectDelayedTyposInExpr(Res.get()); - if (!Res.isUsable()) - return {Res, OpenACCParseCanContinue::Can}; - Res = getActions().OpenACC().ActOnVar(DK, CK, Res.get()); return {Res, OpenACCParseCanContinue::Can}; diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index e41e5ba8596b..78d3503d8eb6 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -576,6 +576,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { return DeclGroupPtrTy(); } + Scope *OuterScope = getCurScope(); // Enter scope. DeclarationNameInfo DirName; SourceLocation Loc = Tok.getLocation(); @@ -614,12 +615,17 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { IsCorrect = false; } + // This needs to be called within the scope because + // processImplicitMapsWithDefaultMappers may add clauses when analyzing nested + // types. The scope used for calling ActOnOpenMPDeclareMapperDirective, + // however, needs to be the outer one, otherwise declared mappers don't become + // visible. + DeclGroupPtrTy DG = Actions.OpenMP().ActOnOpenMPDeclareMapperDirective( + OuterScope, Actions.getCurLexicalContext(), MapperId, MapperType, + Range.getBegin(), VName, AS, MapperVarRef.get(), Clauses); // Exit scope. Actions.OpenMP().EndOpenMPDSABlock(nullptr); OMPDirectiveScope.Exit(); - DeclGroupPtrTy DG = Actions.OpenMP().ActOnOpenMPDeclareMapperDirective( - getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType, - Range.getBegin(), VName, AS, MapperVarRef.get(), Clauses); if (!IsCorrect) return DeclGroupPtrTy(); @@ -1483,6 +1489,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); SmallVector AdjustNothing; SmallVector AdjustNeedDevicePtr; + SmallVector AdjustNeedDeviceAddr; SmallVector AppendArgs; SourceLocation AdjustArgsLoc, AppendArgsLoc; @@ -1515,11 +1522,21 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, SmallVector Vars; IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args, Vars, Data); - if (!IsError) - llvm::append_range(Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing - ? AdjustNothing - : AdjustNeedDevicePtr, - Vars); + if (!IsError) { + switch (Data.ExtraModifier) { + case OMPC_ADJUST_ARGS_nothing: + llvm::append_range(AdjustNothing, Vars); + break; + case OMPC_ADJUST_ARGS_need_device_ptr: + llvm::append_range(AdjustNeedDevicePtr, Vars); + break; + case OMPC_ADJUST_ARGS_need_device_addr: + llvm::append_range(AdjustNeedDeviceAddr, Vars); + break; + default: + llvm_unreachable("Unexpected 'adjust_args' clause modifier."); + } + } break; } case OMPC_append_args: @@ -1559,8 +1576,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, if (DeclVarData && !TI.Sets.empty()) Actions.OpenMP().ActOnOpenMPDeclareVariantDirective( DeclVarData->first, DeclVarData->second, TI, AdjustNothing, - AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc, - SourceRange(Loc, Tok.getLocation())); + AdjustNeedDevicePtr, AdjustNeedDeviceAddr, AppendArgs, AdjustArgsLoc, + AppendArgsLoc, SourceRange(Loc, Tok.getLocation())); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); @@ -3589,8 +3606,7 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, while (Tok.isNot(tok::r_paren)) { SourceLocation Loc = Tok.getLocation(); ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr); - ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr( - ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + ExprResult PTExpr = ParseRHSOfBinaryExpression(LHS, prec::Conditional); PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc, /*DiscardedValue=*/false); if (PTExpr.isUsable()) { @@ -3651,8 +3667,7 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, // Parse the variable. SourceLocation VarLoc = Tok.getLocation(); - ExprResult InteropVarExpr = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + ExprResult InteropVarExpr = ParseAssignmentExpression(); if (!InteropVarExpr.isUsable()) { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -4277,8 +4292,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() { // Parse SourceLocation Loc = Tok.getLocation(); ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr); - ExprResult Begin = Actions.CorrectDelayedTyposInExpr( - ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + ExprResult Begin = ParseRHSOfBinaryExpression(LHS, prec::Conditional); Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc, /*DiscardedValue=*/false); // Parse ':'. @@ -4289,8 +4303,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() { // Parse Loc = Tok.getLocation(); LHS = ParseCastExpression(CastParseKind::AnyCastExpr); - ExprResult End = Actions.CorrectDelayedTyposInExpr( - ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + ExprResult End = ParseRHSOfBinaryExpression(LHS, prec::Conditional); End = Actions.ActOnFinishFullExpr(End.get(), Loc, /*DiscardedValue=*/false); @@ -4303,8 +4316,7 @@ ExprResult Parser::ParseOpenMPIteratorsExpr() { // Parse Loc = Tok.getLocation(); LHS = ParseCastExpression(CastParseKind::AnyCastExpr); - Step = Actions.CorrectDelayedTyposInExpr( - ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Step = ParseRHSOfBinaryExpression(LHS, prec::Conditional); Step = Actions.ActOnFinishFullExpr(Step.get(), Loc, /*DiscardedValue=*/false); } @@ -4786,7 +4798,6 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); Tail = ParseOpenMPIteratorsExpr(); } - Tail = Actions.CorrectDelayedTyposInExpr(Tail); Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(), /*DiscardedValue=*/false); if (Tail.isUsable() || Data.AllocateAlignment) { @@ -4818,7 +4829,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) { - Diag(Tok, diag::err_omp_unknown_adjust_args_op); + Diag(Tok, diag::err_omp_unknown_adjust_args_op) + << (getLangOpts().OpenMP >= 60 ? 1 : 0); SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); @@ -4846,8 +4858,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) { // Parse variable - ExprResult VarExpr = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + ExprResult VarExpr = ParseAssignmentExpression(); if (VarExpr.isUsable()) { Vars.push_back(VarExpr.get()); } else { @@ -4884,6 +4895,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, SourceLocation ELoc = ConsumeToken(); if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) { + bool Malformed = false; while (Tok.isNot(tok::r_paren)) { if (Tok.is(tok::identifier)) { // identifier could be a linear kind (val, uval, ref) or step @@ -4920,6 +4932,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ModifierFound = true; } else { StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); + if (!StepFound) { + Malformed = true; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } } } else { // parse an integer expression as step size @@ -4931,7 +4948,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end)) break; } - if (!StepFound && !ModifierFound) + if (!Malformed && !StepFound && !ModifierFound) Diag(ELoc, diag::err_expected_expression); } else { // for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1) diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 6341e565b504..98933811265e 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1926,7 +1926,7 @@ void Parser::HandlePragmaAttribute() { SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::GNU()); else ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr, diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 499a079ac5b5..5b61ba38829c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -631,7 +631,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { { ParseScopeFlags FilterScope(this, getCurScope()->getFlags() | Scope::SEHFilterScope); - FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + FilterExpr = ParseExpression(); } if (getLangOpts().Borland) { @@ -861,10 +861,12 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, << "'case'" << tok::colon << FixItHint::CreateReplacement(ColonLoc, ":"); } else { - SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); + SourceLocation ExpectedLoc = getEndOfPreviousToken(); + Diag(ExpectedLoc, diag::err_expected_after) << "'case'" << tok::colon << FixItHint::CreateInsertion(ExpectedLoc, ":"); + ColonLoc = ExpectedLoc; } @@ -1858,11 +1860,7 @@ StmtResult Parser::ParseDoStatement() { SourceLocation Start = Tok.getLocation(); ExprResult Cond = ParseExpression(); - // Correct the typos in condition before closing the scope. - if (Cond.isUsable()) - Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr, - /*RecoverUncorrectedTypos=*/true); - else { + if (!Cond.isUsable()) { if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) SkipUntil(tok::semi); Cond = Actions.CreateRecoveryExpr( @@ -2061,7 +2059,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { } } else { ProhibitAttributes(attrs); - Value = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + Value = ParseExpression(); ForEach = isTokIdentifier_in(); @@ -2221,19 +2219,17 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRangeInfo.ParsedForRangeDecl()) { - ExprResult CorrectedRange = - Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get()); if (ForRangeInfo.ExpansionStmt) ForRangeStmt = Actions.ActOnCXXExpansionStmt( - ExpansionStmtTemplateParm, TemplateKWLoc, ForLoc, T.getOpenLocation(), - FirstPart.get(), ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, - CorrectedRange.get(), T.getCloseLocation(), Sema::BFRK_Build, - ForRangeInfo.LifetimeExtendTemps); + ExpansionStmtTemplateParm, TemplateKWLoc, ForLoc, T.getOpenLocation(), + FirstPart.get(), ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, + ForRangeInfo.RangeExpr.get(), T.getCloseLocation(), Sema::BFRK_Build, + ForRangeInfo.LifetimeExtendTemps); else ForRangeStmt = Actions.ActOnCXXForRangeStmt( getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(), ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, - CorrectedRange.get(), T.getCloseLocation(), Sema::BFRK_Build, + ForRangeInfo.RangeExpr.get(), T.getCloseLocation(), Sema::BFRK_Build, ForRangeInfo.LifetimeExtendTemps); } else if (ForEach) { // Similarly, we need to do the semantic analysis for a for-range @@ -2407,8 +2403,8 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc, ArgsUnion(Hint.ValueExpr)}; TempAttrs.addNew(Hint.PragmaNameLoc->getIdentifierInfo(), Hint.Range, - /*scopeName=*/nullptr, Hint.PragmaNameLoc->getLoc(), - ArgHints, /*numArgs=*/4, ParsedAttr::Form::Pragma()); + AttributeScopeInfo(), ArgHints, /*numArgs=*/4, + ParsedAttr::Form::Pragma()); } // Get the next statement. diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index f2417479a0e7..182907df5607 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -864,7 +864,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl &Names, // Read the parenthesized expression. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + ExprResult Res = ParseExpression(); T.consumeClose(); if (Res.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index a2e21c4dcff5..65868915505a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -298,8 +298,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, return nullptr; } - ExprResult ConstraintExprResult = - Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + ExprResult ConstraintExprResult = ParseConstraintExpression(); if (ConstraintExprResult.isInvalid()) { SkipUntil(tok::semi); if (D) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 16ed0c05ce62..4b81e19cc26f 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1896,6 +1896,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC, return AnnotatedNameKind::Unresolved; } +SourceLocation Parser::getEndOfPreviousToken() const { + SourceLocation TokenEndLoc = PP.getLocForEndOfToken(PrevTokLocation); + return TokenEndLoc.isValid() ? TokenEndLoc : Tok.getLocation(); +} + bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { assert(Tok.isNot(tok::identifier)); Diag(Tok, diag::ext_keyword_as_ident) @@ -2375,7 +2380,8 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { Parser::DeclGroupPtrTy Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { - SourceLocation StartLoc = Tok.getLocation(); + Token Introducer = Tok; + SourceLocation StartLoc = Introducer.getLocation(); Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export) ? Sema::ModuleDeclKind::Interface @@ -2394,7 +2400,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { // Parse a global-module-fragment, if present. if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) { SourceLocation SemiLoc = ConsumeToken(); - if (ImportState != Sema::ModuleImportState::FirstDecl) { + if (!Introducer.isFirstPPToken()) { Diag(StartLoc, diag::err_global_module_introducer_not_at_start) << SourceRange(StartLoc, SemiLoc); return nullptr; @@ -2451,7 +2457,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { ExpectAndConsumeSemi(diag::err_module_expected_semi); return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition, - ImportState); + ImportState, Introducer.isFirstPPToken()); } Decl *Parser::ParseModuleImport(SourceLocation AtLoc, diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index 1829a4ff3504..109cdf990543 100644 --- a/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/clang/lib/Rewrite/HTMLRewrite.cpp @@ -17,9 +17,7 @@ #include "clang/Lex/TokenConcatenation.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/RewriteBuffer.h" -#include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index fbfb242598c2..9f19f13592e8 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -115,6 +115,14 @@ bool MultiplexExternalSemaSource::wasThisDeclarationADefinition( return false; } +bool MultiplexExternalSemaSource::hasInitializerWithSideEffects( + const VarDecl *VD) const { + for (const auto &S : Sources) + if (S->hasInitializerWithSideEffects(VD)) + return true; + return false; +} + bool MultiplexExternalSemaSource::FindExternalVisibleDeclsByName( const DeclContext *DC, DeclarationName Name, const DeclContext *OriginalDC) { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 523d3ebc5ccf..9098de805e59 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1227,15 +1227,6 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { assert(LateParsedInstantiations.empty() && "end of TU template instantiation should not create more " "late-parsed templates"); - - // Report diagnostics for uncorrected delayed typos. Ideally all of them - // should have been corrected by that time, but it is very hard to cover all - // cases in practice. - for (const auto &Typo : DelayedTypos) { - // We pass an empty TypoCorrection to indicate no correction was performed. - Typo.second.DiagHandler(TypoCorrection()); - } - DelayedTypos.clear(); } void Sema::ActOnEndOfTranslationUnit() { diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index def909fc2478..f21cbbbdb44e 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -303,10 +303,9 @@ static void ProcessAPINotes(Sema &S, Decl *D, AttributeFactory AF{}; AttributePool AP{AF}; auto &C = S.getASTContext(); - ParsedAttr *SNA = - AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr, - SourceLocation(), nullptr, nullptr, nullptr, - ParsedAttr::Form::GNU()); + ParsedAttr *SNA = AP.create( + &C.Idents.get("swift_name"), SourceRange(), AttributeScopeInfo(), + nullptr, nullptr, nullptr, ParsedAttr::Form::GNU()); if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA, /*IsAsync=*/false)) diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 14e16bc39eb3..e15a43c11651 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -161,12 +161,14 @@ namespace { Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } - void checkObjCConversion(CheckedConversionKind CCK) { + void checkObjCConversion(CheckedConversionKind CCK, + bool IsReinterpretCast = false) { assert(Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()); Expr *src = SrcExpr.get(); - if (Self.ObjC().CheckObjCConversion(OpRange, DestType, src, CCK) == - SemaObjC::ACR_unbridged) + if (Self.ObjC().CheckObjCConversion( + OpRange, DestType, src, CCK, true, false, BO_PtrMemD, + IsReinterpretCast) == SemaObjC::ACR_unbridged) IsARCUnbridgedCast = true; SrcExpr = src; } @@ -1263,7 +1265,8 @@ void CastOperation::CheckReinterpretCast() { if (isValidCast(tcr)) { if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) - checkObjCConversion(CheckedConversionKind::OtherCast); + checkObjCConversion(CheckedConversionKind::OtherCast, + /*IsReinterpretCast=*/true); DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType)) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8f8e1ceb7197..69276ce418fa 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2648,8 +2648,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; ExprResult Res = BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); - if (Res.isInvalid()) - CorrectDelayedTyposInExpr(TheCallResult.get()); return Res; } case Builtin::BI__builtin_dump_struct: diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 790ed3c0f1d0..52ac50bb4d5a 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1081,10 +1081,10 @@ static bool CheckFunctionConstraintsWithoutInstantiation( // FIXME: Add TemplateArgs through the 'Innermost' parameter once // the refactoring of getTemplateInstantiationArgs() relands. MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(Template, std::nullopt, /*Final=*/false); + MLTAL.addOuterTemplateArguments(Template, {}, /*Final=*/false); SemaRef.getTemplateInstantiationArgs( MLTAL, /*D=*/FD, FD, - /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, + /*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); MLTAL.replaceInnermostTemplateArguments(Template, TemplateArgs); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 425b32e53a7b..a1389c6c034b 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -309,15 +309,6 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, if (Result.isInvalid()) return ExprError(); - // We meant exactly what we asked for. No need for typo correction. - if (auto *TE = dyn_cast(Result.get())) { - S.clearDelayedTypo(TE); - S.Diag(Loc, diag::err_no_member) - << NameInfo.getName() << Base->getType()->getAsCXXRecordDecl() - << Base->getSourceRange(); - return ExprError(); - } - auto EndLoc = Args.empty() ? Loc : Args.back()->getEndLoc(); return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, EndLoc, nullptr); } @@ -811,7 +802,6 @@ ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { return ExprError(); if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) { - CorrectDelayedTyposInExpr(E); return ExprError(); } @@ -970,7 +960,6 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { return ExprError(); if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) { - CorrectDelayedTyposInExpr(E); return ExprError(); } @@ -1025,7 +1014,6 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) { if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) { - CorrectDelayedTyposInExpr(E); return StmtError(); } return BuildCoreturnStmt(Loc, E); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 11664414df46..e4a74611d075 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -64,6 +64,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/TargetParser/Triple.h" #include @@ -2891,6 +2892,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.HLSL().mergeWaveSizeAttr(D, *WS, WS->getMin(), WS->getMax(), WS->getPreferred(), WS->getSpelledArgsCount()); + else if (const auto *CI = dyn_cast(Attr)) + NewAttr = S.HLSL().mergeVkConstantIdAttr(D, *CI, CI->getId()); else if (const auto *SA = dyn_cast(Attr)) NewAttr = S.HLSL().mergeShaderAttr(D, *SA, SA->getType()); else if (isa(Attr)) @@ -13525,8 +13528,28 @@ bool Sema::GloballyUniqueObjectMightBeAccidentallyDuplicated( // If the object isn't hidden, the dynamic linker will prevent duplication. clang::LinkageInfo Lnk = Target->getLinkageAndVisibility(); - if (Lnk.getVisibility() != HiddenVisibility) + + // The target is "hidden" (from the dynamic linker) if: + // 1. On posix, it has hidden visibility, or + // 2. On windows, it has no import/export annotation + if (Context.getTargetInfo().shouldDLLImportComdatSymbols()) { + if (Target->hasAttr() || Target->hasAttr()) + return false; + + // If the variable isn't directly annotated, check to see if it's a member + // of an annotated class. + const VarDecl *VD = dyn_cast(Target); + + if (VD && VD->isStaticDataMember()) { + const CXXRecordDecl *Ctx = dyn_cast(VD->getDeclContext()); + if (Ctx && + (Ctx->hasAttr() || Ctx->hasAttr())) + return false; + } + } else if (Lnk.getVisibility() != HiddenVisibility) { + // Posix case return false; + } // If the obj doesn't have external linkage, it's supposed to be duplicated. if (!isExternalFormalLinkage(Lnk.getLinkage())) @@ -13557,19 +13580,16 @@ void Sema::DiagnoseUniqueObjectDuplication(const VarDecl *VD) { // duplicated when built into a shared library, which causes problems if it's // mutable (since the copies won't be in sync) or its initialization has side // effects (since it will run once per copy instead of once globally). - // FIXME: Windows uses dllexport/dllimport instead of visibility, and we don't - // handle that yet. Disable the warning on Windows for now. // Don't diagnose if we're inside a template, because it's not practical to // fix the warning in most cases. - if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() && - !VD->isTemplated() && + if (!VD->isTemplated() && GloballyUniqueObjectMightBeAccidentallyDuplicated(VD)) { QualType Type = VD->getType(); if (looksMutable(Type, VD->getASTContext())) { Diag(VD->getLocation(), diag::warn_possible_object_duplication_mutable) - << VD; + << VD << Context.getTargetInfo().shouldDLLImportComdatSymbols(); } // To keep false positives low, only warn if we're certain that the @@ -13582,7 +13602,7 @@ void Sema::DiagnoseUniqueObjectDuplication(const VarDecl *VD) { /*IncludePossibleEffects=*/false) && !isa(Init->IgnoreParenImpCasts())) { Diag(Init->getExprLoc(), diag::warn_possible_object_duplication_init) - << VD; + << VD << Context.getTargetInfo().shouldDLLImportComdatSymbols(); } } } @@ -13591,7 +13611,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (!RealDecl) { - CorrectDelayedTyposInExpr(Init, dyn_cast_or_null(RealDecl)); return; } @@ -13614,12 +13633,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { } if (VDecl->isInvalidDecl()) { - ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); - SmallVector SubExprs; - if (Res.isUsable()) - SubExprs.push_back(Res.get()); ExprResult Recovery = - CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), SubExprs); + CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init}); if (Expr *E = Recovery.get()) VDecl->setInit(E); return; @@ -13634,23 +13649,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (VDecl->getType()->isUndeducedType()) { - // Attempt typo correction early so that the type of the init expression can - // be deduced based on the chosen correction if the original init contains a - // TypoExpr. - ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); - if (!Res.isUsable()) { - // There are unresolved typos in Init, just drop them. - // FIXME: improve the recovery strategy to preserve the Init. - RealDecl->setInvalidDecl(); - return; - } - if (Res.get()->containsErrors()) { + if (Init->containsErrors()) { // Invalidate the decl as we don't know the type for recovery-expr yet. RealDecl->setInvalidDecl(); - VDecl->setInit(Res.get()); + VDecl->setInit(Init); return; } - Init = Res.get(); if (DeduceVariableDeclarationType(VDecl, DirectInit, Init)) return; @@ -13762,6 +13766,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + if (getLangOpts().HLSL) + if (!HLSL().handleInitialization(VDecl, Init)) + return; + // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; @@ -13796,23 +13804,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { InitializedFromParenListExpr = true; } - // Try to correct any TypoExprs in the initialization arguments. - for (size_t Idx = 0; Idx < Args.size(); ++Idx) { - ExprResult Res = CorrectDelayedTyposInExpr( - Args[Idx], VDecl, /*RecoverUncorrectedTypos=*/true, - [this, Entity, Kind](Expr *E) { - InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); - return Init.Failed() ? ExprError() : E; - }); - if (!Res.isUsable()) { - VDecl->setInvalidDecl(); - } else if (Res.get() != Args[Idx]) { - Args[Idx] = Res.get(); - } - } - if (VDecl->isInvalidDecl()) - return; - InitializationSequence InitSeq(*this, Entity, Kind, Args, /*TopLevelOfInitList=*/false, /*TreatUnavailableAsInvalid=*/false); @@ -13985,31 +13976,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // We allow integer constant expressions in all cases. } else if (DclT->isIntegralOrEnumerationType()) { - // Check whether the expression is a constant expression. - SourceLocation Loc; if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified()) // In C++11, a non-constexpr const static data member with an // in-class initializer cannot be volatile. Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile); - else if (Init->isValueDependent()) - ; // Nothing to check. - else if (Init->isIntegerConstantExpr(Context, &Loc)) - ; // Ok, it's an ICE! - else if (Init->getType()->isScopedEnumeralType() && - Init->isCXX11ConstantExpr(Context)) - ; // Ok, it is a scoped-enum constant expression. - else if (Init->isEvaluatable(Context)) { - // If we can constant fold the initializer through heroics, accept it, - // but report this as a use of an extension for -pedantic. - Diag(Loc, diag::ext_in_class_initializer_non_constant) - << Init->getSourceRange(); - } else { - // Otherwise, this is some crazy unknown case. Report the issue at the - // location provided by the isIntegerConstantExpr failed check. - Diag(Loc, diag::err_in_class_initializer_non_constant) - << Init->getSourceRange(); - VDecl->setInvalidDecl(); - } // We allow foldable floating-point constants as an extension. } else if (DclT->isFloatingType()) { // also permits complex, which is ok @@ -14222,6 +14192,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { } } + // HLSL variable with the `vk::constant_id` attribute must be initialized. + if (!Var->isInvalidDecl() && Var->hasAttr()) { + Diag(Var->getLocation(), diag::err_specialization_const); + Var->setInvalidDecl(); + return; + } + if (!Var->isInvalidDecl() && RealDecl->hasAttr()) { if (Var->getStorageClass() == SC_Extern) { Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl) @@ -14747,6 +14724,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Compute and cache the constant value, and remember that we have a // constant initializer. if (HasConstInit) { + if (var->isStaticDataMember() && !var->isInline() && + var->getLexicalDeclContext()->isRecord() && + type->isIntegralOrEnumerationType()) { + // In C++98, in-class initialization for a static data member must + // be an integer constant expression. + SourceLocation Loc; + if (!Init->isIntegerConstantExpr(Context, &Loc)) { + Diag(Loc, diag::ext_in_class_initializer_non_constant) + << Init->getSourceRange(); + } + } (void)var->checkForConstantInitialization(Notes); Notes.clear(); } else if (CacheCulprit) { @@ -14782,6 +14770,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { << Attr->getRange() << Attr->isConstinit(); for (auto &it : Notes) Diag(it.first, it.second); + } else if (var->isStaticDataMember() && !var->isInline() && + var->getLexicalDeclContext()->isRecord()) { + Diag(var->getLocation(), diag::err_in_class_initializer_non_constant) + << Init->getSourceRange(); + for (auto &it : Notes) + Diag(it.first, it.second); + var->setInvalidDecl(); } else if (IsGlobal && !getDiagnostics().isIgnored(diag::warn_global_constructor, var->getLocation())) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a893b86058bf..35182ea4d3c1 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -53,7 +53,6 @@ #include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/SemaRISCV.h" -#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaWasm.h" @@ -1986,14 +1985,13 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), AL.isRegularKeywordAttribute() - ? diag::err_keyword_not_supported_on_target - : diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + if (AL.isRegularKeywordAttribute()) + Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target); + else + DiagnoseUnknownAttribute(AL); AL.setInvalid(); return true; } - return false; } @@ -3292,8 +3290,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { if (ParsedAttrs.Duplicate != "") return Diag(LiteralLoc, diag::err_duplicate_target_attribute) << Duplicate << None << ParsedAttrs.Duplicate << Target; - for (const auto &Feature : ParsedAttrs.Features) { - StringRef CurFeature = Feature; + for (StringRef CurFeature : ParsedAttrs.Features) { if (!CurFeature.starts_with('+') && !CurFeature.starts_with('-')) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << AttrStr << Target; @@ -3301,8 +3298,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { } if (Context.getTargetInfo().getTriple().isLoongArch()) { - for (const auto &Feature : ParsedAttrs.Features) { - StringRef CurFeature = Feature; + for (StringRef CurFeature : ParsedAttrs.Features) { if (CurFeature.starts_with("!arch=")) { StringRef ArchValue = CurFeature.split("=").second.trim(); return Diag(LiteralLoc, diag::err_attribute_unsupported) @@ -7653,6 +7649,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLVkExtBuiltinInput: S.HLSL().handleVkExtBuiltinInputAttr(D, AL); break; + case ParsedAttr::AT_HLSLVkConstantId: + S.HLSL().handleVkConstantIdAttr(D, AL); + break; case ParsedAttr::AT_HLSLSV_GroupThreadID: S.HLSL().handleSV_GroupThreadIDAttr(D, AL); break; @@ -8023,8 +8022,7 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { - S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + S.DiagnoseUnknownAttribute(AL); } else { S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL << AL.getRange(); @@ -8042,15 +8040,45 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) { void Sema::DiagnoseUnknownAttribute(const ParsedAttr &AL) { std::string NormalizedFullName = '\'' + AL.getNormalizedFullName() + '\''; - if (auto CorrectedFullName = - AL.getCorrectedFullName(Context.getTargetInfo(), getLangOpts())) { - Diag(AL.getNormalizedRange().getBegin(), - diag::warn_unknown_attribute_ignored_suggestion) - << NormalizedFullName << *CorrectedFullName << AL.getNormalizedRange(); + SourceRange NR = AL.getNormalizedRange(); + + StringRef ScopeName = AL.getNormalizedScopeName(); + std::optional CorrectedScopeName = + AL.tryGetCorrectedScopeName(ScopeName); + if (CorrectedScopeName) { + ScopeName = *CorrectedScopeName; + } + + StringRef AttrName = AL.getNormalizedAttrName(ScopeName); + std::optional CorrectedAttrName = AL.tryGetCorrectedAttrName( + ScopeName, AttrName, Context.getTargetInfo(), getLangOpts()); + if (CorrectedAttrName) { + AttrName = *CorrectedAttrName; + } + + if (CorrectedScopeName || CorrectedAttrName) { + std::string CorrectedFullName = + AL.getNormalizedFullName(ScopeName, AttrName); + SemaDiagnosticBuilder D = + Diag(CorrectedScopeName ? NR.getBegin() : AL.getRange().getBegin(), + diag::warn_unknown_attribute_ignored_suggestion); + + D << NormalizedFullName << CorrectedFullName; + + if (AL.isExplicitScope()) { + D << FixItHint::CreateReplacement(NR, CorrectedFullName) << NR; + } else { + if (CorrectedScopeName) { + D << FixItHint::CreateReplacement(SourceRange(AL.getScopeLoc()), + ScopeName); + } + if (CorrectedAttrName) { + D << FixItHint::CreateReplacement(AL.getRange(), AttrName); + } + } } else { - Diag(AL.getNormalizedRange().getBegin(), - diag::warn_unknown_attribute_ignored) - << NormalizedFullName << AL.getNormalizedRange(); + Diag(NR.getBegin(), diag::warn_unknown_attribute_ignored) + << NormalizedFullName << NR; } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 2a74662e371a..0d524f262bc2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2892,8 +2892,7 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + DiagnoseUnknownAttribute(AL); else Diag(AL.getLoc(), diag::err_base_specifier_attribute) << AL << AL.isRegularKeywordAttribute() << AL.getRange(); @@ -3146,12 +3145,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths); - if (!DerivationOkay) { - if (auto *RD = Derived->getAsCXXRecordDecl(); RD && !RD->isInvalidDecl()) - Diag(Loc, - diag::err_class_not_derived_from_base) << Derived << Base << Range; + if (!DerivationOkay) return true; - } const CXXBasePath *Path = nullptr; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) @@ -4185,10 +4180,6 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { if (ConstraintExpr.isInvalid()) return ExprError(); - ConstraintExpr = CorrectDelayedTyposInExpr(ConstraintExpr); - if (ConstraintExpr.isInvalid()) - return ExprError(); - if (DiagnoseUnexpandedParameterPack(ConstraintExpr.get(), UPPC_RequiresClause)) return ExprError(); @@ -4238,23 +4229,20 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, return; } - ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr, - /*RecoverUncorrectedTypos=*/true); - assert(Init.isUsable() && "Init should at least have a RecoveryExpr"); - if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) { - Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc); + if (!FD->getType()->isDependentType() && !InitExpr.get()->isTypeDependent()) { + InitExpr = ConvertMemberDefaultInitExpression(FD, InitExpr.get(), InitLoc); // C++11 [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. - if (!Init.isInvalid()) - Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false); - if (Init.isInvalid()) { + if (!InitExpr.isInvalid()) + InitExpr = ActOnFinishFullExpr(InitExpr.get(), /*DiscarededValue=*/false); + if (InitExpr.isInvalid()) { FD->setInvalidDecl(); return; } } - FD->setInClassInitializer(Init.get()); + FD->setInClassInitializer(InitExpr.get()); } /// Find the direct and/or virtual base specifiers that @@ -4424,13 +4412,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc) { - ExprResult Res = CorrectDelayedTyposInExpr(Init, /*InitDecl=*/nullptr, - /*RecoverUncorrectedTypos=*/true); - if (!Res.isUsable()) - return true; - Init = Res.get(); - - if (!ConstructorD) + if (!ConstructorD || !Init) return true; AdjustDeclIfTemplate(ConstructorD); @@ -7203,7 +7185,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // "effectively constexpr" for better compatibility. // See https://github.com/llvm/llvm-project/issues/102293 for more info. if (isa(M)) { - auto Check = [](QualType T, auto &&Check) -> bool { + llvm::SmallDenseSet Visited; + auto Check = [&Visited](QualType T, auto &&Check) -> bool { + if (!Visited.insert(T->getCanonicalTypeUnqualified()).second) + return false; const CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); if (!RD || !RD->isCompleteDefinition()) @@ -7212,16 +7197,11 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!RD->hasConstexprDestructor()) return false; - QualType CanUnqualT = T.getCanonicalType().getUnqualifiedType(); for (const CXXBaseSpecifier &B : RD->bases()) - if (B.getType().getCanonicalType().getUnqualifiedType() != - CanUnqualT && - !Check(B.getType(), Check)) + if (!Check(B.getType(), Check)) return false; for (const FieldDecl *FD : RD->fields()) - if (FD->getType().getCanonicalType().getUnqualifiedType() != - CanUnqualT && - !Check(FD->getType(), Check)) + if (!Check(FD->getType(), Check)) return false; return true; }; diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 5fd0c06ab784..926cbf6e0699 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1372,7 +1372,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::UnaryExprOrTypeTraitExprClass: case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: - case Expr::TypoExprClass: // FIXME: Many of the above can throw. return CT_Cannot; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d6ad5d0a9a25..1714605342ea 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2072,9 +2072,9 @@ ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef StringToks) { for (const Token &Tok : StringToks) StringTokLocs.push_back(Tok.getLocation()); - StringLiteral *Lit = StringLiteral::Create( - Context, Literal.GetString(), StringLiteralKind::Unevaluated, false, {}, - &StringTokLocs[0], StringTokLocs.size()); + StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), + StringLiteralKind::Unevaluated, + false, {}, StringTokLocs); if (!Literal.getUDSuffix().empty()) { SourceLocation UDSuffixLoc = @@ -2208,10 +2208,8 @@ Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { Context.getStringLiteralArrayType(CharTy, Literal.GetNumStringChars()); // Pass &StringTokLocs[0], StringTokLocs.size() to factory! - StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), - Kind, Literal.Pascal, StrTy, - &StringTokLocs[0], - StringTokLocs.size()); + StringLiteral *Lit = StringLiteral::Create( + Context, Literal.GetString(), Kind, Literal.Pascal, StrTy, StringTokLocs); if (Literal.getUDSuffix().empty()) return Lit; @@ -2448,42 +2446,6 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, } } -static void emitEmptyLookupTypoDiagnostic(const TypoCorrection &TC, - Sema &SemaRef, const CXXScopeSpec &SS, - DeclarationName Typo, - SourceRange TypoRange, - unsigned DiagnosticID, - unsigned DiagnosticSuggestID) { - DeclContext *Ctx = - SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); - if (!TC) { - // Emit a special diagnostic for failed member lookups. - // FIXME: computing the declaration context might fail here (?) - if (Ctx) - SemaRef.Diag(TypoRange.getBegin(), diag::err_no_member) - << Typo << Ctx << TypoRange; - else - SemaRef.Diag(TypoRange.getBegin(), DiagnosticID) << Typo << TypoRange; - return; - } - - std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); - bool DroppedSpecifier = - TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; - unsigned NoteID = TC.getCorrectionDeclAs() - ? diag::note_implicit_param_decl - : diag::note_previous_decl; - if (!Ctx) - SemaRef.diagnoseTypo( - TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo << TypoRange, - SemaRef.PDiag(NoteID)); - else - SemaRef.diagnoseTypo(TC, - SemaRef.PDiag(diag::err_no_member_suggest) - << Typo << Ctx << DroppedSpecifier << TypoRange, - SemaRef.PDiag(NoteID)); -} - bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) { // During a default argument instantiation the CurContext points // to a CXXMethodDecl; but we can't apply a this-> fixit inside a @@ -2546,8 +2508,7 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) { bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef Args, DeclContext *LookupCtx, - TypoExpr **Out) { + ArrayRef Args, DeclContext *LookupCtx) { DeclarationName Name = R.getLookupName(); SourceRange NameRange = R.getLookupNameInfo().getSourceRange(); @@ -2606,21 +2567,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // We didn't find anything, so try to correct for a typo. TypoCorrection Corrected; - if (S && Out) { - assert(!ExplicitTemplateArgs && - "Diagnosing an empty lookup with explicit template args!"); - *Out = CorrectTypoDelayed( - R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, - [=](const TypoCorrection &TC) { - emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, NameRange, - diagnostic, diagnostic_suggest); - }, - nullptr, CorrectTypoKind::ErrorRecovery, LookupCtx); - if (*Out) - return true; - } else if (S && (Corrected = CorrectTypo( - R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, - CorrectTypoKind::ErrorRecovery, LookupCtx))) { + if (S && (Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, + CCC, CorrectTypoKind::ErrorRecovery, LookupCtx))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -2882,7 +2831,6 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. - TypoExpr *TE = nullptr; DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep() : nullptr); DefaultValidator.IsAddressOfOperand = IsAddressOfOperand; @@ -2898,29 +2846,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, - {}, nullptr, &TE)) { - if (TE && KeywordReplacement) { - auto &State = getTypoExprState(TE); - auto BestTC = State.Consumer->getNextCorrection(); - if (BestTC.isKeyword()) { - auto *II = BestTC.getCorrectionAsIdentifierInfo(); - if (State.DiagHandler) - State.DiagHandler(BestTC); - KeywordReplacement->startToken(); - KeywordReplacement->setKind(II->getTokenID()); - KeywordReplacement->setIdentifierInfo(II); - KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin()); - // Clean up the state associated with the TypoExpr, since it has - // now been diagnosed (without a call to CorrectDelayedTyposInExpr). - clearDelayedTypo(TE); - // Signal that a correction to a keyword was performed by returning a - // valid-but-null ExprResult. - return (Expr*)nullptr; - } - State.Consumer->resetCorrectionStream(); - } - return TE ? TE : ExprError(); - } + {}, nullptr)) + return ExprError(); assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); @@ -3866,7 +3793,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Expr *Lit = StringLiteral::Create(Context, StringRef(TokSpelling.data(), Length), StringLiteralKind::Ordinary, - /*Pascal*/ false, StrTy, &TokLoc, 1); + /*Pascal*/ false, StrTy, TokLoc); return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } @@ -7033,40 +6960,6 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, CurFPFeatureOverrides(), NumParams, UsesADL); } - if (!Context.isDependenceAllowed()) { - // Forget about the nulled arguments since typo correction - // do not handle them well. - TheCall->shrinkNumArgs(Args.size()); - // C cannot always handle TypoExpr nodes in builtin calls and direct - // function calls as their argument checking don't necessarily handle - // dependent types properly, so make sure any TypoExprs have been - // dealt with. - ExprResult Result = CorrectDelayedTyposInExpr(TheCall); - if (!Result.isUsable()) return ExprError(); - CallExpr *TheOldCall = TheCall; - TheCall = dyn_cast(Result.get()); - bool CorrectedTypos = TheCall != TheOldCall; - if (!TheCall) return Result; - Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); - - // A new call expression node was created if some typos were corrected. - // However it may not have been constructed with enough storage. In this - // case, rebuild the node with enough storage. The waste of space is - // immaterial since this only happens when some typos were corrected. - if (CorrectedTypos && Args.size() < NumParams) { - if (Config) - TheCall = CUDAKernelCallExpr::Create( - Context, Fn, cast(Config), Args, ResultTy, VK_PRValue, - RParenLoc, CurFPFeatureOverrides(), NumParams); - else - TheCall = - CallExpr::Create(Context, Fn, Args, ResultTy, VK_PRValue, RParenLoc, - CurFPFeatureOverrides(), NumParams, UsesADL); - } - // We can now handle the nulled arguments for the default arguments. - TheCall->setNumArgsUnsafe(std::max(Args.size(), NumParams)); - } - // Bail out early if calling a builtin with custom type checking. if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) { ExprResult E = CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); @@ -7305,6 +7198,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, // void func(char *para[(int [1]){ 0 }[0]); const Scope *S = getCurScope(); bool IsFileScope = !CurContext->isFunctionOrMethod() && + !S->isInCFunctionScope() && (!S || !S->isFunctionPrototypeScope()); // In C, compound literals are l-values for some reason. @@ -7957,12 +7851,6 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, if (getLangOpts().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); - } else { - // Make sure any TypoExprs have been dealt with. - ExprResult Res = CorrectDelayedTyposInExpr(CastExpr); - if (!Res.isUsable()) - return ExprError(); - CastExpr = Res.get(); } checkUnusedDeclAttributes(D); @@ -9008,30 +8896,6 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr) { - if (!Context.isDependenceAllowed()) { - // C cannot handle TypoExpr nodes in the condition because it - // doesn't handle dependent types properly, so make sure any TypoExprs have - // been dealt with before checking the operands. - ExprResult CondResult = CorrectDelayedTyposInExpr(CondExpr); - ExprResult LHSResult = CorrectDelayedTyposInExpr(LHSExpr); - ExprResult RHSResult = CorrectDelayedTyposInExpr(RHSExpr); - - if (!CondResult.isUsable()) - return ExprError(); - - if (LHSExpr) { - if (!LHSResult.isUsable()) - return ExprError(); - } - - if (!RHSResult.isUsable()) - return ExprError(); - - CondExpr = CondResult.get(); - LHSExpr = LHSResult.get(); - RHSExpr = RHSResult.get(); - } - // If this is the gnu "x ?: y" extension, analyze the types as though the LHS // was the condition. OpaqueValueExpr *opaqueValue = nullptr; @@ -15068,18 +14932,6 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, } } -static NamedDecl *getDeclFromExpr(Expr *E) { - if (!E) - return nullptr; - if (auto *DRE = dyn_cast(E)) - return DRE->getDecl(); - if (auto *ME = dyn_cast(E)) - return ME->getMemberDecl(); - if (auto *IRE = dyn_cast(E)) - return IRE->getDecl(); - return nullptr; -} - // This helper function promotes a binary operator's operands (which are of a // half vector type) to a vector of floats and then truncates the result to // a vector of either half or short. @@ -15115,28 +14967,6 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, return convertVector(BO, ResultTy->castAs()->getElementType(), S); } -static std::pair -CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, - Expr *RHSExpr) { - ExprResult LHS = LHSExpr, RHS = RHSExpr; - if (!S.Context.isDependenceAllowed()) { - // C cannot handle TypoExpr nodes on either side of a binop because it - // doesn't handle dependent types properly, so make sure any TypoExprs have - // been dealt with before checking the operands. - LHS = S.CorrectDelayedTyposInExpr(LHS); - RHS = S.CorrectDelayedTyposInExpr( - RHS, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, - [Opc, LHS](Expr *E) { - if (Opc != BO_Assign) - return ExprResult(E); - // Avoid correcting the RHS to the same Expr as the LHS. - Decl *D = getDeclFromExpr(E); - return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; - }); - } - return std::make_pair(LHS, RHS); -} - /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, @@ -15193,7 +15023,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ExprObjectKind OK = OK_Ordinary; bool ConvertHalfVec = false; - std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); if (!LHS.isUsable() || !RHS.isUsable()) return ExprError(); @@ -15709,12 +15538,8 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr, bool ForFoldExpression) { - ExprResult LHS, RHS; - std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); - if (!LHS.isUsable() || !RHS.isUsable()) + if (!LHSExpr || !RHSExpr) return ExprError(); - LHSExpr = LHS.get(); - RHSExpr = RHS.get(); // We want to end up calling one of SemaPseudoObject::checkAssignment // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if @@ -18311,8 +18136,6 @@ HandleImmediateInvocations(Sema &SemaRef, void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); - unsigned NumTypos = Rec.NumTypos; - if (!Rec.Lambdas.empty()) { using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind; if (!getLangOpts().CPlusPlus20 && @@ -18380,9 +18203,6 @@ void Sema::PopExpressionEvaluationContext() { // Pop the current expression evaluation context off the stack. ExprEvalContexts.pop_back(); - - // The global expression evaluation context record is never popped. - ExprEvalContexts.back().NumTypos += NumTypos; } void Sema::DiscardCleanupsInEvaluationContext() { @@ -20153,8 +19973,6 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { } ExprResult Sema::ActOnConstantExpression(ExprResult Res) { - Res = CorrectDelayedTyposInExpr(Res); - if (!Res.isUsable()) return Res; @@ -21488,15 +21306,6 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { } ExprResult Sema::CheckPlaceholderExpr(Expr *E) { - if (!Context.isDependenceAllowed()) { - // C cannot handle TypoExpr nodes on either side of a binop because it - // doesn't handle dependent types properly, so make sure any TypoExprs have - // been dealt with before checking the operands. - ExprResult Result = CorrectDelayedTyposInExpr(E); - if (!Result.isUsable()) return ExprError(); - E = Result.get(); - } - const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType(); if (!placeholderType) return E; @@ -21539,7 +21348,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { } if (TST.isNull()) TST = Context.getTemplateSpecializationType( - TN, ULE->template_arguments(), /*CanonicalArgs=*/std::nullopt, + TN, ULE->template_arguments(), /*CanonicalArgs=*/{}, HasAnyDependentTA ? Context.DependentTy : Context.IntTy); QualType ET = Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 96e08989eb6d..6d44c4d2da1f 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -42,7 +42,6 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaHLSL.h" -#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaPPC.h" @@ -1504,13 +1503,7 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs, RParenOrBraceLoc, ListInitialization); - // Avoid creating a non-type-dependent expression that contains typos. - // Non-type-dependent expressions are liable to be discarded without - // checking for embedded typos. - if (!Result.isInvalid() && Result.get()->isInstantiationDependent() && - !Result.get()->isTypeDependent()) - Result = CorrectDelayedTyposInExpr(Result.get()); - else if (Result.isInvalid()) + if (Result.isInvalid()) Result = CreateRecoveryExpr(TInfo->getTypeLoc().getBeginLoc(), RParenOrBraceLoc, exprs, Ty); return Result; @@ -7657,417 +7650,6 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( CurrentLSI->clearPotentialCaptures(); } -static ExprResult attemptRecovery(Sema &SemaRef, - const TypoCorrectionConsumer &Consumer, - const TypoCorrection &TC) { - LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), - Consumer.getLookupResult().getLookupKind()); - const CXXScopeSpec *SS = Consumer.getSS(); - CXXScopeSpec NewSS; - - // Use an approprate CXXScopeSpec for building the expr. - if (auto *NNS = TC.getCorrectionSpecifier()) - NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); - else if (SS && !TC.WillReplaceSpecifier()) - NewSS = *SS; - - if (auto *ND = TC.getFoundDecl()) { - R.setLookupName(ND->getDeclName()); - R.addDecl(ND); - if (ND->isCXXClassMember()) { - // Figure out the correct naming class to add to the LookupResult. - CXXRecordDecl *Record = nullptr; - if (auto *NNS = TC.getCorrectionSpecifier()) - Record = NNS->getAsType()->getAsCXXRecordDecl(); - if (!Record) - Record = - dyn_cast(ND->getDeclContext()->getRedeclContext()); - if (Record) - R.setNamingClass(Record); - - // Detect and handle the case where the decl might be an implicit - // member. - if (SemaRef.isPotentialImplicitMemberAccess( - NewSS, R, Consumer.isAddressOfOperand())) - return SemaRef.BuildPossibleImplicitMemberExpr( - NewSS, /*TemplateKWLoc*/ SourceLocation(), R, - /*TemplateArgs*/ nullptr, /*S*/ nullptr); - } else if (auto *Ivar = dyn_cast(ND)) { - return SemaRef.ObjC().LookupInObjCMethod(R, Consumer.getScope(), - Ivar->getIdentifier()); - } - } - - return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false, - /*AcceptInvalidDecl*/ true); -} - -namespace { -class FindTypoExprs : public DynamicRecursiveASTVisitor { - llvm::SmallSetVector &TypoExprs; - -public: - explicit FindTypoExprs(llvm::SmallSetVector &TypoExprs) - : TypoExprs(TypoExprs) {} - bool VisitTypoExpr(TypoExpr *TE) override { - TypoExprs.insert(TE); - return true; - } -}; - -class TransformTypos : public TreeTransform { - typedef TreeTransform BaseTransform; - - VarDecl *InitDecl; // A decl to avoid as a correction because it is in the - // process of being initialized. - llvm::function_ref ExprFilter; - llvm::SmallSetVector TypoExprs, AmbiguousTypoExprs; - llvm::SmallDenseMap TransformCache; - llvm::SmallDenseMap OverloadResolution; - - /// Emit diagnostics for all of the TypoExprs encountered. - /// - /// If the TypoExprs were successfully corrected, then the diagnostics should - /// suggest the corrections. Otherwise the diagnostics will not suggest - /// anything (having been passed an empty TypoCorrection). - /// - /// If we've failed to correct due to ambiguous corrections, we need to - /// be sure to pass empty corrections and replacements. Otherwise it's - /// possible that the Consumer has a TypoCorrection that failed to ambiguity - /// and we don't want to report those diagnostics. - void EmitAllDiagnostics(bool IsAmbiguous) { - for (TypoExpr *TE : TypoExprs) { - auto &State = SemaRef.getTypoExprState(TE); - if (State.DiagHandler) { - TypoCorrection TC = IsAmbiguous - ? TypoCorrection() : State.Consumer->getCurrentCorrection(); - ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE]; - - // Extract the NamedDecl from the transformed TypoExpr and add it to the - // TypoCorrection, replacing the existing decls. This ensures the right - // NamedDecl is used in diagnostics e.g. in the case where overload - // resolution was used to select one from several possible decls that - // had been stored in the TypoCorrection. - if (auto *ND = getDeclFromExpr( - Replacement.isInvalid() ? nullptr : Replacement.get())) - TC.setCorrectionDecl(ND); - - State.DiagHandler(TC); - } - SemaRef.clearDelayedTypo(TE); - } - } - - /// Try to advance the typo correction state of the first unfinished TypoExpr. - /// We allow advancement of the correction stream by removing it from the - /// TransformCache which allows `TransformTypoExpr` to advance during the - /// next transformation attempt. - /// - /// Any substitution attempts for the previous TypoExprs (which must have been - /// finished) will need to be retried since it's possible that they will now - /// be invalid given the latest advancement. - /// - /// We need to be sure that we're making progress - it's possible that the - /// tree is so malformed that the transform never makes it to the - /// `TransformTypoExpr`. - /// - /// Returns true if there are any untried correction combinations. - bool CheckAndAdvanceTypoExprCorrectionStreams() { - for (auto *TE : TypoExprs) { - auto &State = SemaRef.getTypoExprState(TE); - TransformCache.erase(TE); - if (!State.Consumer->hasMadeAnyCorrectionProgress()) - return false; - if (!State.Consumer->finished()) - return true; - State.Consumer->resetCorrectionStream(); - } - return false; - } - - NamedDecl *getDeclFromExpr(Expr *E) { - if (auto *OE = dyn_cast_or_null(E)) - E = OverloadResolution[OE]; - - if (!E) - return nullptr; - if (auto *DRE = dyn_cast(E)) - return DRE->getFoundDecl(); - if (auto *ME = dyn_cast(E)) - return ME->getFoundDecl(); - // FIXME: Add any other expr types that could be seen by the delayed typo - // correction TreeTransform for which the corresponding TypoCorrection could - // contain multiple decls. - return nullptr; - } - - ExprResult TryTransform(Expr *E) { - Sema::SFINAETrap Trap(SemaRef); - ExprResult Res = TransformExpr(E); - if (Trap.hasErrorOccurred() || Res.isInvalid()) - return ExprError(); - - return ExprFilter(Res.get()); - } - - // Since correcting typos may intoduce new TypoExprs, this function - // checks for new TypoExprs and recurses if it finds any. Note that it will - // only succeed if it is able to correct all typos in the given expression. - ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) { - if (Res.isInvalid()) { - return Res; - } - // Check to see if any new TypoExprs were created. If so, we need to recurse - // to check their validity. - Expr *FixedExpr = Res.get(); - - auto SavedTypoExprs = std::move(TypoExprs); - auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs); - TypoExprs.clear(); - AmbiguousTypoExprs.clear(); - - FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr); - if (!TypoExprs.empty()) { - // Recurse to handle newly created TypoExprs. If we're not able to - // handle them, discard these TypoExprs. - ExprResult RecurResult = - RecursiveTransformLoop(FixedExpr, IsAmbiguous); - if (RecurResult.isInvalid()) { - Res = ExprError(); - // Recursive corrections didn't work, wipe them away and don't add - // them to the TypoExprs set. Remove them from Sema's TypoExpr list - // since we don't want to clear them twice. Note: it's possible the - // TypoExprs were created recursively and thus won't be in our - // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`. - auto &SemaTypoExprs = SemaRef.TypoExprs; - for (auto *TE : TypoExprs) { - TransformCache.erase(TE); - SemaRef.clearDelayedTypo(TE); - - auto SI = find(SemaTypoExprs, TE); - if (SI != SemaTypoExprs.end()) { - SemaTypoExprs.erase(SI); - } - } - } else { - // TypoExpr is valid: add newly created TypoExprs since we were - // able to correct them. - Res = RecurResult; - SavedTypoExprs.set_union(TypoExprs); - } - } - - TypoExprs = std::move(SavedTypoExprs); - AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs); - - return Res; - } - - // Try to transform the given expression, looping through the correction - // candidates with `CheckAndAdvanceTypoExprCorrectionStreams`. - // - // If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to - // true and this method immediately will return an `ExprError`. - ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) { - ExprResult Res; - auto SavedTypoExprs = std::move(SemaRef.TypoExprs); - SemaRef.TypoExprs.clear(); - - while (true) { - Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); - - // Recursion encountered an ambiguous correction. This means that our - // correction itself is ambiguous, so stop now. - if (IsAmbiguous) - break; - - // If the transform is still valid after checking for any new typos, - // it's good to go. - if (!Res.isInvalid()) - break; - - // The transform was invalid, see if we have any TypoExprs with untried - // correction candidates. - if (!CheckAndAdvanceTypoExprCorrectionStreams()) - break; - } - - // If we found a valid result, double check to make sure it's not ambiguous. - if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) { - auto SavedTransformCache = - llvm::SmallDenseMap(TransformCache); - - // Ensure none of the TypoExprs have multiple typo correction candidates - // with the same edit length that pass all the checks and filters. - while (!AmbiguousTypoExprs.empty()) { - auto TE = AmbiguousTypoExprs.back(); - - // TryTransform itself can create new Typos, adding them to the TypoExpr map - // and invalidating our TypoExprState, so always fetch it instead of storing. - SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition(); - - TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection(); - TypoCorrection Next; - do { - // Fetch the next correction by erasing the typo from the cache and calling - // `TryTransform` which will iterate through corrections in - // `TransformTypoExpr`. - TransformCache.erase(TE); - ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); - - if (!AmbigRes.isInvalid() || IsAmbiguous) { - SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream(); - SavedTransformCache.erase(TE); - Res = ExprError(); - IsAmbiguous = true; - break; - } - } while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) && - Next.getEditDistance(false) == TC.getEditDistance(false)); - - if (IsAmbiguous) - break; - - AmbiguousTypoExprs.remove(TE); - SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition(); - TransformCache[TE] = SavedTransformCache[TE]; - } - TransformCache = std::move(SavedTransformCache); - } - - // Wipe away any newly created TypoExprs that we don't know about. Since we - // clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only - // possible if a `TypoExpr` is created during a transformation but then - // fails before we can discover it. - auto &SemaTypoExprs = SemaRef.TypoExprs; - for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) { - auto TE = *Iterator; - auto FI = find(TypoExprs, TE); - if (FI != TypoExprs.end()) { - Iterator++; - continue; - } - SemaRef.clearDelayedTypo(TE); - Iterator = SemaTypoExprs.erase(Iterator); - } - SemaRef.TypoExprs = std::move(SavedTypoExprs); - - return Res; - } - -public: - TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref Filter) - : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} - - ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation RParenLoc, - Expr *ExecConfig = nullptr) { - auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, - RParenLoc, ExecConfig); - if (auto *OE = dyn_cast(Callee)) { - if (Result.isUsable()) { - Expr *ResultCall = Result.get(); - if (auto *BE = dyn_cast(ResultCall)) - ResultCall = BE->getSubExpr(); - if (auto *CE = dyn_cast(ResultCall)) - OverloadResolution[OE] = CE->getCallee(); - } - } - return Result; - } - - ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } - - ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } - - ExprResult Transform(Expr *E) { - bool IsAmbiguous = false; - ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous); - - if (!Res.isUsable()) - FindTypoExprs(TypoExprs).TraverseStmt(E); - - EmitAllDiagnostics(IsAmbiguous); - - return Res; - } - - ExprResult TransformTypoExpr(TypoExpr *E) { - // If the TypoExpr hasn't been seen before, record it. Otherwise, return the - // cached transformation result if there is one and the TypoExpr isn't the - // first one that was encountered. - auto &CacheEntry = TransformCache[E]; - if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) { - return CacheEntry; - } - - auto &State = SemaRef.getTypoExprState(E); - assert(State.Consumer && "Cannot transform a cleared TypoExpr"); - - // For the first TypoExpr and an uncached TypoExpr, find the next likely - // typo correction and return it. - while (TypoCorrection TC = State.Consumer->getNextCorrection()) { - if (InitDecl && TC.getFoundDecl() == InitDecl) - continue; - // FIXME: If we would typo-correct to an invalid declaration, it's - // probably best to just suppress all errors from this typo correction. - ExprResult NE = State.RecoveryHandler ? - State.RecoveryHandler(SemaRef, E, TC) : - attemptRecovery(SemaRef, *State.Consumer, TC); - if (!NE.isInvalid()) { - // Check whether there may be a second viable correction with the same - // edit distance; if so, remember this TypoExpr may have an ambiguous - // correction so it can be more thoroughly vetted later. - TypoCorrection Next; - if ((Next = State.Consumer->peekNextCorrection()) && - Next.getEditDistance(false) == TC.getEditDistance(false)) { - AmbiguousTypoExprs.insert(E); - } else { - AmbiguousTypoExprs.remove(E); - } - assert(!NE.isUnset() && - "Typo was transformed into a valid-but-null ExprResult"); - return CacheEntry = NE; - } - } - return CacheEntry = ExprError(); - } -}; -} - -ExprResult -Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, - bool RecoverUncorrectedTypos, - llvm::function_ref Filter) { - // If the current evaluation context indicates there are uncorrected typos - // and the current expression isn't guaranteed to not have typos, try to - // resolve any TypoExpr nodes that might be in the expression. - if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && - (E->isTypeDependent() || E->isValueDependent() || - E->isInstantiationDependent())) { - auto TyposResolved = DelayedTypos.size(); - auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); - TyposResolved -= DelayedTypos.size(); - if (Result.isInvalid() || Result.get() != E) { - ExprEvalContexts.back().NumTypos -= TyposResolved; - if (Result.isInvalid() && RecoverUncorrectedTypos) { - struct TyposReplace : TreeTransform { - TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} - ExprResult TransformTypoExpr(clang::TypoExpr *E) { - return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(), - E->getEndLoc(), {}); - } - } TT(*this); - return TT.TransformExpr(E); - } - return Result; - } - assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); - } - return E; -} - ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, bool IsConstexpr, bool IsTemplateArgument) { @@ -8099,8 +7681,6 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, DiagnoseUnusedExprResult(FullExpr.get(), diag::warn_unused_expr); } - FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr, - /*RecoverUncorrectedTypos=*/true); if (FullExpr.isInvalid()) return ExprError(); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index c844847c0471..944bf6c4de66 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -661,64 +661,11 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, return true; } -namespace { - -// Callback to only accept typo corrections that are either a ValueDecl or a -// FunctionTemplateDecl and are declared in the current record or, for a C++ -// classes, one of its base classes. -class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { -public: - explicit RecordMemberExprValidatorCCC(QualType RTy) - : Record(RTy->getAsRecordDecl()) { - // Don't add bare keywords to the consumer since they will always fail - // validation by virtue of not being associated with any decls. - WantTypeSpecifiers = false; - WantExpressionKeywords = false; - WantCXXNamedCasts = false; - WantFunctionLikeCasts = false; - WantRemainingKeywords = false; - } - - bool ValidateCandidate(const TypoCorrection &candidate) override { - NamedDecl *ND = candidate.getCorrectionDecl(); - // Don't accept candidates that cannot be member functions, constants, - // variables, or templates. - if (!ND || !(isa(ND) || isa(ND))) - return false; - - // Accept candidates that occur in the current record. - if (Record->containsDecl(ND)) - return true; - - if (const auto *RD = dyn_cast(Record)) { - // Accept candidates that occur in any of the current class' base classes. - for (const auto &BS : RD->bases()) { - if (const auto *BSTy = BS.getType()->getAs()) { - if (BSTy->getDecl()->containsDecl(ND)) - return true; - } - } - } - - return false; - } - - std::unique_ptr clone() override { - return std::make_unique(*this); - } - -private: - const RecordDecl *const Record; -}; - -} - static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Expr *BaseExpr, QualType RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, - SourceLocation TemplateKWLoc, - TypoExpr *&TE) { + SourceLocation TemplateKWLoc) { SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); if (!RTy->isDependentType() && !SemaRef.isThisOutsideMemberFunctionBody(RTy) && @@ -735,56 +682,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, /*EnteringContext=*/false, TemplateKWLoc); SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); - - if (!R.empty() || R.wasNotFoundInCurrentInstantiation()) - return false; - - DeclarationName Typo = R.getLookupName(); - SourceLocation TypoLoc = R.getNameLoc(); - // Recompute the lookup context. - DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS) - : SemaRef.computeDeclContext(RTy); - - struct QueryState { - Sema &SemaRef; - DeclarationNameInfo NameInfo; - Sema::LookupNameKind LookupKind; - RedeclarationKind Redecl; - }; - QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(), - R.redeclarationKind()}; - RecordMemberExprValidatorCCC CCC(RTy); - TE = SemaRef.CorrectTypoDelayed( - R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, CCC, - [=, &SemaRef](const TypoCorrection &TC) { - if (TC) { - assert(!TC.isKeyword() && - "Got a keyword as a correction for a member!"); - bool DroppedSpecifier = - TC.WillReplaceSpecifier() && - Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts()); - SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) - << Typo << DC << DroppedSpecifier - << SS.getRange()); - } else { - SemaRef.Diag(TypoLoc, diag::err_no_member) - << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange); - } - }, - [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { - LookupResult R(Q.SemaRef, Q.NameInfo, Q.LookupKind, Q.Redecl); - R.clear(); // Ensure there's no decls lingering in the shared state. - R.suppressDiagnostics(); - R.setLookupName(TC.getCorrection()); - for (NamedDecl *ND : TC) - R.addDecl(ND); - R.resolveKind(); - return SemaRef.BuildMemberReferenceExpr( - BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(), - nullptr, R, nullptr, nullptr); - }, - CorrectTypoKind::ErrorRecovery, DC); - return false; } @@ -804,15 +701,11 @@ ExprResult Sema::BuildMemberReferenceExpr( // Implicit member accesses. if (!Base) { - TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->castAs()->getPointeeType(); if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow, - SS, TemplateArgs != nullptr, TemplateKWLoc, - TE)) + SS, TemplateArgs != nullptr, TemplateKWLoc)) return ExprError(); - if (TE) - return TE; // Explicit member accesses. } else { @@ -1341,6 +1234,29 @@ Sema::BuildMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, DeclarationNameInfo NameInfo(cast(ND)->getDeclName(), ND->getLocation()); + { + CXXRecordDecl *DerivedRecord = [](QualType QT) { + if (QualType PT = QT->getPointeeType(); !PT.isNull()) + QT = PT; + return QT->getAsCXXRecordDecl()->getCanonicalDecl(); + }(Base->getType()); + CXXRecordDecl *BaseRecord = [](NamedDecl *ND) { + DeclContext *DC = ND->getDeclContext(); + while (!isa(DC)) { + DC = DC->getParent(); + assert(DC); + } + return cast(DC)->getCanonicalDecl(); + }(ND); + if (BaseRecord != DerivedRecord && + !IsDerivedFrom(Base->getExprLoc(), DerivedRecord, BaseRecord)) { + Diag(Base->getExprLoc(), diag::err_class_not_derived_from_base) + << DerivedRecord << BaseRecord << SourceRange(Base->getBeginLoc(), + RHS->getEndLoc()); + return ExprError(); + } + } + LookupResult LR(*this, NameInfo, LookupMemberName); if (LR.empty()) LR.addDecl(ND); @@ -1500,16 +1416,15 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Handle field access to simple records. if (BaseType->getAsRecordDecl()) { - TypoExpr *TE = nullptr; if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, - SS, HasTemplateArgs, TemplateKWLoc, TE)) + SS, HasTemplateArgs, TemplateKWLoc)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that // the lookup result was filled in. If typo correction was attempted and // failed, the lookup result will have been cleared--that combined with the // valid-but-null ExprResult will trigger the appropriate diagnostics. - return ExprResult(TE); + return ExprResult{}; } else if (BaseType->isDependentType()) { R.setNotFoundInCurrentInstantiation(); return ExprEmpty(); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 3505d9f38d23..e0662d82914f 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -74,8 +74,7 @@ ExprResult SemaObjC::ParseObjCStringLiteral(SourceLocation *AtLocs, CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr, CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers()); S = StringLiteral::Create(Context, StrBuf, StringLiteralKind::Ordinary, - /*Pascal=*/false, StrTy, &StrLocs[0], - StrLocs.size()); + /*Pascal=*/false, StrTy, StrLocs); } return BuildObjCStringLiteral(AtLocs[0], S); @@ -4390,7 +4389,7 @@ SemaObjC::ARCConversionResult SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK, bool Diagnose, bool DiagnoseCFAudited, - BinaryOperatorKind Opc) { + BinaryOperatorKind Opc, bool IsReinterpretCast) { ASTContext &Context = getASTContext(); QualType castExprType = castExpr->getType(); @@ -4450,13 +4449,17 @@ SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType, // must be explicit. // Allow conversions between pointers to lifetime types and coreFoundation // pointers too, but only when the conversions are explicit. + // Allow conversions requested with a reinterpret_cast that converts an + // expression of type T* to type U*. if (exprACTC == ACTC_indirectRetainable && (castACTC == ACTC_voidPtr || - (castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK)))) + (castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK)) || + (IsReinterpretCast && effCastType->isAnyPointerType()))) return ACR_okay; if (castACTC == ACTC_indirectRetainable && - (exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) && - SemaRef.isCast(CCK)) + (((exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) && + SemaRef.isCast(CCK)) || + (IsReinterpretCast && castExprType->isAnyPointerType()))) return ACR_okay; switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 900652a9b298..75b9542c40c2 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -119,6 +120,40 @@ static ResourceClass getResourceClass(RegisterType RT) { llvm_unreachable("unexpected RegisterType value"); } +static Builtin::ID getSpecConstBuiltinId(QualType Type) { + const auto *BT = dyn_cast(Type); + if (!BT) { + if (!Type->isEnumeralType()) + return Builtin::NotBuiltin; + return Builtin::BI__builtin_get_spirv_spec_constant_int; + } + + switch (BT->getKind()) { + case BuiltinType::Bool: + return Builtin::BI__builtin_get_spirv_spec_constant_bool; + case BuiltinType::Short: + return Builtin::BI__builtin_get_spirv_spec_constant_short; + case BuiltinType::Int: + return Builtin::BI__builtin_get_spirv_spec_constant_int; + case BuiltinType::LongLong: + return Builtin::BI__builtin_get_spirv_spec_constant_longlong; + case BuiltinType::UShort: + return Builtin::BI__builtin_get_spirv_spec_constant_ushort; + case BuiltinType::UInt: + return Builtin::BI__builtin_get_spirv_spec_constant_uint; + case BuiltinType::ULongLong: + return Builtin::BI__builtin_get_spirv_spec_constant_ulonglong; + case BuiltinType::Half: + return Builtin::BI__builtin_get_spirv_spec_constant_half; + case BuiltinType::Float: + return Builtin::BI__builtin_get_spirv_spec_constant_float; + case BuiltinType::Double: + return Builtin::BI__builtin_get_spirv_spec_constant_double; + default: + return Builtin::NotBuiltin; + } +} + DeclBindingInfo *ResourceBindings::addDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass) { assert(getDeclBindingInfo(VD, ResClass) == nullptr && @@ -607,6 +642,41 @@ HLSLWaveSizeAttr *SemaHLSL::mergeWaveSizeAttr(Decl *D, return Result; } +HLSLVkConstantIdAttr * +SemaHLSL::mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, + int Id) { + + auto &TargetInfo = getASTContext().getTargetInfo(); + if (TargetInfo.getTriple().getArch() != llvm::Triple::spirv) { + Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; + return nullptr; + } + + auto *VD = cast(D); + + if (getSpecConstBuiltinId(VD->getType()) == Builtin::NotBuiltin) { + Diag(VD->getLocation(), diag::err_specialization_const); + return nullptr; + } + + if (!VD->getType().isConstQualified()) { + Diag(VD->getLocation(), diag::err_specialization_const); + return nullptr; + } + + if (HLSLVkConstantIdAttr *CI = D->getAttr()) { + if (CI->getId() != Id) { + Diag(CI->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; + Diag(AL.getLoc(), diag::note_conflicting_attribute); + } + return nullptr; + } + + HLSLVkConstantIdAttr *Result = + ::new (getASTContext()) HLSLVkConstantIdAttr(getASTContext(), AL, Id); + return Result; +} + HLSLShaderAttr * SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType) { @@ -978,6 +1048,159 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +std::pair +SemaHLSL::ActOnStartRootSignatureDecl(StringRef Signature) { + llvm::hash_code Hash = llvm::hash_value(Signature); + std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash); + IdentifierInfo *DeclIdent = &(getASTContext().Idents.get(IdStr)); + + // Check if we have already found a decl of the same name. + LookupResult R(SemaRef, DeclIdent, SourceLocation(), + Sema::LookupOrdinaryName); + bool Found = SemaRef.LookupQualifiedName(R, SemaRef.CurContext); + return {DeclIdent, Found}; +} + +void SemaHLSL::ActOnFinishRootSignatureDecl( + SourceLocation Loc, IdentifierInfo *DeclIdent, + SmallVector &Elements) { + + auto *SignatureDecl = HLSLRootSignatureDecl::Create( + SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc, + DeclIdent, Elements); + + if (handleRootSignatureDecl(SignatureDecl, Loc)) + return; + + SignatureDecl->setImplicit(); + SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); +} + +bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, + SourceLocation Loc) { + // The following conducts analysis on resource ranges to detect and report + // any overlaps in resource ranges. + // + // A resource range overlaps with another resource range if they have: + // - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) + // - equivalent resource space + // - overlapping visbility + // + // The following algorithm is implemented in the following steps: + // + // 1. Collect RangeInfo from relevant RootElements: + // - RangeInfo will retain the interval, ResourceClass, Space and Visibility + // 2. Sort the RangeInfo's such that they are grouped together by + // ResourceClass and Space (GroupT defined below) + // 3. Iterate through the collected RangeInfos by their groups + // - For each group we will have a ResourceRange for each visibility + // - As we iterate through we will: + // A: Insert the current RangeInfo into the corresponding Visibility + // ResourceRange + // B: Check for overlap with any overlapping Visibility ResourceRange + using RangeInfo = llvm::hlsl::rootsig::RangeInfo; + using ResourceRange = llvm::hlsl::rootsig::ResourceRange; + using GroupT = std::pair; + + // 1. Collect RangeInfos + llvm::SmallVector Infos; + for (const llvm::hlsl::rootsig::RootElement &Elem : D->getRootElements()) { + if (const auto *Descriptor = + std::get_if(&Elem)) { + RangeInfo Info; + Info.LowerBound = Descriptor->Reg.Number; + Info.UpperBound = Info.LowerBound; // use inclusive ranges [] + + Info.Class = + llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type)); + Info.Space = Descriptor->Space; + Info.Visibility = Descriptor->Visibility; + Infos.push_back(Info); + } + } + + // 2. Sort the RangeInfo's by their GroupT to form groupings + std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) { + return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space); + }); + + // 3. First we will init our state to track: + if (Infos.size() == 0) + return false; // No ranges to overlap + GroupT CurGroup = {Infos[0].Class, Infos[0].Space}; + bool HadOverlap = false; + + // Create a ResourceRange for each Visibility + ResourceRange::MapT::Allocator Allocator; + std::array Ranges = { + ResourceRange(Allocator), // All + ResourceRange(Allocator), // Vertex + ResourceRange(Allocator), // Hull + ResourceRange(Allocator), // Domain + ResourceRange(Allocator), // Geometry + ResourceRange(Allocator), // Pixel + ResourceRange(Allocator), // Amplification + ResourceRange(Allocator), // Mesh + }; + + // Reset the ResourceRanges for when we iterate through a new group + auto ClearRanges = [&Ranges]() { + for (ResourceRange &Range : Ranges) + Range.clear(); + }; + + // Helper to report diagnostics + auto ReportOverlap = [this, Loc, &HadOverlap](const RangeInfo *Info, + const RangeInfo *OInfo) { + HadOverlap = true; + auto CommonVis = + Info->Visibility == llvm::hlsl::rootsig::ShaderVisibility::All + ? OInfo->Visibility + : Info->Visibility; + this->Diag(Loc, diag::err_hlsl_resource_range_overlap) + << llvm::to_underlying(Info->Class) << Info->LowerBound + << Info->UpperBound << llvm::to_underlying(OInfo->Class) + << OInfo->LowerBound << OInfo->UpperBound << Info->Space << CommonVis; + }; + + // 3: Iterate through collected RangeInfos + for (const RangeInfo &Info : Infos) { + GroupT InfoGroup = {Info.Class, Info.Space}; + // Reset our ResourceRanges when we enter a new group + if (CurGroup != InfoGroup) { + ClearRanges(); + CurGroup = InfoGroup; + } + + // 3A: Insert range info into corresponding Visibility ResourceRange + ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Visibility)]; + if (std::optional Overlapping = VisRange.insert(Info)) + ReportOverlap(&Info, Overlapping.value()); + + // 3B: Check for overlap in all overlapping Visibility ResourceRanges + // + // If the range that we are inserting has ShaderVisiblity::All it needs to + // check for an overlap in all other visibility types as well. + // Otherwise, the range that is inserted needs to check that it does not + // overlap with ShaderVisibility::All. + // + // OverlapRanges will be an ArrayRef to all non-all visibility + // ResourceRanges in the former case and it will be an ArrayRef to just the + // all visiblity ResourceRange in the latter case. + ArrayRef OverlapRanges = + Info.Visibility == llvm::hlsl::rootsig::ShaderVisibility::All + ? ArrayRef{Ranges}.drop_front() + : ArrayRef{Ranges}.take_front(); + + for (const ResourceRange &Range : OverlapRanges) + if (std::optional Overlapping = + Range.getOverlapping(Info)) + ReportOverlap(&Info, Overlapping.value()); + } + + return HadOverlap; +} + void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() != 1) { Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -999,7 +1222,6 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { if (SemaRef.LookupQualifiedName(R, D->getDeclContext())) if (auto *SignatureDecl = dyn_cast(R.getFoundDecl())) { - // Perform validation of constructs here D->addAttr(::new (getASTContext()) RootSignatureAttr( getASTContext(), AL, Ident, SignatureDecl)); } @@ -1008,12 +1230,15 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); + bool IsDXIL = getASTContext().getTargetInfo().getTriple().getArch() == + llvm::Triple::dxil; + uint32_t ZMax = 1024; uint32_t ThreadMax = 1024; - if (SMVersion.getMajor() <= 4) { + if (IsDXIL && SMVersion.getMajor() <= 4) { ZMax = 1; ThreadMax = 768; - } else if (SMVersion.getMajor() == 5) { + } else if (IsDXIL && SMVersion.getMajor() == 5) { ZMax = 64; ThreadMax = 1024; } @@ -1132,6 +1357,15 @@ void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) { HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID)); } +void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) { + uint32_t Id; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id)) + return; + HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id); + if (NewAttr) + D->addAttr(NewAttr); +} + bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) { const auto *VT = T->getAs(); @@ -2206,8 +2440,9 @@ static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType) { auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); if (VecTyA) - ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), - VectorKind::Generic); + ReturnType = + S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements()); + TheCall->setType(ReturnType); } @@ -2520,8 +2755,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (auto *VecTy = EltTy->getAs()) { EltTy = VecTy->getElementType(); - ResTy = SemaRef.Context.getVectorType(ResTy, VecTy->getNumElements(), - VecTy->getVectorKind()); + ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements()); } if (!EltTy->isIntegerType()) { @@ -3181,6 +3415,7 @@ static bool IsDefaultBufferConstantDecl(VarDecl *VD) { return VD->getDeclContext()->isTranslationUnit() && QT.getAddressSpace() == LangAS::Default && VD->getStorageClass() != SC_Static && + !VD->hasAttr() && !isInvalidConstantBufferLeafElementType(QT.getTypePtr()); } @@ -3248,7 +3483,8 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { const Type *VarType = VD->getType().getTypePtr(); while (VarType->isArrayType()) VarType = VarType->getArrayElementTypeNoTypeQual(); - if (VarType->isHLSLResourceRecord()) { + if (VarType->isHLSLResourceRecord() || + VD->hasAttr()) { // Make the variable for resources static. The global externally visible // storage is accessed through the handle, which is a member. The variable // itself is not externally visible. @@ -3671,3 +3907,41 @@ bool SemaHLSL::transformInitList(const InitializedEntity &Entity, Init->updateInit(Ctx, I, NewInit->getInit(I)); return true; } + +bool SemaHLSL::handleInitialization(VarDecl *VDecl, Expr *&Init) { + const HLSLVkConstantIdAttr *ConstIdAttr = + VDecl->getAttr(); + if (!ConstIdAttr) + return true; + + ASTContext &Context = SemaRef.getASTContext(); + + APValue InitValue; + if (!Init->isCXX11ConstantExpr(Context, &InitValue)) { + Diag(VDecl->getLocation(), diag::err_specialization_const); + VDecl->setInvalidDecl(); + return false; + } + + Builtin::ID BID = getSpecConstBuiltinId(VDecl->getType()); + + // Argument 1: The ID from the attribute + int ConstantID = ConstIdAttr->getId(); + llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID); + Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy, + ConstIdAttr->getLocation()); + + SmallVector Args = {IdExpr, Init}; + Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args); + if (C->getType()->getCanonicalTypeUnqualified() != + VDecl->getType()->getCanonicalTypeUnqualified()) { + C = SemaRef + .BuildCStyleCastExpr(SourceLocation(), + Context.getTrivialTypeSourceInfo( + Init->getType(), Init->getExprLoc()), + SourceLocation(), C) + .get(); + } + Init = C; + return true; +} diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 0d6d44140c3d..0c1cd4f7498e 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1578,6 +1578,21 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND) { if (auto *TD = dyn_cast(ND)) for (auto *Param : *TD->getTemplateParameters()) makeMergedDefinitionVisible(Param); + + // If we import a named module which contains a header, and then we include a + // header which contains a definition of enums, we will skip parsing the enums + // in the current TU. But we need to ensure the visibility of the enum + // contants, since they are able to be found with the parents of their + // parents. + if (auto *ED = dyn_cast(ND); + ED && ED->isFromGlobalModule() && !ED->isScoped()) { + for (auto *ECD : ED->enumerators()) { + ECD->setVisibleDespiteOwningModule(); + DeclContext *RedeclCtx = ED->getDeclContext()->getRedeclContext(); + if (RedeclCtx->lookup(ECD->getDeclName()).empty()) + RedeclCtx->makeDeclVisibleInContext(ECD); + } + } } /// Find the module in which the given declaration was defined. @@ -1991,6 +2006,8 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { if (D->isModulePrivate()) return false; + Module *DeclTopModule = DeclModule->getTopLevelModule(); + // [module.reach]/p1 // A translation unit U is necessarily reachable from a point P if U is a // module interface unit on which the translation unit containing P has an @@ -2009,17 +2026,28 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { // // Here we only check for the first condition. Since we couldn't see // DeclModule if it isn't (transitively) imported. - if (DeclModule->getTopLevelModule()->isModuleInterfaceUnit()) + if (DeclTopModule->isModuleInterfaceUnit()) return true; - // [module.reach]/p2 + // [module.reach]/p1,2 + // A translation unit U is necessarily reachable from a point P if U is a + // module interface unit on which the translation unit containing P has an + // interface dependency, or the translation unit containing P imports U, in + // either case prior to P + // // Additional translation units on // which the point within the program has an interface dependency may be // considered reachable, but it is unspecified which are and under what // circumstances. - // - // The decision here is to treat all additional tranditional units as - // unreachable. + Module *CurrentM = SemaRef.getCurrentModule(); + + // Directly imported module are necessarily reachable. + // Since we can't export import a module implementation partition unit, we + // don't need to count for Exports here. + if (CurrentM && CurrentM->getTopLevelModule()->Imports.count(DeclTopModule)) + return true; + + // Then we treat all module implementation partition unit as unreachable. return false; } @@ -2185,22 +2213,10 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) { // Class and enumeration member names can be found by name lookup in any // context in which a definition of the type is reachable. // - // FIXME: The current implementation didn't consider about scope. For example, - // ``` - // // m.cppm - // export module m; - // enum E1 { e1 }; - // // Use.cpp - // import m; - // void test() { - // auto a = E1::e1; // Error as expected. - // auto b = e1; // Should be error. namespace-scope name e1 is not visible - // } - // ``` - // For the above example, the current implementation would emit error for `a` - // correctly. However, the implementation wouldn't diagnose about `b` now. - // Since we only check the reachability for the parent only. - // See clang/test/CXX/module/module.interface/p7.cpp for example. + // NOTE: The above wording may be problematic. See + // https://github.com/llvm/llvm-project/issues/131058 But it is much complext + // to adjust it in Sema's lookup process. Now we hacked it in ASTWriter. See + // the comments in ASTDeclContextNameLookupTrait::getLookupVisibility. if (auto *TD = dyn_cast(DC)) return SemaRef.hasReachableDefinition(TD); @@ -5453,40 +5469,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure && !SecondBestTC); } -TypoExpr *Sema::CorrectTypoDelayed( - const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, - TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, - DeclContext *MemberContext, bool EnteringContext, - const ObjCObjectPointerType *OPT) { - auto Consumer = makeTypoCorrectionConsumer( - TypoName, LookupKind, S, SS, CCC, MemberContext, EnteringContext, OPT, - Mode == CorrectTypoKind::ErrorRecovery); - - // Give the external sema source a chance to correct the typo. - TypoCorrection ExternalTypo; - if (ExternalSource && Consumer) { - ExternalTypo = ExternalSource->CorrectTypo( - TypoName, LookupKind, S, SS, *Consumer->getCorrectionValidator(), - MemberContext, EnteringContext, OPT); - if (ExternalTypo) - Consumer->addCorrection(ExternalTypo); - } - - if (!Consumer || Consumer->empty()) - return nullptr; - - // Make sure the best edit distance (prior to adding any namespace qualifiers) - // is not more that about a third of the length of the typo's identifier. - unsigned ED = Consumer->getBestEditDistance(true); - IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); - if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) - return nullptr; - ExprEvalContexts.back().NumTypos++; - return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC), - TypoName.getLoc()); -} - void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { if (!CDecl) return; @@ -5811,32 +5793,6 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, Diag(Correction.getCorrectionRange().getBegin(), PD); } -TypoExpr *Sema::createDelayedTypo(std::unique_ptr TCC, - TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC, - SourceLocation TypoLoc) { - assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); - auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc); - auto &State = DelayedTypos[TE]; - State.Consumer = std::move(TCC); - State.DiagHandler = std::move(TDG); - State.RecoveryHandler = std::move(TRC); - if (TE) - TypoExprs.push_back(TE); - return TE; -} - -const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const { - auto Entry = DelayedTypos.find(TE); - assert(Entry != DelayedTypos.end() && - "Failed to get the state for a TypoExpr!"); - return Entry->second; -} - -void Sema::clearDelayedTypo(TypoExpr *TE) { - DelayedTypos.erase(TE); -} - void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) { DeclarationNameInfo Name(II, IILoc); LookupResult R(*this, Name, LookupAnyName, diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 6c4df0aa35af..fe70ce3fba6a 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -136,6 +136,7 @@ makeTransitiveImportsVisible(ASTContext &Ctx, VisibleModuleSet &VisibleModules, "modules only."); llvm::SmallVector Worklist; + llvm::SmallSet Visited; Worklist.push_back(Imported); Module *FoundPrimaryModuleInterface = @@ -144,18 +145,22 @@ makeTransitiveImportsVisible(ASTContext &Ctx, VisibleModuleSet &VisibleModules, while (!Worklist.empty()) { Module *Importing = Worklist.pop_back_val(); - if (VisibleModules.isVisible(Importing)) + if (Visited.count(Importing)) continue; + Visited.insert(Importing); // FIXME: The ImportLoc here is not meaningful. It may be problematic if we // use the sourcelocation loaded from the visible modules. VisibleModules.setVisible(Importing, ImportLoc); if (isImportingModuleUnitFromSameModule(Ctx, Importing, CurrentModule, - FoundPrimaryModuleInterface)) + FoundPrimaryModuleInterface)) { for (Module *TransImported : Importing->Imports) - if (!VisibleModules.isVisible(TransImported)) - Worklist.push_back(TransImported); + Worklist.push_back(TransImported); + + for (auto [Exports, _] : Importing->Exports) + Worklist.push_back(Exports); + } } } @@ -258,11 +263,11 @@ static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II, Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, - ModuleIdPath Partition, ModuleImportState &ImportState) { + ModuleIdPath Partition, ModuleImportState &ImportState, + bool IntroducerIsFirstPPToken) { assert(getLangOpts().CPlusPlusModules && "should only have module decl in standard C++ modules"); - bool IsFirstDecl = ImportState == ModuleImportState::FirstDecl; bool SeenGMF = ImportState == ModuleImportState::GlobalFragment; // If any of the steps here fail, we count that as invalidating C++20 // module state; @@ -328,14 +333,11 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, SeenGMF == (bool)this->TheGlobalModuleFragment) && "mismatched global module state"); - // In C++20, the module-declaration must be the first declaration if there - // is no global module fragment. - if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !SeenGMF) { + // In C++20, A module directive may only appear as the first preprocessing + // tokens in a file (excluding the global module fragment.). + if (getLangOpts().CPlusPlusModules && !IntroducerIsFirstPPToken && !SeenGMF) { Diag(ModuleLoc, diag::err_module_decl_not_at_start); - SourceLocation BeginLoc = - ModuleScopes.empty() - ? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) - : ModuleScopes.back().BeginLoc; + SourceLocation BeginLoc = PP.getMainFileFirstPPToken().getLocation(); if (BeginLoc.isValid()) { Diag(BeginLoc, diag::note_global_module_introducer_missing) << FixItHint::CreateInsertion(BeginLoc, "module;\n"); @@ -712,7 +714,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, Mod->Kind == Module::ModuleKind::ModulePartitionImplementation) { Diag(ExportLoc, diag::err_export_partition_impl) << SourceRange(ExportLoc, Path.back().getLoc()); - } else if (!ModuleScopes.empty() && !currentModuleIsImplementation()) { + } else if (ExportLoc.isValid() && + (ModuleScopes.empty() || currentModuleIsImplementation())) { + // [module.interface]p1: + // An export-declaration shall inhabit a namespace scope and appear in the + // purview of a module interface unit. + Diag(ExportLoc, diag::err_export_not_in_module_interface); + } else if (!ModuleScopes.empty()) { // Re-export the module if the imported module is exported. // Note that we don't need to add re-exported module to Imports field // since `Exports` implies the module is imported already. @@ -720,11 +728,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, getCurrentModule()->Exports.emplace_back(Mod, false); else getCurrentModule()->Imports.insert(Mod); - } else if (ExportLoc.isValid()) { - // [module.interface]p1: - // An export-declaration shall inhabit a namespace scope and appear in the - // purview of a module interface unit. - Diag(ExportLoc, diag::err_export_not_in_module_interface); } return Import; diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index 56815cd2731a..0f39a9817ce7 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -124,17 +124,12 @@ ExprResult SemaObjC::CheckObjCForCollectionOperand(SourceLocation forLoc, if (!collection) return ExprError(); - ExprResult result = SemaRef.CorrectDelayedTyposInExpr(collection); - if (!result.isUsable()) - return ExprError(); - collection = result.get(); - // Bail out early if we've got a type-dependent expression. if (collection->isTypeDependent()) return collection; // Perform normal l-value conversion. - result = SemaRef.DefaultFunctionArrayLvalueConversion(collection); + ExprResult result = SemaRef.DefaultFunctionArrayLvalueConversion(collection); if (result.isInvalid()) return ExprError(); collection = result.get(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index a3395ac157d9..00f465818080 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7122,6 +7122,7 @@ void SemaOpenMP::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( getASTContext(), VariantFuncRef, DVScope.TI, /*NothingArgs=*/nullptr, /*NothingArgsSize=*/0, /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0, + /*NeedDeviceAddrArgs=*/nullptr, /*NeedDeviceAddrArgsSize=*/0, /*AppendArgs=*/nullptr, /*AppendArgsSize=*/0); for (FunctionDecl *BaseFD : Bases) BaseFD->addAttr(OMPDeclareVariantA); @@ -7553,6 +7554,7 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef AdjustArgsNothing, ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AdjustArgsNeedDeviceAddr, ArrayRef AppendArgs, SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, SourceRange SR) { @@ -7564,6 +7566,7 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( SmallVector AllAdjustArgs; llvm::append_range(AllAdjustArgs, AdjustArgsNothing); llvm::append_range(AllAdjustArgs, AdjustArgsNeedDevicePtr); + llvm::append_range(AllAdjustArgs, AdjustArgsNeedDeviceAddr); if (!AllAdjustArgs.empty() || !AppendArgs.empty()) { VariantMatchInfo VMI; @@ -7614,6 +7617,8 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( const_cast(AdjustArgsNothing.data()), AdjustArgsNothing.size(), const_cast(AdjustArgsNeedDevicePtr.data()), AdjustArgsNeedDevicePtr.size(), + const_cast(AdjustArgsNeedDeviceAddr.data()), + AdjustArgsNeedDeviceAddr.size(), const_cast(AppendArgs.data()), AppendArgs.size(), SR); FD->addAttr(NewAttr); } @@ -15135,7 +15140,7 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt, // instantiated. if (SemaRef.CurContext->isDependentContext()) return OMPReverseDirective::Create(Context, StartLoc, EndLoc, AStmt, - nullptr, nullptr); + NumLoops, nullptr, nullptr); assert(LoopHelpers.size() == NumLoops && "Expecting a single-dimensional loop iteration space"); @@ -15294,7 +15299,7 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt, ForStmt(Context, Init.get(), Cond.get(), nullptr, Incr.get(), ReversedBody, LoopHelper.Init->getBeginLoc(), LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc()); - return OMPReverseDirective::Create(Context, StartLoc, EndLoc, AStmt, + return OMPReverseDirective::Create(Context, StartLoc, EndLoc, AStmt, NumLoops, ReversedFor, buildPreInits(Context, PreInits)); } @@ -22057,20 +22062,34 @@ static void checkMappableExpressionList( Type.getCanonicalType(), UnresolvedMapper); if (ER.isInvalid()) continue; - if (!ER.get() && isa(VE)) { - // Create implicit mapper as needed. - QualType BaseType = VE->getType().getCanonicalType(); - if (BaseType->isSpecificBuiltinType(BuiltinType::ArraySection)) { - const auto *OASE = cast(VE->IgnoreParenImpCasts()); - QualType BType = ArraySectionExpr::getBaseOriginalType(OASE->getBase()); - QualType ElemType; - if (const auto *ATy = BType->getAsArrayTypeUnsafe()) - ElemType = ATy->getElementType(); - else - ElemType = BType->getPointeeType(); + + // If no user-defined mapper is found, we need to create an implicit one for + // arrays/array-sections on structs that have members that have + // user-defined mappers. This is needed to ensure that the mapper for the + // member is invoked when mapping each element of the array/array-section. + if (!ER.get()) { + QualType BaseType; + + if (isa(VE)) { + BaseType = VE->getType().getCanonicalType(); + if (BaseType->isSpecificBuiltinType(BuiltinType::ArraySection)) { + const auto *OASE = cast(VE->IgnoreParenImpCasts()); + QualType BType = + ArraySectionExpr::getBaseOriginalType(OASE->getBase()); + QualType ElemType; + if (const auto *ATy = BType->getAsArrayTypeUnsafe()) + ElemType = ATy->getElementType(); + else + ElemType = BType->getPointeeType(); + BaseType = ElemType.getCanonicalType(); + } + } else if (VE->getType()->isArrayType()) { + const ArrayType *AT = VE->getType()->getAsArrayTypeUnsafe(); + const QualType ElemType = AT->getElementType(); BaseType = ElemType.getCanonicalType(); } - if (BaseType->getAsRecordDecl() && + + if (!BaseType.isNull() && BaseType->getAsRecordDecl() && isImplicitMapperNeeded(SemaRef, DSAS, BaseType, VE)) { ER = buildImplicitMapper(SemaRef, BaseType, DSAS); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 2b0585905fd5..ce9e62d53131 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -9282,11 +9282,10 @@ class BuiltinOperatorOverloadBuilder { /// the candidates into a unique set, then move from that set into the list /// of arithmetic types. llvm::SmallSetVector BitIntCandidates; - llvm::for_each(CandidateTypes, [&BitIntCandidates]( - BuiltinCandidateTypeSet &Candidate) { + for (BuiltinCandidateTypeSet &Candidate : CandidateTypes) { for (QualType BitTy : Candidate.bitint_types()) BitIntCandidates.insert(CanQualType::CreateUnsafe(BitTy)); - }); + } llvm::move(BitIntCandidates, std::back_inserter(ArithmeticTypes)); LastPromotedIntegralType = ArithmeticTypes.size(); LastPromotedArithmeticType = ArithmeticTypes.size(); @@ -11340,9 +11339,9 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, iterator &Best) { - assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) || - DeferredCandidatesCount == 0 && - "Unexpected deferred template candidates"); + assert((shouldDeferTemplateArgumentDeduction(S.getLangOpts()) || + DeferredCandidatesCount == 0) && + "Unexpected deferred template candidates"); bool TwoPhaseResolution = DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled; @@ -14074,8 +14073,10 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization( // specified and it, along with any default template arguments, // identifies a single function template specialization, then the // template-id is an lvalue for the function template specialization. - FunctionTemplateDecl *FunctionTemplate - = cast((*I)->getUnderlyingDecl()); + FunctionTemplateDecl *FunctionTemplate = + dyn_cast((*I)->getUnderlyingDecl()); + if (!FunctionTemplate) + continue; // C++ [over.over]p2: // If the name is a function template, template argument deduction is diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 9f70be746eb3..9eab0c2a0df6 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -47,7 +47,7 @@ struct RVVIntrinsicDef { std::string BuiltinName; /// Mapping to RequiredFeatures in riscv_vector.td - std::string RequiredExtensions; + StringRef RequiredExtensions; /// Function signature, first element is return type. RVVTypes Signature; diff --git a/clang/lib/Sema/SemaReflect.cpp b/clang/lib/Sema/SemaReflect.cpp index 7f0a31c14fb0..07324d30240f 100644 --- a/clang/lib/Sema/SemaReflect.cpp +++ b/clang/lib/Sema/SemaReflect.cpp @@ -659,16 +659,13 @@ public: ParsedAttr::Form Form(tok::kw_alignas); SourceRange Range(DefinitionLoc, DefinitionLoc); - MemberAttrs.addAtEnd(AttrPool.create(&II, Range, nullptr, - SourceLocation{}, nullptr, 0, - Form)); + MemberAttrs.addAtEnd(AttrPool.create(&II, Range, {}, nullptr, 0, Form)); } if (MemberSpec->NoUniqueAddress) { IdentifierInfo &II = S.Context.Idents.get("no_unique_address"); SourceRange Range(DefinitionLoc, DefinitionLoc); - MemberAttrs.addAtEnd(AttrPool.create(&II, Range, nullptr, - SourceLocation{}, nullptr, 0, + MemberAttrs.addAtEnd(AttrPool.create(&II, Range, {}, nullptr, 0, ParsedAttr::Form::CXX11())); } @@ -785,8 +782,8 @@ public: SourceRange Range(DefinitionLoc, DefinitionLoc); IdentifierInfo &II = S.Context.Idents.get("__annotation_placeholder"); AttributeCommonInfo *ACI = ParsedAttrs.addNew( - &II, Range, nullptr, DefinitionLoc, nullptr, 0, - ParsedAttr::Form::Annotation()); + &II, Range, {}, nullptr, 0, + ParsedAttr::Form::Annotation(), DefinitionLoc); Annot = CXX26AnnotationAttr::Create(S.Context, CE, *ACI); Annot->setValue(Value.getReflectedValue()); @@ -804,8 +801,8 @@ public: SourceRange Range(Loc, Loc); IdentifierInfo &II = S.Context.Idents.get("__annotation_placeholder"); - return ParsedAttrs.addNew(&II, Range, nullptr, Loc, nullptr, 0, - ParsedAttr::Form::Annotation()); + return ParsedAttrs.addNew(&II, Range, {}, nullptr, 0, + ParsedAttr::Form::Annotation(), Loc); } }; } // anonymous namespace diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index c18d1bcacd5f..3fc5335cbf5e 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -535,12 +535,7 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) { return ER; }; - ExprResult Converted = CorrectDelayedTyposInExpr( - Val, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, - CheckAndFinish); - if (Converted.get() == Val.get()) - Converted = CheckAndFinish(Val.get()); - return Converted; + return CheckAndFinish(Val.get()); } StmtResult @@ -2344,7 +2339,7 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, SourceLocation Loc, int DiagID) { if (Decl->getType()->isUndeducedType()) { - ExprResult Res = SemaRef.CorrectDelayedTyposInExpr(Init); + ExprResult Res = Init; if (!Res.isUsable()) { Decl->setInvalidDecl(); return true; @@ -3845,13 +3840,9 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope) { - // Correct typos, in case the containing function returns 'auto' and - // RetValExp should determine the deduced type. - ExprResult RetVal = CorrectDelayedTyposInExpr( - RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true); - if (RetVal.isInvalid()) { + ExprResult RetVal = RetValExp; + if (RetVal.isInvalid()) return StmtError(); - } if (getCurScope()->isInOpenACCComputeConstructScope()) return StmtError( diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 17da5fd8325b..857d46af9ada 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -672,12 +672,14 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { - S.Diag(A.getLoc(), A.isRegularKeywordAttribute() - ? (unsigned)diag::err_keyword_not_supported_on_target - : A.isDeclspecAttribute() - ? (unsigned)diag::warn_unhandled_ms_attribute_ignored - : (unsigned)diag::warn_unknown_attribute_ignored) - << A << A.getRange(); + if (A.isRegularKeywordAttribute() || A.isDeclspecAttribute()) { + S.Diag(A.getLoc(), A.isRegularKeywordAttribute() + ? diag::err_keyword_not_supported_on_target + : diag::warn_unhandled_ms_attribute_ignored) + << A << A.getRange(); + } else { + S.DiagnoseUnknownAttribute(A); + } return nullptr; } @@ -782,11 +784,10 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A, ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption, const IdentifierInfo *AttrName, SourceRange Range) { - ExprResult Res = CorrectDelayedTyposInExpr(Assumption); - if (Res.isInvalid()) + if (!Assumption) return ExprError(); - Res = CheckPlaceholderExpr(Res.get()); + ExprResult Res = CheckPlaceholderExpr(Assumption); if (Res.isInvalid()) return ExprError(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 477bcea36113..0d2f8ae11643 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -527,6 +527,7 @@ static void instantiateOMPDeclareVariantAttr( SmallVector NothingExprs; SmallVector NeedDevicePtrExprs; + SmallVector NeedDeviceAddrExprs; SmallVector AppendArgs; for (Expr *E : Attr.adjustArgsNothing()) { @@ -541,14 +542,20 @@ static void instantiateOMPDeclareVariantAttr( continue; NeedDevicePtrExprs.push_back(ER.get()); } + for (Expr *E : Attr.adjustArgsNeedDeviceAddr()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NeedDeviceAddrExprs.push_back(ER.get()); + } for (OMPInteropInfo &II : Attr.appendArgs()) { // When prefer_type is implemented for append_args handle them here too. AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync); } S.OpenMP().ActOnOpenMPDeclareVariantDirective( - FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(), - SourceLocation(), Attr.getRange()); + FD, E, TI, NothingExprs, NeedDevicePtrExprs, NeedDeviceAddrExprs, + AppendArgs, SourceLocation(), SourceLocation(), Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 8bfbcc68c0fe..796f0e4e3994 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -763,7 +763,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, if (!Pattern->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << Pattern->getSourceRange(); - CorrectDelayedTyposInExpr(Pattern); return ExprError(); } @@ -1227,11 +1226,9 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression, SourceLocation RSquareLoc) { bool isParameterPack = ::isParameterPack(PackExpression); if (!isParameterPack) { - if (!PackExpression->containsErrors()) { - CorrectDelayedTyposInExpr(IndexExpr); + if (!PackExpression->containsErrors()) Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack) << PackExpression; - } return ExprError(); } ExprResult Res = @@ -1429,11 +1426,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, CheckFoldOperand(*this, LHS); CheckFoldOperand(*this, RHS); - auto DiscardOperands = [&] { - CorrectDelayedTyposInExpr(LHS); - CorrectDelayedTyposInExpr(RHS); - }; - // [expr.prim.fold]p3: // In a binary fold, op1 and op2 shall be the same fold-operator, and // either e1 shall contain an unexpanded parameter pack or e2 shall contain @@ -1441,7 +1433,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, if (LHS && RHS && LHS->containsUnexpandedParameterPack() == RHS->containsUnexpandedParameterPack()) { - DiscardOperands(); return Diag(EllipsisLoc, LHS->containsUnexpandedParameterPack() ? diag::err_fold_expression_packs_both_sides @@ -1456,7 +1447,6 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, Expr *Pack = LHS ? LHS : RHS; assert(Pack && "fold expression with neither LHS nor RHS"); if (!Pack->containsUnexpandedParameterPack()) { - DiscardOperands(); return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << Pack->getSourceRange(); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 93fa14bd95f6..ec37c1a031f5 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4580,7 +4580,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, false /*IsRegularKeywordAttribute*/); ParsedAttr *nullabilityAttr = Pool.create( S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), - nullptr, SourceLocation(), nullptr, 0, form); + AttributeScopeInfo(), nullptr, 0, form); attrs.addAtEnd(nullabilityAttr); @@ -5765,10 +5765,10 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, // If there wasn't one, add one (with an invalid source location // so that we don't make an AttributedType for it). - ParsedAttr *attr = D.getAttributePool().create( - &S.Context.Idents.get("objc_ownership"), SourceLocation(), - /*scope*/ nullptr, SourceLocation(), - /*args*/ &Args, 1, ParsedAttr::Form::GNU()); + ParsedAttr *attr = + D.getAttributePool().create(&S.Context.Idents.get("objc_ownership"), + SourceLocation(), AttributeScopeInfo(), + /*args*/ &Args, 1, ParsedAttr::Form::GNU()); chunk.getAttrs().addAtEnd(attr); // TODO: mark whether we did this inference? } diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 65cc1bf74424..b30b90581224 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -188,6 +188,7 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef, return false; } + bool IsUnion = D->isUnion(); for (const FieldDecl *Field : D->fields()) { if (Field->getType()->isDependentType()) continue; @@ -197,6 +198,12 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef, // of a trivially relocatable type if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType())) return false; + + // A union contains values with address discriminated pointer auth + // cannot be relocated. + if (IsUnion && SemaRef.Context.containsAddressDiscriminatedPointerAuth( + Field->getType())) + return false; } return !D->hasDeletedDestructor(); } @@ -313,7 +320,6 @@ bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) { } bool Sema::IsCXXTriviallyRelocatableType(QualType Type) { - QualType BaseElementType = getASTContext().getBaseElementType(Type); if (Type->isVariableArrayType()) @@ -322,10 +328,10 @@ bool Sema::IsCXXTriviallyRelocatableType(QualType Type) { if (BaseElementType.hasNonTrivialObjCLifetime()) return false; - if (BaseElementType.hasAddressDiscriminatedPointerAuth()) + if (BaseElementType->isIncompleteType()) return false; - if (BaseElementType->isIncompleteType()) + if (Context.containsNonRelocatablePointerAuth(Type)) return false; if (BaseElementType->isScalarType() || BaseElementType->isVectorType()) @@ -674,7 +680,10 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) { if (!BaseElementType->isObjectType()) return false; - if (T.hasAddressDiscriminatedPointerAuth()) + // The deprecated __builtin_is_trivially_relocatable does not have + // an equivalent to __builtin_trivially_relocate, so there is no + // safe way to use it if there are any address discriminated values. + if (SemaRef.getASTContext().containsAddressDiscriminatedPointerAuth(T)) return false; if (const auto *RD = BaseElementType->getAsCXXRecordDecl(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index f16400c3c441..e6099f64ce04 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13744,12 +13744,6 @@ TreeTransform::TransformOpaqueValueExpr(OpaqueValueExpr *E) { return E; } -template -ExprResult -TreeTransform::TransformTypoExpr(TypoExpr *E) { - return E; -} - template ExprResult TreeTransform::TransformRecoveryExpr(RecoveryExpr *E) { llvm::SmallVector Children; @@ -16876,7 +16870,7 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { return getDerived().RebuildSizeOfPackExpr( E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), /*Length=*/static_cast(Args.size()), - /*PartialArgs=*/std::nullopt); + /*PartialArgs=*/{}); } template diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 5d33933abe5f..c7293510abb4 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4097,8 +4097,8 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, uint64_t TULocalOffset = TULocalLocalOffset ? BaseOffset + TULocalLocalOffset : 0; - DelayedNamespaceOffsetMap[ID] = {LexicalOffset, VisibleOffset, - ModuleLocalOffset, TULocalOffset}; + DelayedNamespaceOffsetMap[ID] = { + {VisibleOffset, TULocalOffset, ModuleLocalOffset}, LexicalOffset}; assert(!GetExistingDecl(ID) && "We shouldn't load the namespace in the front of delayed " @@ -8565,17 +8565,21 @@ bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, SmallVector Decls; llvm::SmallPtrSet Found; + auto Find = [&, this](auto &&Table, auto &&Key) { + for (GlobalDeclID ID : Table.find(Key)) { + NamedDecl *ND = cast(GetDecl(ID)); + if (ND->getDeclName() == Name && Found.insert(ND).second) + Decls.push_back(ND); + } + }; + Deserializing LookupResults(this); // FIXME: Clear the redundancy with templated lambda in C++20 when that's // available. if (auto It = Lookups.find(DC); It != Lookups.end()) { ++NumVisibleDeclContextsRead; - for (GlobalDeclID ID : It->second.Table.find(Name)) { - NamedDecl *ND = cast(GetDecl(ID)); - if (ND->getDeclName() == Name && Found.insert(ND).second) - Decls.push_back(ND); - } + Find(It->second.Table, Name); } if (auto *NamedModule = @@ -8583,21 +8587,13 @@ bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, : nullptr) { if (auto It = ModuleLocalLookups.find(DC); It != ModuleLocalLookups.end()) { ++NumModuleLocalVisibleDeclContexts; - for (GlobalDeclID ID : It->second.Table.find({Name, NamedModule})) { - NamedDecl *ND = cast(GetDecl(ID)); - if (ND->getDeclName() == Name && Found.insert(ND).second) - Decls.push_back(ND); - } + Find(It->second.Table, std::make_pair(Name, NamedModule)); } } if (auto It = TULocalLookups.find(DC); It != TULocalLookups.end()) { ++NumTULocalVisibleDeclContexts; - for (GlobalDeclID ID : It->second.Table.find(Name)) { - NamedDecl *ND = cast(GetDecl(ID)); - if (ND->getDeclName() == Name && Found.insert(ND).second) - Decls.push_back(ND); - } + Find(It->second.Table, Name); } SetExternalVisibleDeclsForName(DC, Name, Decls); @@ -9747,6 +9743,10 @@ bool ASTReader::wasThisDeclarationADefinition(const FunctionDecl *FD) { return ThisDeclarationWasADefinitionSet.contains(FD); } +bool ASTReader::hasInitializerWithSideEffects(const VarDecl *VD) const { + return InitSideEffectVars.count(VD); +} + Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 47248f5a5ed4..415369b63072 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -416,9 +416,7 @@ public: void VisitOpenACCDeclareDecl(OpenACCDeclareDecl *D); void VisitOpenACCRoutineDecl(OpenACCRoutineDecl *D); - void VisitDeclContext(DeclContext *DC, uint64_t &LexicalOffset, - uint64_t &VisibleOffset, uint64_t &ModuleLocalOffset, - uint64_t &TULocalOffset); + void VisitDeclContext(DeclContext *DC, LookupBlockOffsets &Offsets); template RedeclarableResult VisitRedeclarable(Redeclarable *D); @@ -668,22 +666,21 @@ void ASTDeclReader::VisitPragmaCommentDecl(PragmaCommentDecl *D) { D->setLocation(readSourceLocation()); D->CommentKind = (PragmaMSCommentKind)Record.readInt(); std::string Arg = readString(); - memcpy(D->getTrailingObjects(), Arg.data(), Arg.size()); - D->getTrailingObjects()[Arg.size()] = '\0'; + memcpy(D->getTrailingObjects(), Arg.data(), Arg.size()); + D->getTrailingObjects()[Arg.size()] = '\0'; } void ASTDeclReader::VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *D) { VisitDecl(D); D->setLocation(readSourceLocation()); std::string Name = readString(); - memcpy(D->getTrailingObjects(), Name.data(), Name.size()); - D->getTrailingObjects()[Name.size()] = '\0'; + memcpy(D->getTrailingObjects(), Name.data(), Name.size()); + D->getTrailingObjects()[Name.size()] = '\0'; D->ValueStart = Name.size() + 1; std::string Value = readString(); - memcpy(D->getTrailingObjects() + D->ValueStart, Value.data(), - Value.size()); - D->getTrailingObjects()[D->ValueStart + Value.size()] = '\0'; + memcpy(D->getTrailingObjects() + D->ValueStart, Value.data(), Value.size()); + D->getTrailingObjects()[D->ValueStart + Value.size()] = '\0'; } void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { @@ -1633,6 +1630,9 @@ RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = VarDeclBits.getNextBit(); + if (VarDeclBits.getNextBit()) + Reader.InitSideEffectVars.insert(VD); + VD->NonParmVarDeclBits.EscapingByref = VarDeclBits.getNextBit(); HasDeducedType = VarDeclBits.getNextBit(); VD->NonParmVarDeclBits.ImplicitParamKind = @@ -1750,7 +1750,7 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) { VisitVarDecl(DD); - auto **BDs = DD->getTrailingObjects(); + auto **BDs = DD->getTrailingObjects(); for (unsigned I = 0; I != DD->NumBindings; ++I) { BDs[I] = readDeclAs(); BDs[I]->setDecomposedDecl(DD); @@ -1877,12 +1877,8 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { void ASTDeclReader::VisitHLSLBufferDecl(HLSLBufferDecl *D) { VisitNamedDecl(D); - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - uint64_t ModuleLocalOffset = 0; - uint64_t TULocalOffset = 0; - VisitDeclContext(D, LexicalOffset, VisibleOffset, ModuleLocalOffset, - TULocalOffset); + LookupBlockOffsets Offsets; + VisitDeclContext(D, Offsets); D->IsCBuffer = Record.readBool(); D->KwLoc = readSourceLocation(); D->LBraceLoc = readSourceLocation(); @@ -1925,7 +1921,7 @@ void ASTDeclReader::VisitUsingEnumDecl(UsingEnumDecl *D) { void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) { VisitNamedDecl(D); D->InstantiatedFrom = readDeclAs(); - auto **Expansions = D->getTrailingObjects(); + auto **Expansions = D->getTrailingObjects(); for (unsigned I = 0; I != D->NumExpansions; ++I) Expansions[I] = readDeclAs(); mergeMergeable(D); @@ -2366,7 +2362,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { VisitDecl(D); D->ImportedModule = readModule(); D->setImportComplete(Record.readInt()); - auto *StoredLocs = D->getTrailingObjects(); + auto *StoredLocs = D->getTrailingObjects(); for (unsigned I = 0, N = Record.back(); I != N; ++I) StoredLocs[I] = readSourceLocation(); Record.skipInts(1); // The number of stored source locations. @@ -2384,8 +2380,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { else D->Friend = readTypeSourceInfo(); for (unsigned i = 0; i != D->NumTPLists; ++i) - D->getTrailingObjects()[i] = - Record.readTemplateParameterList(); + D->getTrailingObjects()[i] = Record.readTemplateParameterList(); D->NextFriend = readDeclID().getRawValue(); D->UnsupportedFriend = (Record.readInt() != 0); D->FriendLoc = readSourceLocation(); @@ -2753,7 +2748,7 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { D->setDepth(Record.readInt()); D->setPosition(Record.readInt()); if (D->isExpandedParameterPack()) { - auto **Data = D->getTrailingObjects(); + auto **Data = D->getTrailingObjects(); for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); I != N; ++I) Data[I] = Record.readTemplateParameterList(); @@ -2808,14 +2803,12 @@ void ASTDeclReader::VisitLifetimeExtendedTemporaryDecl( mergeMergeable(D); } -void ASTDeclReader::VisitDeclContext(DeclContext *DC, uint64_t &LexicalOffset, - uint64_t &VisibleOffset, - uint64_t &ModuleLocalOffset, - uint64_t &TULocalOffset) { - LexicalOffset = ReadLocalOffset(); - VisibleOffset = ReadLocalOffset(); - ModuleLocalOffset = ReadLocalOffset(); - TULocalOffset = ReadLocalOffset(); +void ASTDeclReader::VisitDeclContext(DeclContext *DC, + LookupBlockOffsets &Offsets) { + Offsets.LexicalOffset = ReadLocalOffset(); + Offsets.VisibleOffset = ReadLocalOffset(); + Offsets.ModuleLocalOffset = ReadLocalOffset(); + Offsets.TULocalOffset = ReadLocalOffset(); } template @@ -3212,8 +3205,8 @@ Attr *ASTRecordReader::readAttr() { SpellingIndex == AlignedAttr::Keyword_alignas); bool IsRegularKeywordAttribute = Record.readBool(); - AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc, - AttributeCommonInfo::Kind(ParsedKind), + AttributeCommonInfo Info(AttrName, AttributeScopeInfo(ScopeName, ScopeLoc), + AttrRange, AttributeCommonInfo::Kind(ParsedKind), {AttributeCommonInfo::Syntax(Syntax), SpellingIndex, IsAlignas, IsRegularKeywordAttribute}); @@ -4269,42 +4262,37 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { // If this declaration is also a declaration context, get the // offsets for its tables of lexical and visible declarations. if (auto *DC = dyn_cast(D)) { - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - uint64_t ModuleLocalOffset = 0; - uint64_t TULocalOffset = 0; + LookupBlockOffsets Offsets; - Reader.VisitDeclContext(DC, LexicalOffset, VisibleOffset, ModuleLocalOffset, - TULocalOffset); + Reader.VisitDeclContext(DC, Offsets); // Get the lexical and visible block for the delayed namespace. // It is sufficient to judge if ID is in DelayedNamespaceOffsetMap. // But it may be more efficient to filter the other cases. - if (!LexicalOffset && !VisibleOffset && !ModuleLocalOffset && - isa(D)) + if (!Offsets && isa(D)) if (auto Iter = DelayedNamespaceOffsetMap.find(ID); - Iter != DelayedNamespaceOffsetMap.end()) { - LexicalOffset = Iter->second.LexicalOffset; - VisibleOffset = Iter->second.VisibleOffset; - ModuleLocalOffset = Iter->second.ModuleLocalOffset; - TULocalOffset = Iter->second.TULocalOffset; - } + Iter != DelayedNamespaceOffsetMap.end()) + Offsets = Iter->second; - if (LexicalOffset && - ReadLexicalDeclContextStorage(*Loc.F, DeclsCursor, LexicalOffset, DC)) - return nullptr; - if (VisibleOffset && ReadVisibleDeclContextStorage( - *Loc.F, DeclsCursor, VisibleOffset, ID, - VisibleDeclContextStorageKind::GenerallyVisible)) - return nullptr; - if (ModuleLocalOffset && + if (Offsets.VisibleOffset && ReadVisibleDeclContextStorage( - *Loc.F, DeclsCursor, ModuleLocalOffset, ID, + *Loc.F, DeclsCursor, Offsets.VisibleOffset, ID, + VisibleDeclContextStorageKind::GenerallyVisible)) + return nullptr; + if (Offsets.ModuleLocalOffset && + ReadVisibleDeclContextStorage( + *Loc.F, DeclsCursor, Offsets.ModuleLocalOffset, ID, VisibleDeclContextStorageKind::ModuleLocalVisible)) return nullptr; - if (TULocalOffset && ReadVisibleDeclContextStorage( - *Loc.F, DeclsCursor, TULocalOffset, ID, - VisibleDeclContextStorageKind::TULocalVisible)) + if (Offsets.TULocalOffset && + ReadVisibleDeclContextStorage( + *Loc.F, DeclsCursor, Offsets.TULocalOffset, ID, + VisibleDeclContextStorageKind::TULocalVisible)) + return nullptr; + + if (Offsets.LexicalOffset && + ReadLexicalDeclContextStorage(*Loc.F, DeclsCursor, + Offsets.LexicalOffset, DC)) return nullptr; } assert(Record.getIdx() == Record.size()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 0664b443e063..4c97cd601514 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -821,7 +821,7 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) { unsigned NumExprs = Record.readInt(); assert((NumExprs == E->getNumExprs()) && "Wrong NumExprs!"); for (unsigned I = 0; I != NumExprs; ++I) - E->getTrailingObjects()[I] = Record.readSubStmt(); + E->getTrailingObjects()[I] = Record.readSubStmt(); E->LParenLoc = readSourceLocation(); E->RParenLoc = readSourceLocation(); } @@ -1993,7 +1993,7 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { E->CXXDefaultArgExprBits.Loc = readSourceLocation(); E->CXXDefaultArgExprBits.HasRewrittenInit = Record.readInt(); if (E->CXXDefaultArgExprBits.HasRewrittenInit) - *E->getTrailingObjects() = Record.readSubExpr(); + *E->getTrailingObjects() = Record.readSubExpr(); } void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { @@ -2003,7 +2003,7 @@ void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { E->UsedContext = readDeclAs(); E->CXXDefaultInitExprBits.Loc = readSourceLocation(); if (E->CXXDefaultInitExprBits.HasRewrittenInit) - *E->getTrailingObjects() = Record.readSubExpr(); + *E->getTrailingObjects() = Record.readSubExpr(); } void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { @@ -2100,7 +2100,7 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { Obj = cast(Record.readSubExpr()); else llvm_unreachable("unexpected cleanup object type"); - E->getTrailingObjects()[i] = Obj; + E->getTrailingObjects()[i] = Obj; } E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt(); @@ -2299,9 +2299,8 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { E->Pack = Record.readDeclAs(); if (E->isPartiallySubstituted()) { assert(E->Length == NumPartialArgs); - for (auto *I = E->getTrailingObjects(), - *E = I + NumPartialArgs; - I != E; ++I) + for (auto *I = E->getTrailingObjects(), *E = I + NumPartialArgs; I != E; + ++I) new (I) TemplateArgument(Record.readTemplateArgument()); } else if (!E->isValueDependent()) { E->Length = Record.readInt(); @@ -2316,7 +2315,7 @@ void ASTStmtReader::VisitPackIndexingExpr(PackIndexingExpr *E) { E->RSquareLoc = readSourceLocation(); E->SubExprs[0] = Record.readStmt(); E->SubExprs[1] = Record.readStmt(); - auto **Exprs = E->getTrailingObjects(); + auto **Exprs = E->getTrailingObjects(); for (unsigned I = 0; I < E->PackIndexingExprBits.TransformedExpressions; ++I) Exprs[I] = Record.readExpr(); } @@ -2353,7 +2352,7 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { E->NumParameters = Record.readInt(); E->ParamPack = readDeclAs(); E->NameLoc = readSourceLocation(); - auto **Parms = E->getTrailingObjects(); + auto **Parms = E->getTrailingObjects(); for (unsigned i = 0, n = E->NumParameters; i != n; ++i) Parms[i] = readDeclAs(); } @@ -2390,7 +2389,7 @@ void ASTStmtReader::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { E->LParenLoc = readSourceLocation(); E->RParenLoc = readSourceLocation(); for (unsigned I = 0; I < ExpectedNumExprs; I++) - E->getTrailingObjects()[I] = Record.readSubExpr(); + E->getTrailingObjects()[I] = Record.readSubExpr(); bool HasArrayFillerOrUnionDecl = Record.readBool(); if (HasArrayFillerOrUnionDecl) { @@ -2411,10 +2410,6 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { E->setIsUnique(Record.readInt()); } -void ASTStmtReader::VisitTypoExpr(TypoExpr *E) { - llvm_unreachable("Cannot read TypoExpr nodes"); -} - void ASTStmtReader::VisitRecoveryExpr(RecoveryExpr *E) { VisitExpr(E); unsigned NumArgs = Record.readInt(); @@ -3707,11 +3702,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { } case STMT_OMP_REVERSE_DIRECTIVE: { - assert(Record[ASTStmtReader::NumStmtFields] == 1 && - "Reverse directive accepts only a single loop"); + unsigned NumLoops = Record[ASTStmtReader::NumStmtFields]; assert(Record[ASTStmtReader::NumStmtFields + 1] == 0 && "Reverse directive has no clauses"); - S = OMPReverseDirective::CreateEmpty(Context); + S = OMPReverseDirective::CreateEmpty(Context, NumLoops); break; } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 046bafc5b068..575253bcd685 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4105,11 +4105,9 @@ public: using hash_value_type = unsigned; using offset_type = unsigned; -protected: explicit ASTDeclContextNameLookupTraitBase(ASTWriter &Writer) : Writer(Writer) {} -public: data_type getData(const DeclIDsTy &LocalIDs) { unsigned Start = DeclIDs.size(); for (auto ID : LocalIDs) @@ -4247,6 +4245,38 @@ public: } }; +class ASTDeclContextNameTrivialLookupTrait + : public ASTDeclContextNameLookupTraitBase { +public: + using key_type = DeclarationNameKey; + using key_type_ref = key_type; + +public: + using ASTDeclContextNameLookupTraitBase::ASTDeclContextNameLookupTraitBase; + + using ASTDeclContextNameLookupTraitBase::getData; + + static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; } + + hash_value_type ComputeHash(key_type Name) { return Name.getHash(); } + + std::pair EmitKeyDataLength(raw_ostream &Out, + DeclarationNameKey Name, + data_type_ref Lookup) { + auto [KeyLen, DataLen] = EmitKeyDataLengthBase(Out, Name, Lookup); + return emitULEBKeyDataLength(KeyLen, DataLen, Out); + } + + void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { + return EmitKeyBase(Out, Name); + } + + void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, + unsigned DataLen) { + EmitDataBase(Out, Lookup, DataLen); + } +}; + static bool isModuleLocalDecl(NamedDecl *D) { // For decls not in a file context, they should have the same visibility // with their parent. @@ -4289,25 +4319,73 @@ static bool isTULocalInNamedModules(NamedDecl *D) { return D->getLinkageInternal() == Linkage::Internal; } -// Trait used for the on-disk hash table used in the method pool. -template -class ASTDeclContextNameLookupTrait : public ASTDeclContextNameLookupTraitBase { +class ASTDeclContextNameLookupTrait + : public ASTDeclContextNameTrivialLookupTrait { public: + using TULocalDeclsMapTy = llvm::DenseMap; + using ModuleLevelDeclsMapTy = llvm::DenseMap; - using key_type = DeclarationNameKey; - using key_type_ref = key_type; - - using TULocalDeclsMapTy = llvm::DenseMap; - private: + enum class LookupVisibility { + GenerallyVisibile, + // The decls can only be found by other TU in the same module. + // Note a clang::Module models a module unit instead of logical module + // in C++20. + ModuleLocalVisible, + // The decls can only be found by the TU itself that defines it. + TULocal, + }; + + LookupVisibility getLookupVisibility(NamedDecl *D) const { + // Only named modules have other lookup visibility. + if (!Writer.isWritingStdCXXNamedModules()) + return LookupVisibility::GenerallyVisibile; + + if (isModuleLocalDecl(D)) + return LookupVisibility::ModuleLocalVisible; + if (isTULocalInNamedModules(D)) + return LookupVisibility::TULocal; + + // A trick to handle enum constants. The enum constants is special since + // they can be found directly without their parent context. This makes it + // tricky to decide if an EnumConstantDecl is visible or not by their own + // visibilities. E.g., for a class member, we can assume it is visible if + // the user get its parent somehow. But for an enum constant, the users may + // access if without its parent context. Although we can fix the problem in + // Sema lookup process, it might be too complex, we just make a trick here. + // Note that we only removes enum constant from the lookup table from its + // parent of parent. We DON'T remove the enum constant from its parent. So + // we don't need to care about merging problems here. + if (auto *ECD = dyn_cast(D); + ECD && DC.isFileContext() && ECD->getOwningModule() && + ECD->getTopLevelOwningNamedModule()->isNamedModule()) { + if (llvm::all_of( + DC.noload_lookup( + cast(ECD->getDeclContext())->getDeclName()), + [](auto *Found) { + return Found->isInvisibleOutsideTheOwningModule(); + })) + return ECD->isFromExplicitGlobalModule() || + ECD->isInAnonymousNamespace() + ? LookupVisibility::TULocal + : LookupVisibility::ModuleLocalVisible; + } + + return LookupVisibility::GenerallyVisibile; + } + + DeclContext &DC; ModuleLevelDeclsMapTy ModuleLocalDeclsMap; TULocalDeclsMapTy TULocalDeclsMap; public: - explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) - : ASTDeclContextNameLookupTraitBase(Writer) {} + using ASTDeclContextNameTrivialLookupTrait:: + ASTDeclContextNameTrivialLookupTrait; + + ASTDeclContextNameLookupTrait(ASTWriter &Writer, DeclContext &DC) + : ASTDeclContextNameTrivialLookupTrait(Writer), DC(DC) {} template data_type getData(const Coll &Decls) { unsigned Start = DeclIDs.size(); @@ -4328,7 +4406,8 @@ public: auto ID = Writer.GetDeclRef(DeclForLocalLookup); - if (isModuleLocalDecl(D)) { + switch (getLookupVisibility(DeclForLocalLookup)) { + case LookupVisibility::ModuleLocalVisible: if (UnsignedOrNone PrimaryModuleHash = getPrimaryModuleHash(D->getOwningModule())) { auto Key = std::make_pair(D->getDeclName(), *PrimaryModuleHash); @@ -4339,17 +4418,18 @@ public: Iter->second.push_back(ID); continue; } + break; + case LookupVisibility::TULocal: { + auto Iter = TULocalDeclsMap.find(D->getDeclName()); + if (Iter == TULocalDeclsMap.end()) + TULocalDeclsMap.insert({D->getDeclName(), DeclIDsTy{ID}}); + else + Iter->second.push_back(ID); + continue; } - - if constexpr (CollectingTULocalDecls) { - if (isTULocalInNamedModules(D)) { - auto Iter = TULocalDeclsMap.find(D->getDeclName()); - if (Iter == TULocalDeclsMap.end()) - TULocalDeclsMap.insert({D->getDeclName(), DeclIDsTy{ID}}); - else - Iter->second.push_back(ID); - continue; - } + case LookupVisibility::GenerallyVisibile: + // Generally visible decls go into the general lookup table. + break; } DeclIDs.push_back(ID); @@ -4357,33 +4437,11 @@ public: return std::make_pair(Start, DeclIDs.size()); } - using ASTDeclContextNameLookupTraitBase::getData; - const ModuleLevelDeclsMapTy &getModuleLocalDecls() { return ModuleLocalDeclsMap; } const TULocalDeclsMapTy &getTULocalDecls() { return TULocalDeclsMap; } - - static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; } - - hash_value_type ComputeHash(key_type Name) { return Name.getHash(); } - - std::pair EmitKeyDataLength(raw_ostream &Out, - DeclarationNameKey Name, - data_type_ref Lookup) { - auto [KeyLen, DataLen] = EmitKeyDataLengthBase(Out, Name, Lookup); - return emitULEBKeyDataLength(KeyLen, DataLen, Out); - } - - void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { - return EmitKeyBase(Out, Name); - } - - void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, - unsigned DataLen) { - EmitDataBase(Out, Lookup, DataLen); - } }; } // namespace @@ -4597,11 +4655,10 @@ void ASTWriter::GenerateNameLookupTable( assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table"); // Create the on-disk hash table representation. - MultiOnDiskHashTableGenerator< - reader::ASTDeclContextNameLookupTrait, - ASTDeclContextNameLookupTrait> + MultiOnDiskHashTableGenerator Generator; - ASTDeclContextNameLookupTrait Trait(*this); + ASTDeclContextNameLookupTrait Trait(*this, *DC); // The first step is to collect the declaration names which we need to // serialize into the name lookup table, and to collect them in a stable @@ -4759,12 +4816,10 @@ void ASTWriter::GenerateNameLookupTable( const auto &TULocalDecls = Trait.getTULocalDecls(); if (!TULocalDecls.empty() && !isGeneratingReducedBMI()) { - MultiOnDiskHashTableGenerator< - reader::ASTDeclContextNameLookupTrait, - ASTDeclContextNameLookupTrait> + MultiOnDiskHashTableGenerator TULookupGenerator; - ASTDeclContextNameLookupTrait TULocalTrait( - *this); + ASTDeclContextNameTrivialLookupTrait TULocalTrait(*this); for (const auto &TULocalIter : TULocalDecls) { const auto &Key = TULocalIter.first; @@ -4783,14 +4838,9 @@ void ASTWriter::GenerateNameLookupTable( /// /// \returns the offset of the DECL_CONTEXT_VISIBLE block within the /// bitstream, or 0 if no block was written. -void ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, - DeclContext *DC, - uint64_t &VisibleBlockOffset, - uint64_t &ModuleLocalBlockOffset, - uint64_t &TULocalBlockOffset) { - assert(VisibleBlockOffset == 0); - assert(ModuleLocalBlockOffset == 0); - assert(TULocalBlockOffset == 0); +void ASTWriter::WriteDeclContextVisibleBlock( + ASTContext &Context, DeclContext *DC, VisibleLookupBlockOffsets &Offsets) { + assert(!Offsets); // If we imported a key declaration of this namespace, write the visible // lookup results as an update record for it rather than including them @@ -4874,7 +4924,7 @@ void ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, if (!Map || Map->empty()) return; - VisibleBlockOffset = Stream.GetCurrentBitNo(); + Offsets.VisibleOffset = Stream.GetCurrentBitNo(); // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; SmallString<4096> ModuleLocalLookupTable; @@ -4889,8 +4939,8 @@ void ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, ++NumVisibleDeclContexts; if (!ModuleLocalLookupTable.empty()) { - ModuleLocalBlockOffset = Stream.GetCurrentBitNo(); - assert(ModuleLocalBlockOffset > VisibleBlockOffset); + Offsets.ModuleLocalOffset = Stream.GetCurrentBitNo(); + assert(Offsets.ModuleLocalOffset > Offsets.VisibleOffset); // Write the lookup table RecordData::value_type ModuleLocalRecord[] = { DECL_CONTEXT_MODULE_LOCAL_VISIBLE}; @@ -4900,7 +4950,7 @@ void ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, } if (!TULookupTable.empty()) { - TULocalBlockOffset = Stream.GetCurrentBitNo(); + Offsets.TULocalOffset = Stream.GetCurrentBitNo(); // Write the lookup table RecordData::value_type TULocalDeclsRecord[] = { DECL_CONTEXT_TU_LOCAL_VISIBLE}; @@ -5183,8 +5233,9 @@ void ASTRecordWriter::AddAttr(const Attr *A) { // FIXME: Clang can't handle the serialization/deserialization of // preferred_name properly now. See // https://github.com/llvm/llvm-project/issues/56490 for example. - if (!A || (isa(A) && - Writer->isWritingStdCXXNamedModules())) + if (!A || + (isa(A) && (Writer->isWritingStdCXXNamedModules() || + Writer->isWritingStdCXXHeaderUnit()))) return Record.push_back(0); Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs @@ -6218,31 +6269,26 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { assert(DelayedNamespace.empty() || GeneratingReducedBMI); RecordData DelayedNamespaceRecord; for (NamespaceDecl *NS : DelayedNamespace) { - uint64_t LexicalOffset = WriteDeclContextLexicalBlock(Context, NS); - uint64_t VisibleOffset = 0; - uint64_t ModuleLocalOffset = 0; - uint64_t TULocalOffset = 0; - WriteDeclContextVisibleBlock(Context, NS, VisibleOffset, ModuleLocalOffset, - TULocalOffset); + LookupBlockOffsets Offsets; + + Offsets.LexicalOffset = WriteDeclContextLexicalBlock(Context, NS); + WriteDeclContextVisibleBlock(Context, NS, Offsets); + + if (Offsets.LexicalOffset) + Offsets.LexicalOffset -= DeclTypesBlockStartOffset; // Write the offset relative to current block. - if (LexicalOffset) - LexicalOffset -= DeclTypesBlockStartOffset; + if (Offsets.VisibleOffset) + Offsets.VisibleOffset -= DeclTypesBlockStartOffset; - if (VisibleOffset) - VisibleOffset -= DeclTypesBlockStartOffset; + if (Offsets.ModuleLocalOffset) + Offsets.ModuleLocalOffset -= DeclTypesBlockStartOffset; - if (ModuleLocalOffset) - ModuleLocalOffset -= DeclTypesBlockStartOffset; - - if (TULocalOffset) - TULocalOffset -= DeclTypesBlockStartOffset; + if (Offsets.TULocalOffset) + Offsets.TULocalOffset -= DeclTypesBlockStartOffset; AddDeclRef(NS, DelayedNamespaceRecord); - DelayedNamespaceRecord.push_back(LexicalOffset); - DelayedNamespaceRecord.push_back(VisibleOffset); - DelayedNamespaceRecord.push_back(ModuleLocalOffset); - DelayedNamespaceRecord.push_back(TULocalOffset); + AddLookupOffsets(Offsets, DelayedNamespaceRecord); } // The process of writing lexical and visible block for delayed namespace @@ -6833,6 +6879,14 @@ TypeID ASTWriter::GetOrCreateTypeID(ASTContext &Context, QualType T) { }); } +void ASTWriter::AddLookupOffsets(const LookupBlockOffsets &Offsets, + RecordDataImpl &Record) { + Record.push_back(Offsets.LexicalOffset); + Record.push_back(Offsets.VisibleOffset); + Record.push_back(Offsets.ModuleLocalOffset); + Record.push_back(Offsets.TULocalOffset); +} + void ASTWriter::AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record) { if (!wasDeclEmitted(D)) return; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 8a378b59e05b..673e68dd7b1e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -223,6 +223,48 @@ namespace clang { Record.AddDeclRef(F.second); } + template bool shouldSkipWritingSpecializations(T *Spec) { + // Now we will only avoid writing specializations if we're generating + // reduced BMI. + if (!GeneratingReducedBMI) + return false; + + assert((isa(Spec))); + + ArrayRef Args; + if (auto *CTSD = dyn_cast(Spec)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(Spec)) + Args = VTSD->getTemplateArgs().asArray(); + else + Args = cast(Spec) + ->getTemplateSpecializationArgs() + ->asArray(); + + // If there is any template argument is TULocal, we can avoid writing the + // specialization since the consumers of reduced BMI won't get the + // specialization anyway. + for (const TemplateArgument &TA : Args) { + switch (TA.getKind()) { + case TemplateArgument::Type: { + Linkage L = TA.getAsType()->getLinkage(); + if (!isExternallyVisible(L)) + return true; + break; + } + case TemplateArgument::Declaration: + if (!TA.getAsDecl()->isExternallyVisible()) + return true; + break; + default: + break; + } + } + + return false; + } + /// Add to the record the first template specialization from each module /// file that provides a declaration of D. We store the DeclId and an /// ODRHash of the template arguments of D which should provide enough @@ -237,6 +279,9 @@ namespace clang { CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts); for (const auto &F : Firsts) { + if (shouldSkipWritingSpecializations(F.second)) + continue; + if (isa(F.second)) PartialSpecsInMap.push_back(F.second); @@ -1263,6 +1308,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VarDeclBits.addBit(D->isConstexpr()); VarDeclBits.addBit(D->isInitCapture()); VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope()); + VarDeclBits.addBit(D->hasInitWithSideEffects()); VarDeclBits.addBit(D->isEscapingByref()); HasDeducedType = D->getType()->getContainedDeducedType(); @@ -1312,10 +1358,11 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() && D->getKind() == Decl::Var && !D->isInline() && !D->isConstexpr() && !D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() && - !D->isEscapingByref() && !HasDeducedType && - D->getStorageDuration() != SD_Static && !D->getDescribedVarTemplate() && - !D->getMemberSpecializationInfo() && !D->isObjCForDecl() && - !isa(D) && !D->isEscapingByref()) + !D->hasInitWithSideEffects() && !D->isEscapingByref() && + !HasDeducedType && D->getStorageDuration() != SD_Static && + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + !D->isObjCForDecl() && !isa(D) && + !D->isEscapingByref()) AbbrevToUse = Writer.getDeclVarAbbrev(); Code = serialization::DECL_VAR; @@ -2160,11 +2207,7 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC) { static_assert(DeclContext::NumDeclContextBits == 13, "You need to update the serializer after you change the " "DeclContextBits"); - - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - uint64_t ModuleLocalOffset = 0; - uint64_t TULocalOffset = 0; + LookupBlockOffsets Offsets; if (Writer.isGeneratingReducedBMI() && isa(DC) && cast(DC)->isFromExplicitGlobalModule()) { @@ -2173,17 +2216,12 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC) { // details. Writer.DelayedNamespace.push_back(cast(DC)); } else { - LexicalOffset = + Offsets.LexicalOffset = Writer.WriteDeclContextLexicalBlock(Record.getASTContext(), DC); - Writer.WriteDeclContextVisibleBlock(Record.getASTContext(), DC, - VisibleOffset, ModuleLocalOffset, - TULocalOffset); + Writer.WriteDeclContextVisibleBlock(Record.getASTContext(), DC, Offsets); } - Record.AddOffset(LexicalOffset); - Record.AddOffset(VisibleOffset); - Record.AddOffset(ModuleLocalOffset); - Record.AddOffset(TULocalOffset); + Record.AddLookupOffsets(Offsets); } const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) { @@ -2711,12 +2749,12 @@ void ASTWriter::WriteDeclAbbrevs() { // VarDecl Abv->Add(BitCodeAbbrevOp( BitCodeAbbrevOp::Fixed, - 21)); // Packed Var Decl bits: Linkage, ModulesCodegen, + 22)); // Packed Var Decl bits: Linkage, ModulesCodegen, // SClass, TSCSpec, InitStyle, // isARCPseudoStrong, IsThisDeclarationADemotedDefinition, // isExceptionVariable, isNRVOVariable, isCXXForRangeDecl, // isInline, isInlineSpecified, isConstexpr, - // isInitCapture, isPrevDeclInSameScope, + // isInitCapture, isPrevDeclInSameScope, hasInitWithSideEffects, // EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum) // Type Source Info diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 1170f708817c..c0027d0ef583 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2442,12 +2442,6 @@ void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { Code = serialization::EXPR_OPAQUE_VALUE; } -void ASTStmtWriter::VisitTypoExpr(TypoExpr *E) { - VisitExpr(E); - // TODO: Figure out sane writer behavior for a TypoExpr, if necessary - llvm_unreachable("Cannot write TypoExpr nodes"); -} - //===----------------------------------------------------------------------===// // CUDA Expressions and Statements. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 15d73fb9ca39..ab90615f6318 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -69,7 +69,7 @@ void DivZeroChecker::reportTaintBug( llvm::ArrayRef TaintedSyms) const { if (!TaintedDivChecker.isEnabled()) return; - if (ExplodedNode *N = C.generateNonFatalErrorNode(StateZero)) { + if (ExplodedNode *N = C.generateErrorNode(StateZero)) { auto R = std::make_unique(TaintedDivChecker, Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); @@ -113,9 +113,9 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, if ((stateNotZero && stateZero)) { std::vector taintedSyms = getTaintedSymbols(C.getState(), *DV); if (!taintedSyms.empty()) { - reportTaintBug("Division by a tainted value, possibly zero", stateNotZero, - C, taintedSyms); - return; + reportTaintBug("Division by a tainted value, possibly zero", stateZero, C, + taintedSyms); + // Fallthrough to continue analysis in case of non-zero denominator. } } diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 344be0b176c5..4982cd59b0a4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -49,15 +49,19 @@ REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, const ObjCObjectPointerType *) namespace { -class DynamicTypePropagation: - public Checker< check::PreCall, - check::PostCall, - check::DeadSymbols, - check::PostStmt, - check::PostStmt, - check::PreObjCMessage, - check::PostObjCMessage > { +class DynamicTypePropagation + : public CheckerFamily, + check::PostStmt, check::PreObjCMessage, + check::PostObjCMessage> { +public: + // This checker family implements only one frontend, but -- unlike a simple + // Checker -- its backend can be enabled (by the checker DynamicTypeChecker + // which depends on it) without enabling the frontend. + CheckerFrontendWithBugType ObjCGenericsChecker{ + "Generics", categories::CoreFoundationObjectiveC}; +private: /// Return a better dynamic type if one can be derived from the cast. const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, CheckerContext &C) const; @@ -66,13 +70,6 @@ class DynamicTypePropagation: ProgramStateRef &State, CheckerContext &C) const; - mutable std::unique_ptr ObjCGenericsBugType; - void initBugType() const { - if (!ObjCGenericsBugType) - ObjCGenericsBugType.reset(new BugType( - GenericCheckName, "Generics", categories::CoreFoundationObjectiveC)); - } - class GenericsBugVisitor : public BugReporterVisitor { public: GenericsBugVisitor(SymbolRef S) : Sym(S) {} @@ -106,9 +103,8 @@ public: void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; - /// This value is set to true, when the Generics checker is turned on. - bool CheckGenerics = false; - CheckerNameRef GenericCheckName; + /// Identifies this checker family for debugging purposes. + StringRef getDebugTag() const override { return "DynamicTypePropagation"; } }; bool isObjCClassType(QualType Type) { @@ -1026,10 +1022,9 @@ void DynamicTypePropagation::reportGenericsBug( const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, ExplodedNode *N, SymbolRef Sym, CheckerContext &C, const Stmt *ReportedNode) const { - if (!CheckGenerics) + if (!ObjCGenericsChecker.isEnabled()) return; - initBugType(); SmallString<192> Buf; llvm::raw_svector_ostream OS(Buf); OS << "Conversion from value of type '"; @@ -1037,7 +1032,7 @@ void DynamicTypePropagation::reportGenericsBug( OS << "' to incompatible type '"; QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); OS << "'"; - auto R = std::make_unique(*ObjCGenericsBugType, + auto R = std::make_unique(ObjCGenericsChecker, OS.str(), N); R->markInteresting(Sym); R->addVisitor(std::make_unique(Sym)); @@ -1102,20 +1097,22 @@ PathDiagnosticPieceRef DynamicTypePropagation::GenericsBugVisitor::VisitNode( } /// Register checkers. -void ento::registerObjCGenericsChecker(CheckerManager &mgr) { - DynamicTypePropagation *checker = mgr.getChecker(); - checker->CheckGenerics = true; - checker->GenericCheckName = mgr.getCurrentCheckerName(); +void ento::registerObjCGenericsChecker(CheckerManager &Mgr) { + Mgr.getChecker()->ObjCGenericsChecker.enable(Mgr); } -bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &mgr) { +bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &) { return true; } -void ento::registerDynamicTypePropagation(CheckerManager &mgr) { - mgr.registerChecker(); +void ento::registerDynamicTypePropagation(CheckerManager &Mgr) { + // The checker 'core.DynamicTypeChecker' relies on the modeling implemented + // in the class 'DynamicTypePropagation', so this "modeling checker" can + // register the 'DynamicTypePropagation' backend for its callbacks without + // enabling its frontend. + Mgr.getChecker(); } -bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &mgr) { +bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index fef33509c0b6..35e98a5e2719 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1371,6 +1371,20 @@ void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State, C.addTransition(State); } +const Expr *getPlacementNewBufferArg(const CallExpr *CE, + const FunctionDecl *FD) { + // Checking for signature: + // void* operator new ( std::size_t count, void* ptr ); + // void* operator new[]( std::size_t count, void* ptr ); + if (CE->getNumArgs() != 2 || (FD->getOverloadedOperator() != OO_New && + FD->getOverloadedOperator() != OO_Array_New)) + return nullptr; + auto BuffType = FD->getParamDecl(1)->getType(); + if (BuffType.isNull() || !BuffType->isVoidPointerType()) + return nullptr; + return CE->getArg(1); +} + void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) const { @@ -1386,6 +1400,14 @@ void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State, // processed by the checkPostStmt callbacks for CXXNewExpr and // CXXDeleteExpr. const FunctionDecl *FD = C.getCalleeDecl(CE); + if (const auto *BufArg = getPlacementNewBufferArg(CE, FD)) { + // Placement new does not allocate memory + auto RetVal = State->getSVal(BufArg, Call.getLocationContext()); + State = State->BindExpr(CE, C.getLocationContext(), RetVal); + C.addTransition(State); + return; + } + switch (FD->getOverloadedOperator()) { case OO_New: State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State, diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 461d01b452fd..9744d1abf779 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -81,11 +81,12 @@ enum class ErrorKind : int { }; class NullabilityChecker - : public Checker, - check::PostCall, check::PostStmt, - check::PostObjCMessage, check::DeadSymbols, eval::Assume, - check::Location, check::Event, - check::BeginFunction> { + : public CheckerFamily< + check::Bind, check::PreCall, check::PreStmt, + check::PostCall, check::PostStmt, + check::PostObjCMessage, check::DeadSymbols, eval::Assume, + check::Location, check::Event, + check::BeginFunction> { public: // If true, the checker will not diagnose nullabilility issues for calls @@ -113,25 +114,21 @@ public: void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; - enum CheckKind { - CK_NullPassedToNonnull, - CK_NullReturnedFromNonnull, - CK_NullableDereferenced, - CK_NullablePassedToNonnull, - CK_NullableReturnedFromNonnull, - CK_NumCheckKinds - }; + StringRef getDebugTag() const override { return "NullabilityChecker"; } - bool ChecksEnabled[CK_NumCheckKinds] = {false}; - CheckerNameRef CheckNames[CK_NumCheckKinds]; - mutable std::unique_ptr BTs[CK_NumCheckKinds]; - - const std::unique_ptr &getBugType(CheckKind Kind) const { - if (!BTs[Kind]) - BTs[Kind].reset(new BugType(CheckNames[Kind], "Nullability", - categories::MemoryError)); - return BTs[Kind]; - } + // FIXME: All bug types share the same Description ("Nullability") since the + // creation of this checker. We should write more descriptive descriptions... + // or just eliminate the Description field if it is meaningless? + CheckerFrontendWithBugType NullPassedToNonnull{"Nullability", + categories::MemoryError}; + CheckerFrontendWithBugType NullReturnedFromNonnull{"Nullability", + categories::MemoryError}; + CheckerFrontendWithBugType NullableDereferenced{"Nullability", + categories::MemoryError}; + CheckerFrontendWithBugType NullablePassedToNonnull{"Nullability", + categories::MemoryError}; + CheckerFrontendWithBugType NullableReturnedFromNonnull{ + "Nullability", categories::MemoryError}; // When set to false no nullability information will be tracked in // NullabilityMap. It is possible to catch errors like passing a null pointer @@ -164,17 +161,16 @@ private: /// /// When \p SuppressPath is set to true, no more bugs will be reported on this /// path by this checker. - void reportBugIfInvariantHolds(StringRef Msg, ErrorKind Error, CheckKind CK, - ExplodedNode *N, const MemRegion *Region, - CheckerContext &C, + void reportBugIfInvariantHolds(StringRef Msg, ErrorKind Error, + const BugType &BT, ExplodedNode *N, + const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr = nullptr, bool SuppressPath = false) const; - void reportBug(StringRef Msg, ErrorKind Error, CheckKind CK, ExplodedNode *N, - const MemRegion *Region, BugReporter &BR, + void reportBug(StringRef Msg, ErrorKind Error, const BugType &BT, + ExplodedNode *N, const MemRegion *Region, BugReporter &BR, const Stmt *ValueExpr = nullptr) const { - const std::unique_ptr &BT = getBugType(CK); - auto R = std::make_unique(*BT, Msg, N); + auto R = std::make_unique(BT, Msg, N); if (Region) { R->markInteresting(Region); R->addVisitor(Region); @@ -480,7 +476,7 @@ static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N, } void NullabilityChecker::reportBugIfInvariantHolds( - StringRef Msg, ErrorKind Error, CheckKind CK, ExplodedNode *N, + StringRef Msg, ErrorKind Error, const BugType &BT, ExplodedNode *N, const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr, bool SuppressPath) const { ProgramStateRef OriginalState = N->getState(); @@ -492,7 +488,7 @@ void NullabilityChecker::reportBugIfInvariantHolds( N = C.addTransition(OriginalState, N); } - reportBug(Msg, Error, CK, N, Region, C.getBugReporter(), ValueExpr); + reportBug(Msg, Error, BT, N, Region, C.getBugReporter(), ValueExpr); } /// Cleaning up the program state. @@ -546,19 +542,19 @@ void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const { if (!TrackedNullability) return; - if (ChecksEnabled[CK_NullableDereferenced] && + if (NullableDereferenced.isEnabled() && TrackedNullability->getValue() == Nullability::Nullable) { BugReporter &BR = *Event.BR; // Do not suppress errors on defensive code paths, because dereferencing // a nullable pointer is always an error. if (Event.IsDirectDereference) reportBug("Nullable pointer is dereferenced", - ErrorKind::NullableDereferenced, CK_NullableDereferenced, + ErrorKind::NullableDereferenced, NullableDereferenced, Event.SinkNode, Region, BR); else { reportBug("Nullable pointer is passed to a callee that requires a " "non-null", - ErrorKind::NullablePassedToNonnull, CK_NullableDereferenced, + ErrorKind::NullablePassedToNonnull, NullableDereferenced, Event.SinkNode, Region, BR); } } @@ -710,29 +706,28 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S, Nullability RetExprTypeLevelNullability = getNullabilityAnnotation(lookThroughImplicitCasts(RetExpr)->getType()); - bool NullReturnedFromNonNull = (RequiredNullability == Nullability::Nonnull && - Nullness == NullConstraint::IsNull); - if (ChecksEnabled[CK_NullReturnedFromNonnull] && NullReturnedFromNonNull && - RetExprTypeLevelNullability != Nullability::Nonnull && - !InSuppressedMethodFamily) { - ExplodedNode *N = C.generateErrorNode(State); - if (!N) + if (RequiredNullability == Nullability::Nonnull && + Nullness == NullConstraint::IsNull) { + if (NullReturnedFromNonnull.isEnabled() && + RetExprTypeLevelNullability != Nullability::Nonnull && + !InSuppressedMethodFamily) { + ExplodedNode *N = C.generateErrorNode(State); + if (!N) + return; + + SmallString<256> SBuf; + llvm::raw_svector_ostream OS(SBuf); + OS << (RetExpr->getType()->isObjCObjectPointerType() ? "nil" : "Null"); + OS << " returned from a " << C.getDeclDescription(D) + << " that is expected to return a non-null value"; + reportBugIfInvariantHolds(OS.str(), ErrorKind::NilReturnedToNonnull, + NullReturnedFromNonnull, N, nullptr, C, + RetExpr); return; + } - SmallString<256> SBuf; - llvm::raw_svector_ostream OS(SBuf); - OS << (RetExpr->getType()->isObjCObjectPointerType() ? "nil" : "Null"); - OS << " returned from a " << C.getDeclDescription(D) << - " that is expected to return a non-null value"; - reportBugIfInvariantHolds(OS.str(), ErrorKind::NilReturnedToNonnull, - CK_NullReturnedFromNonnull, N, nullptr, C, - RetExpr); - return; - } - - // If null was returned from a non-null function, mark the nullability - // invariant as violated even if the diagnostic was suppressed. - if (NullReturnedFromNonNull) { + // If null was returned from a non-null function, mark the nullability + // invariant as violated even if the diagnostic was suppressed. State = State->set(true); C.addTransition(State); return; @@ -746,7 +741,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S, State->get(Region); if (TrackedNullability) { Nullability TrackedNullabValue = TrackedNullability->getValue(); - if (ChecksEnabled[CK_NullableReturnedFromNonnull] && + if (NullableReturnedFromNonnull.isEnabled() && Nullness != NullConstraint::IsNotNull && TrackedNullabValue == Nullability::Nullable && RequiredNullability == Nullability::Nonnull) { @@ -758,7 +753,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S, " that is expected to return a non-null value"; reportBugIfInvariantHolds(OS.str(), ErrorKind::NullableReturnedToNonnull, - CK_NullableReturnedFromNonnull, N, Region, C); + NullableReturnedFromNonnull, N, Region, C); } return; } @@ -809,8 +804,7 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, unsigned ParamIdx = Param->getFunctionScopeIndex() + 1; - if (ChecksEnabled[CK_NullPassedToNonnull] && - Nullness == NullConstraint::IsNull && + if (NullPassedToNonnull.isEnabled() && Nullness == NullConstraint::IsNull && ArgExprTypeLevelNullability != Nullability::Nonnull && RequiredNullability == Nullability::Nonnull && isDiagnosableCall(Call)) { @@ -824,7 +818,7 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, OS << " passed to a callee that requires a non-null " << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter"; reportBugIfInvariantHolds(OS.str(), ErrorKind::NilPassedToNonnull, - CK_NullPassedToNonnull, N, nullptr, C, ArgExpr, + NullPassedToNonnull, N, nullptr, C, ArgExpr, /*SuppressPath=*/false); return; } @@ -841,7 +835,7 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, TrackedNullability->getValue() != Nullability::Nullable) continue; - if (ChecksEnabled[CK_NullablePassedToNonnull] && + if (NullablePassedToNonnull.isEnabled() && RequiredNullability == Nullability::Nonnull && isDiagnosableCall(Call)) { ExplodedNode *N = C.addTransition(State); @@ -850,17 +844,16 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, OS << "Nullable pointer is passed to a callee that requires a non-null " << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter"; reportBugIfInvariantHolds(OS.str(), ErrorKind::NullablePassedToNonnull, - CK_NullablePassedToNonnull, N, Region, C, + NullablePassedToNonnull, N, Region, C, ArgExpr, /*SuppressPath=*/true); return; } - if (ChecksEnabled[CK_NullableDereferenced] && + if (NullableDereferenced.isEnabled() && Param->getType()->isReferenceType()) { ExplodedNode *N = C.addTransition(State); - reportBugIfInvariantHolds("Nullable pointer is dereferenced", - ErrorKind::NullableDereferenced, - CK_NullableDereferenced, N, Region, C, - ArgExpr, /*SuppressPath=*/true); + reportBugIfInvariantHolds( + "Nullable pointer is dereferenced", ErrorKind::NullableDereferenced, + NullableDereferenced, N, Region, C, ArgExpr, /*SuppressPath=*/true); return; } continue; @@ -1294,7 +1287,7 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull && RhsNullness == NullConstraint::IsNull); - if (ChecksEnabled[CK_NullPassedToNonnull] && NullAssignedToNonNull && + if (NullPassedToNonnull.isEnabled() && NullAssignedToNonNull && ValNullability != Nullability::Nonnull && ValueExprTypeLevelNullability != Nullability::Nonnull && !isARCNilInitializedLocal(C, S)) { @@ -1312,7 +1305,7 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null"); OS << " assigned to a pointer which is expected to have non-null value"; reportBugIfInvariantHolds(OS.str(), ErrorKind::NilAssignedToNonnull, - CK_NullPassedToNonnull, N, nullptr, C, ValueStmt); + NullPassedToNonnull, N, nullptr, C, ValueStmt); return; } @@ -1338,13 +1331,13 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, if (RhsNullness == NullConstraint::IsNotNull || TrackedNullability->getValue() != Nullability::Nullable) return; - if (ChecksEnabled[CK_NullablePassedToNonnull] && + if (NullablePassedToNonnull.isEnabled() && LocNullability == Nullability::Nonnull) { ExplodedNode *N = C.addTransition(State, C.getPredecessor()); reportBugIfInvariantHolds("Nullable pointer is assigned to a pointer " "which is expected to have non-null value", ErrorKind::NullableAssignedToNonnull, - CK_NullablePassedToNonnull, N, ValueRegion, C); + NullablePassedToNonnull, N, ValueRegion, C); } return; } @@ -1391,28 +1384,26 @@ void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State, } } -void ento::registerNullabilityBase(CheckerManager &mgr) { - mgr.registerChecker(); -} +// The checker group "nullability" (which consists of the checkers that are +// implemented in this file) has a group-level configuration option which +// affects all the checkers in the group. As this is a completely unique +// remnant of old design (this is the only group option in the analyzer), there +// is no machinery to inject the group name from `Checkers.td`, so it is simply +// hardcoded here: +constexpr llvm::StringLiteral GroupName = "nullability"; +constexpr llvm::StringLiteral GroupOptName = "NoDiagnoseCallsToSystemHeaders"; -bool ento::shouldRegisterNullabilityBase(const CheckerManager &mgr) { - return true; -} - -#define REGISTER_CHECKER(name, trackingRequired) \ - void ento::register##name##Checker(CheckerManager &mgr) { \ - NullabilityChecker *checker = mgr.getChecker(); \ - checker->ChecksEnabled[NullabilityChecker::CK_##name] = true; \ - checker->CheckNames[NullabilityChecker::CK_##name] = \ - mgr.getCurrentCheckerName(); \ - checker->NeedTracking = checker->NeedTracking || trackingRequired; \ - checker->NoDiagnoseCallsToSystemHeaders = \ - checker->NoDiagnoseCallsToSystemHeaders || \ - mgr.getAnalyzerOptions().getCheckerBooleanOption( \ - checker, "NoDiagnoseCallsToSystemHeaders", true); \ +#define REGISTER_CHECKER(NAME, TRACKING_REQUIRED) \ + void ento::register##NAME##Checker(CheckerManager &Mgr) { \ + NullabilityChecker *Chk = Mgr.getChecker(); \ + Chk->NAME.enable(Mgr); \ + Chk->NeedTracking = Chk->NeedTracking || TRACKING_REQUIRED; \ + Chk->NoDiagnoseCallsToSystemHeaders = \ + Mgr.getAnalyzerOptions().getCheckerBooleanOption(GroupName, \ + GroupOptName, true); \ } \ \ - bool ento::shouldRegister##name##Checker(const CheckerManager &mgr) { \ + bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \ return true; \ } diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index a00a09f60fd5..62bc3218d9ce 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "RetainCountChecker.h" -#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9f68233cf71a..4b9db04b7e3c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1748,7 +1748,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ExpressionTraitExprClass: case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: - case Stmt::TypoExprClass: case Stmt::RecoveryExprClass: case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: diff --git a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp index 836fc375809a..f965bfb590d8 100644 --- a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp +++ b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp @@ -92,7 +92,7 @@ void Z3CrosscheckVisitor::finalizeVisitor(BugReporterContext &BRC, }; auto AttemptOnce = [&](const llvm::SMTSolverRef &Solver) -> Z3Result { - constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime; + auto getCurrentTime = llvm::TimeRecord::getCurrentTime; unsigned InitialRLimit = GetUsedRLimit(Solver); double Start = getCurrentTime(/*Start=*/true).getWallTime(); std::optional IsSAT = Solver->check(); diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp index daf09ac66f21..5a4e805d4a9d 100644 --- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp +++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp @@ -8,13 +8,10 @@ #include "clang/Support/RISCVVIntrinsicUtils.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include #include using namespace llvm; diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index d01c57ee69c0..999fa790124c 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -22,8 +22,7 @@ namespace clang { namespace tooling { static StringRef getDriverMode(const CommandLineArguments &Args) { - for (const auto &Arg : Args) { - StringRef ArgRef = Arg; + for (StringRef ArgRef : Args) { if (ArgRef.consume_front("--driver-mode=")) { return ArgRef; } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp index 140833050f4e..2868522f8001 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Threading.h" #include @@ -232,19 +233,19 @@ bool DependencyScanningWorkerFilesystem::shouldBypass(StringRef Path) const { } DependencyScanningWorkerFilesystem::DependencyScanningWorkerFilesystem( - DependencyScanningFilesystemSharedCache &SharedCache, + DependencyScanningService &Service, IntrusiveRefCntPtr FS) : llvm::RTTIExtends(std::move(FS)), - SharedCache(SharedCache), - WorkingDirForCacheLookup(llvm::errc::invalid_argument) { + Service(Service), WorkingDirForCacheLookup(llvm::errc::invalid_argument) { updateWorkingDirForCacheLookup(); } const CachedFileSystemEntry & DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID( TentativeEntry TEntry) { - auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID()); + auto &Shard = + Service.getSharedCache().getShardForUID(TEntry.Status.getUniqueID()); return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(), std::move(TEntry.Status), std::move(TEntry.Contents)); @@ -255,18 +256,44 @@ DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough( StringRef Filename) { if (const auto *Entry = LocalCache.findEntryByFilename(Filename)) return Entry; - auto &Shard = SharedCache.getShardForFilename(Filename); + auto &Shard = Service.getSharedCache().getShardForFilename(Filename); if (const auto *Entry = Shard.findEntryByFilename(Filename)) return &LocalCache.insertEntryForFilename(Filename, *Entry); return nullptr; } +const CachedFileSystemEntry * +DependencyScanningWorkerFilesystem::findSharedEntryByUID( + llvm::vfs::Status Stat) const { + return Service.getSharedCache() + .getShardForUID(Stat.getUniqueID()) + .findEntryByUID(Stat.getUniqueID()); +} + +const CachedFileSystemEntry & +DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForFilename( + StringRef Filename, std::error_code EC) { + return Service.getSharedCache() + .getShardForFilename(Filename) + .getOrEmplaceEntryForFilename(Filename, EC); +} + +const CachedFileSystemEntry & +DependencyScanningWorkerFilesystem::getOrInsertSharedEntryForFilename( + StringRef Filename, const CachedFileSystemEntry &Entry) { + return Service.getSharedCache() + .getShardForFilename(Filename) + .getOrInsertEntryForFilename(Filename, Entry); +} + llvm::ErrorOr DependencyScanningWorkerFilesystem::computeAndStoreResult( StringRef OriginalFilename, StringRef FilenameForLookup) { llvm::ErrorOr Stat = getUnderlyingFS().status(OriginalFilename); if (!Stat) { + if (!Service.shouldCacheNegativeStats()) + return Stat.getError(); const auto &Entry = getOrEmplaceSharedEntryForFilename(FilenameForLookup, Stat.getError()); return insertLocalEntryForFilename(FilenameForLookup, Entry); @@ -420,7 +447,8 @@ DependencyScanningWorkerFilesystem::getRealPath(const Twine &Path, return HandleCachedRealPath(*RealPath); // If we have the result in the shared cache, cache it locally. - auto &Shard = SharedCache.getShardForFilename(*FilenameForLookup); + auto &Shard = + Service.getSharedCache().getShardForFilename(*FilenameForLookup); if (const auto *ShardRealPath = Shard.findRealPathByFilename(*FilenameForLookup)) { const auto &RealPath = LocalCache.insertRealPathForFilename( diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp index 7f40c99f0728..c2f3cdbb02e3 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -15,7 +15,8 @@ using namespace dependencies; DependencyScanningService::DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS, - std::time_t BuildSessionTimestamp) + std::time_t BuildSessionTimestamp, bool CacheNegativeStats) : Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS), + CacheNegativeStats(CacheNegativeStats), BuildSessionTimestamp(BuildSessionTimestamp) {} diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 9bd85479d981..d9820ca3c584 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -611,8 +611,7 @@ DependencyScanningWorker::DependencyScanningWorker( switch (Service.getMode()) { case ScanningMode::DependencyDirectivesScan: - DepFS = - new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS); + DepFS = new DependencyScanningWorkerFilesystem(Service, FS); BaseFS = DepFS; break; case ScanningMode::CanonicalPreprocessing: diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 44a270d5f7b3..b1495163ccc2 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -657,7 +657,7 @@ void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, P1689ModuleInfo RequiredModule; RequiredModule.ModuleName = Path[0].getIdentifierInfo()->getName().str(); RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; - MDC.RequiredStdCXXModules.push_back(RequiredModule); + MDC.RequiredStdCXXModules.push_back(std::move(RequiredModule)); return; } @@ -920,7 +920,7 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps( void ModuleDepCollectorPP::addOneModuleDep(const Module *M, const ModuleID ID, ModuleDeps &MD) { - MD.ClangModuleDeps.push_back(ID); + MD.ClangModuleDeps.push_back(std::move(ID)); if (MD.IsInStableDirectories) MD.IsInStableDirectories = MDC.ModularDeps[M]->IsInStableDirectories; } diff --git a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp index 710612bef8fd..1013a771d13b 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp @@ -21,6 +21,9 @@ template constexpr To bit_cast(const From &from) { static_assert(sizeof(To) == sizeof(From)); return __builtin_bit_cast(To, from); +#if __x86_64 + // both-note@-2 {{indeterminate value can only initialize an object of type}} +#endif } template @@ -38,11 +41,8 @@ constexpr Init round_trip(const Init &init) { namespace test_long_double { #if __x86_64 -/// FIXME: We could enable this, but since it aborts, it causes the usual mempory leak. -#if 0 -constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // expected-error{{must be initialized by a constant expression}}\ - // expected-note{{in call}} -#endif +constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // both-error{{must be initialized by a constant expression}}\ + // both-note{{in call}} constexpr long double ld = 3.1425926539; struct bytes { diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 21dca15a4577..3b95a8ea4859 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -208,7 +208,7 @@ namespace nan { constexpr double NaN3 = __builtin_nan("foo"); // both-error {{must be initialized by a constant expression}} constexpr float NaN4 = __builtin_nanf(""); - //constexpr long double NaN5 = __builtin_nanf128(""); + constexpr long double NaN5 = __builtin_nanf128(""); /// FIXME: This should be accepted by the current interpreter as well. constexpr char f[] = {'0', 'x', 'A', 'E', '\0'}; @@ -655,8 +655,6 @@ void test_noexcept(int *i) { } // end namespace test_launder -/// FIXME: The commented out tests here use a IntAP value and fail. -/// This currently means we will leak the IntAP value since nothing cleans it up. namespace clz { char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1]; char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1]; @@ -709,7 +707,7 @@ namespace clz { char clz48[__builtin_clzg(1ULL << (BITSIZE(long long) - 1)) == 0 ? 1 : -1]; char clz49[__builtin_clzg(1ULL << (BITSIZE(long long) - 1), 42) == 0 ? 1 : -1]; #ifdef __SIZEOF_INT128__ - // int clz50 = __builtin_clzg((unsigned __int128)0); + int clz50 = __builtin_clzg((unsigned __int128)0); char clz51[__builtin_clzg((unsigned __int128)0, 42) == 42 ? 1 : -1]; char clz52[__builtin_clzg((unsigned __int128)0x1) == BITSIZE(__int128) - 1 ? 1 : -1]; char clz53[__builtin_clzg((unsigned __int128)0x1, 42) == BITSIZE(__int128) - 1 ? 1 : -1]; @@ -717,7 +715,7 @@ namespace clz { char clz55[__builtin_clzg((unsigned __int128)0xf, 42) == BITSIZE(__int128) - 4 ? 1 : -1]; #endif #ifndef __AVR__ - // int clz58 = __builtin_clzg((unsigned _BitInt(128))0); + int clz58 = __builtin_clzg((unsigned _BitInt(128))0); char clz59[__builtin_clzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1]; char clz60[__builtin_clzg((unsigned _BitInt(128))0x1) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1]; char clz61[__builtin_clzg((unsigned _BitInt(128))0x1, 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1]; @@ -775,7 +773,7 @@ namespace ctz { char ctz46[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1)) == BITSIZE(long long) - 1 ? 1 : -1]; char ctz47[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1), 42) == BITSIZE(long long) - 1 ? 1 : -1]; #ifdef __SIZEOF_INT128__ - // int ctz48 = __builtin_ctzg((unsigned __int128)0); + int ctz48 = __builtin_ctzg((unsigned __int128)0); char ctz49[__builtin_ctzg((unsigned __int128)0, 42) == 42 ? 1 : -1]; char ctz50[__builtin_ctzg((unsigned __int128)0x1) == 0 ? 1 : -1]; char ctz51[__builtin_ctzg((unsigned __int128)0x1, 42) == 0 ? 1 : -1]; @@ -785,7 +783,7 @@ namespace ctz { char ctz55[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1), 42) == BITSIZE(__int128) - 1 ? 1 : -1]; #endif #ifndef __AVR__ - // int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0); + int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0); char ctz57[__builtin_ctzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1]; char ctz58[__builtin_ctzg((unsigned _BitInt(128))0x1) == 0 ? 1 : -1]; char ctz59[__builtin_ctzg((unsigned _BitInt(128))0x1, 42) == 0 ? 1 : -1]; @@ -1741,4 +1739,18 @@ namespace WithinLifetime { // both-warning {{expression result unused}} } } + +#ifdef __SIZEOF_INT128__ +namespace I128Mul { + constexpr int mul() { + __int128 A = 10; + __int128 B = 10; + __int128 R; + __builtin_mul_overflow(A, B, &R); + return 1; + } + static_assert(mul() == 1); +} +#endif + #endif diff --git a/clang/test/AST/ByteCode/cxx17.cpp b/clang/test/AST/ByteCode/cxx17.cpp index 08a40e0a9286..0cf3a4f666d6 100644 --- a/clang/test/AST/ByteCode/cxx17.cpp +++ b/clang/test/AST/ByteCode/cxx17.cpp @@ -141,3 +141,11 @@ template constexpr auto c() { } auto y = c<1>(); // both-note {{in instantiation of function template specialization 'c<1>' requested here}} + +namespace NonConstexprStructuredBinding { + void f1() { + int arr[2] = {}; + auto [a, b] = arr; + static_assert(&a != &b); + } +} diff --git a/clang/test/AST/ByteCode/intap.cpp b/clang/test/AST/ByteCode/intap.cpp index 3f952ddf626b..a7e43b34a7d2 100644 --- a/clang/test/AST/ByteCode/intap.cpp +++ b/clang/test/AST/ByteCode/intap.cpp @@ -48,6 +48,13 @@ static_assert(DivA / DivB == 2, ""); constexpr _BitInt(4) DivC = DivA / 0; // both-error {{must be initialized by a constant expression}} \ // both-note {{division by zero}} +constexpr __int128 isMinDiv() { + return __int128{0} / __int128{-1}; +} +static_assert(isMinDiv() == 0, ""); + + + constexpr _BitInt(7) RemA = 47; constexpr _BitInt(6) RemB = 9; static_assert(RemA % RemB == 2, ""); @@ -273,4 +280,18 @@ namespace IncDec { #endif } +#if __cplusplus >= 201402L +const __int128_t a = ( (__int128_t)1 << 64 ); +const _BitInt(72) b = ( 1 << 72 ); // both-warning {{shift count >= width of type}} +constexpr int shifts() { // both-error {{never produces a constant expression}} + (void)(2 >> a); // both-warning {{shift count >= width of type}} \ + // both-note {{shift count 18446744073709551616 >= width of type 'int' (32 bits)}} + (void)(2 >> b); // ref-warning {{shift count is negative}} + (void)(2 << a); // both-warning {{shift count >= width of type}} + (void)(2 << b); // ref-warning {{shift count is negative}} + return 1; +} +#endif + + #endif diff --git a/clang/test/AST/ByteCode/literals.cpp b/clang/test/AST/ByteCode/literals.cpp index 2fa7b69b9347..699746c0b2c4 100644 --- a/clang/test/AST/ByteCode/literals.cpp +++ b/clang/test/AST/ByteCode/literals.cpp @@ -910,7 +910,8 @@ namespace CompoundLiterals { constexpr int f2(int *x =(int[]){1,2,3}) { return x[0]; } - constexpr int g = f2(); // Should evaluate to 1? + // Should evaluate to 1? + constexpr int g = f2(); // #g_decl static_assert(g == 1, ""); // This example should be rejected because the lifetime of the compound @@ -1347,7 +1348,10 @@ namespace NTTP { namespace UnaryOpError { constexpr int foo() { int f = 0; - ++g; // both-error {{use of undeclared identifier 'g'}} + ++g; // both-error {{use of undeclared identifier 'g'}} \ + both-error {{cannot assign to variable 'g' with const-qualified type 'const int'}} \ + both-note@#g_decl {{'CompoundLiterals::g' declared here}} \ + both-note@#g_decl {{variable 'g' declared const here}} return f; } } diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp index 1ee41a98e13b..9c293e5d15fc 100644 --- a/clang/test/AST/ByteCode/new-delete.cpp +++ b/clang/test/AST/ByteCode/new-delete.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -verify=ref,both %s -// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s -// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -verify=ref,both %s +// RUN: %clang_cc1 -verify=expected,both -fexperimental-new-constant-interpreter %s +// RUN: %clang_cc1 -std=c++20 -verify=expected,both -fexperimental-new-constant-interpreter %s +// RUN: %clang_cc1 -std=c++20 -verify=expected,both -triple=i686-linux-gnu -fexperimental-new-constant-interpreter %s +// RUN: %clang_cc1 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,both -triple=i686-linux-gnu %s #if __cplusplus >= 202002L @@ -1012,6 +1012,16 @@ constexpr int no_deallocate_nonalloc = (std::allocator().deallocate((int*)& // both-note {{in call}} \ // both-note {{declared here}} +namespace OpNewNothrow { + constexpr int f() { + int *v = (int*)operator new(sizeof(int), std::align_val_t(2), std::nothrow); // both-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator::allocate' to allocate memory of type 'T'}} + operator delete(v, std::align_val_t(2), std::nothrow); + return 1; + } + static_assert(f()); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} +} + #else /// Make sure we reject this prior to C++20 constexpr int a() { // both-error {{never produces a constant expression}} diff --git a/clang/test/AST/HLSL/vk.spec-constant.usage.hlsl b/clang/test/AST/HLSL/vk.spec-constant.usage.hlsl new file mode 100644 index 000000000000..c0955c1ea7b4 --- /dev/null +++ b/clang/test/AST/HLSL/vk.spec-constant.usage.hlsl @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute -x hlsl -ast-dump -o - %s | FileCheck %s + +// CHECK: VarDecl {{.*}} bool_const 'const hlsl_private bool' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'bool' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool (*)(unsigned int, bool) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'bool (unsigned int, bool) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_bool' 'bool (unsigned int, bool) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +// CHECK-NEXT: CXXBoolLiteralExpr {{.*}} 'bool' true +[[vk::constant_id(1)]] +const bool bool_const = true; + +// CHECK: VarDecl {{.*}} short_const 'const hlsl_private short' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'short' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'short (*)(unsigned int, short) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'short (unsigned int, short) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_short' 'short (unsigned int, short) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'short' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +[[vk::constant_id(2)]] +const short short_const = 4; + +// CHECK: VarDecl {{.*}} int_const 'const hlsl_private int' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(unsigned int, int) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int (unsigned int, int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_int' 'int (unsigned int, int) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3 +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5 +[[vk::constant_id(3)]] +const int int_const = 5; + +// CHECK: VarDecl {{.*}} long_const 'const hlsl_private long long' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'long long' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'long long (*)(unsigned int, long long) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'long long (unsigned int, long long) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_longlong' 'long long (unsigned int, long long) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'long long' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8 +[[vk::constant_id(4)]] +const long long long_const = 8; + +// CHECK: VarDecl {{.*}} ushort_const 'const hlsl_private unsigned short' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'unsigned short' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned short (*)(unsigned int, unsigned short) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned short (unsigned int, unsigned short) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_ushort' 'unsigned short (unsigned int, unsigned short) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned short' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 10 +[[vk::constant_id(5)]] +const unsigned short ushort_const = 10; + +// CHECK: VarDecl {{.*}} uint_const 'const hlsl_private unsigned int' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'unsigned int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int (*)(unsigned int, unsigned int) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int (unsigned int, unsigned int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_uint' 'unsigned int (unsigned int, unsigned int) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 6 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 12 +[[vk::constant_id(6)]] +const unsigned int uint_const = 12; + + +// CHECK: VarDecl {{.*}} ulong_const 'const hlsl_private unsigned long long' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'unsigned long long' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned long long (*)(unsigned int, unsigned long long) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned long long (unsigned int, unsigned long long) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_ulonglong' 'unsigned long long (unsigned int, unsigned long long) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 7 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned long long' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 25 +[[vk::constant_id(7)]] +const unsigned long long ulong_const = 25; + +// CHECK: VarDecl {{.*}} half_const 'const hlsl_private half' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'half' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half (*)(unsigned int, half) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'half (unsigned int, half) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_half' 'half (unsigned int, half) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half' +// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.040000e+01 +[[vk::constant_id(8)]] +const half half_const = 40.4; + +// CHECK: VarDecl {{.*}} float_const 'const hlsl_private float' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'float' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float (*)(unsigned int, float) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float (unsigned int, float) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_float' 'float (unsigned int, float) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 50 +[[vk::constant_id(8)]] +const float float_const = 50; + +// CHECK: VarDecl {{.*}} double_const 'const hlsl_private double' static cinit +// CHECK-NEXT: CallExpr {{.*}} 'double' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double (*)(unsigned int, double) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'double (unsigned int, double) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_double' 'double (unsigned int, double) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 9 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 100 +[[vk::constant_id(9)]] +const double double_const = 100; + +// CHECK: VarDecl {{.*}} enum_const 'const hlsl_private E' static cinit +// CHECK-NEXT: CStyleCastExpr {{.*}} 'E' +// CHECK-NEXT: CallExpr {{.*}} 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(unsigned int, int) noexcept' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int (unsigned int, int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_int' 'int (unsigned int, int) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 10 +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'E' EnumConstant {{.*}} 'e2' 'E' +enum E { + e0 = 10, + e1 = 20, + e2 = 30 +}; + +[[vk::constant_id(10)]] +const E enum_const = e2; + +// CHECK-NOT: CXXRecordDecl {{.*}} implicit struct __cblayout_$Globals definition diff --git a/clang/test/AST/ast-dump-ppc-types.c b/clang/test/AST/ast-dump-ppc-types.c index 26ae5441f20d..1c860c268e0e 100644 --- a/clang/test/AST/ast-dump-ppc-types.c +++ b/clang/test/AST/ast-dump-ppc-types.c @@ -1,9 +1,11 @@ +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu future \ +// RUN: -ast-dump %s | FileCheck %s // RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr10 \ -// RUN: -ast-dump -ast-dump-filter __vector %s | FileCheck %s +// RUN: -ast-dump %s | FileCheck %s // RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr9 \ -// RUN: -ast-dump -ast-dump-filter __vector %s | FileCheck %s +// RUN: -ast-dump %s | FileCheck %s // RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr8 \ -// RUN: -ast-dump -ast-dump-filter __vector %s | FileCheck %s +// RUN: -ast-dump %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump %s | FileCheck %s \ // RUN: --check-prefix=CHECK-X86_64 // RUN: %clang_cc1 -triple arm-unknown-unknown -ast-dump %s | FileCheck %s \ @@ -15,16 +17,21 @@ // are correctly defined. We also added checks on a couple of other targets to // ensure the types are target-dependent. +// CHECK: TypedefDecl {{.*}} implicit __dmr1024 '__dmr1024' +// CHECK: `-BuiltinType {{.*}} '__dmr1024' // CHECK: TypedefDecl {{.*}} implicit __vector_quad '__vector_quad' // CHECK-NEXT: -BuiltinType {{.*}} '__vector_quad' // CHECK: TypedefDecl {{.*}} implicit __vector_pair '__vector_pair' // CHECK-NEXT: -BuiltinType {{.*}} '__vector_pair' +// CHECK-X86_64-NOT: __dmr1024 // CHECK-X86_64-NOT: __vector_quad // CHECK-X86_64-NOT: __vector_pair +// CHECK-ARM-NOT: __dmr1024 // CHECK-ARM-NOT: __vector_quad // CHECK-ARM-NOT: __vector_pair +// CHECK-RISCV64-NOT: __dmr1024 // CHECK-RISCV64-NOT: __vector_quad // CHECK-RISCV64-NOT: __vector_pair diff --git a/clang/test/AST/ast-dump-recovery.c b/clang/test/AST/ast-dump-recovery.c index 68d3f182dd9f..09a03fb9d6fd 100644 --- a/clang/test/AST/ast-dump-recovery.c +++ b/clang/test/AST/ast-dump-recovery.c @@ -23,13 +23,6 @@ int postfix_inc = a++; // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' int unary_address = &(a + 1); -// CHECK: VarDecl {{.*}} ternary 'int' cinit -// CHECK-NEXT: `-ConditionalOperator {{.*}} -// CHECK-NEXT: |-DeclRefExpr {{.*}} 'a' -// CHECK-NEXT: |-RecoveryExpr {{.*}} -// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a' -int ternary = a ? undef : a; - void test1() { // CHECK: `-RecoveryExpr {{.*}} contains-errors // CHECK-NEXT: `-DeclRefExpr {{.*}} 'a' 'const int' @@ -91,12 +84,6 @@ void test3() { // CHECK-NEXT: | `-DeclRefExpr {{.*}} '__builtin_classify_type' // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 (*__builtin_classify_type)(1); - - extern void ext(); - // CHECK: CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-DeclRefExpr {{.*}} 'ext' - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' - ext(undef_var); } // Verify no crash. @@ -110,23 +97,6 @@ void test4() { }; } -// Verify no crash -void test5_GH62711() { - // CHECK: VAArgExpr {{.*}} 'int' contains-errors - // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '' contains-errors - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' contains-errors - if (__builtin_va_arg(undef, int) << 1); -} - -void test6_GH50244() { - double array[16]; - // CHECK: UnaryExprOrTypeTraitExpr {{.*}} 'unsigned long' contains-errors sizeof - // CHECK-NEXT: `-CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-DeclRefExpr {{.*}} 'int ()' - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' - sizeof array / sizeof foo(undef); -} - // No crash on DeclRefExpr that refers to ValueDecl with invalid initializers. void test7() { int b[] = {""()}; diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index b8195950f2fa..a8e30f1759e9 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -9,28 +9,6 @@ int some_func(int *); // CHECK-NEXT: `-IntegerLiteral {{.*}} 123 // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int invalid_call = some_func(123); -void test_invalid_call_1(int s) { - // CHECK: CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: |-RecoveryExpr {{.*}} - // CHECK-NEXT: `-BinaryOperator {{.*}} - // CHECK-NEXT: |-RecoveryExpr {{.*}} - // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 - some_func(undef1, undef2+1); - - // CHECK: BinaryOperator {{.*}} '' contains-errors '=' - // CHECK-NEXT: |-DeclRefExpr {{.*}} 's' - // CHECK-NEXT: `-CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - s = some_func(undef1); - - // CHECK: VarDecl {{.*}} var 'int' - // CHECK-NEXT: `-CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - int var = some_func(undef1); -} int some_func2(int a, int b); void test_invalid_call_2() { @@ -63,22 +41,6 @@ int ambig_func(float); // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int ambig_call = ambig_func(123); -// CHECK: VarDecl {{.*}} unresolved_call1 -// CHECK-NEXT:`-RecoveryExpr {{.*}} '' contains-errors -// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'bar' -// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors -int unresolved_call1 = bar(); - -// CHECK: VarDecl {{.*}} unresolved_call2 -// CHECK-NEXT:`-CallExpr {{.*}} contains-errors -// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'bar' -// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors -// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} 'baz' -// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors -// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'qux' -// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors -int unresolved_call2 = bar(baz(), qux()); - constexpr int a = 10; // CHECK: VarDecl {{.*}} postfix_inc @@ -177,11 +139,6 @@ void test2(Foo2 f) { f.overload(1); } -// CHECK: |-AlignedAttr {{.*}} alignas -// CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors -// CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid' -struct alignas(invalid()) Aligned {}; - auto f(); int f(double); // CHECK: VarDecl {{.*}} unknown_type_call 'int' @@ -203,16 +160,6 @@ void InvalidInitalizer(int x) { // CHECK-NEXT: `-InitListExpr // CHECK-NEDT: `-DeclRefExpr {{.*}} 'x' Bar a3{x}; - // CHECK: `-VarDecl {{.*}} a4 'Bar' - // CHECK-NEXT: `-ParenListExpr {{.*}} 'NULL TYPE' contains-errors - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - Bar a4(invalid()); - // CHECK: `-VarDecl {{.*}} a5 'Bar' - // CHECK-NEXT: `-InitListExpr {{.*}} contains-errors - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - Bar a5{invalid()}; // CHECK: `-VarDecl {{.*}} b1 'Bar' // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors @@ -231,51 +178,11 @@ void InvalidInitalizer(int x) { // CHECK-NEXT: `-InitListExpr {{.*}} 'void' // CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int' Bar b4 = Bar{x}; - // CHECK: `-VarDecl {{.*}} b5 'Bar' - // CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar' - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - Bar b5 = Bar(invalid()); - // CHECK: `-VarDecl {{.*}} b6 'Bar' - // CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar' - // CHECK-NEXT: `-InitListExpr {{.*}} contains-errors - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - Bar b6 = Bar{invalid()}; // CHECK: RecoveryExpr {{.*}} 'Bar' contains-errors // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 Bar(1); - - // CHECK: `-VarDecl {{.*}} var1 - // CHECK-NEXT: `-BinaryOperator {{.*}} '' contains-errors - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 - int var1 = undef + 1; } -void InitializerForAuto() { - // CHECK: `-VarDecl {{.*}} invalid a 'auto' - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - auto a = invalid(); - - // CHECK: `-VarDecl {{.*}} invalid b 'auto' - // CHECK-NEXT: `-CallExpr {{.*}} '' contains-errors - // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' - auto b = some_func(invalid()); - - decltype(ned); - // very bad initailizer: there is an unresolved typo expr internally, we just - // drop it. - // CHECK: `-VarDecl {{.*}} invalid unresolved_typo 'auto' - auto unresolved_typo = gned.*[] {}; -} - -// Verified that the generated call operator is invalid. -// CHECK: |-CXXMethodDecl {{.*}} invalid operator() 'auto () const -> auto' -using Escape = decltype([] { return undef(); }()); // CHECK: VarDecl {{.*}} NoCrashOnInvalidInitList // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors lvalue @@ -301,56 +208,8 @@ void ValueCategory() { xvalue(); // call to a function (rvalue reference return type) yields an xvalue. } -void InvalidCondition() { - // CHECK: IfStmt {{.*}} - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} - if (invalid()) {} - - // CHECK: WhileStmt {{.*}} - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} - while (invalid()) {} - - // CHECK: SwitchStmt {{.*}} - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} - switch(invalid()) { - case 1: - break; - } - // FIXME: figure out why the type of ConditionalOperator is not int. - // CHECK: ConditionalOperator {{.*}} '' contains-errors - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} - // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 - // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 - invalid() ? 1 : 2; -} - void CtorInitializer() { struct S{int m}; - class MemberInit { - int x, y, z; - S s; - MemberInit() : x(invalid), y(invalid, invalid), z(invalid()), s(1,2) {} - // CHECK: CXXConstructorDecl {{.*}} MemberInit 'void ()' - // CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'x' 'int' - // CHECK-NEXT: | `-ParenListExpr - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' - // CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'y' 'int' - // CHECK-NEXT: | `-ParenListExpr - // CHECK-NEXT: | |-RecoveryExpr {{.*}} '' - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' - // CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'z' 'int' - // CHECK-NEXT: | `-ParenListExpr - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' - // CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} '' - // CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 's' 'S' - // CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S' contains-errors - // CHECK-NEXT: | |-IntegerLiteral {{.*}} 1 - // CHECK-NEXT: | `-IntegerLiteral {{.*}} 2 - }; class BaseInit : S { BaseInit(float) : S("no match") {} // CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (float)' @@ -358,13 +217,6 @@ void CtorInitializer() { // CHECK-NEXT: |-CXXCtorInitializer 'S' // CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S' // CHECK-NEXT: | `-StringLiteral - - BaseInit(double) : S(invalid) {} - // CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (double)' - // CHECK-NEXT: |-ParmVarDecl - // CHECK-NEXT: |-CXXCtorInitializer 'S' - // CHECK-NEXT: | `-ParenListExpr - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' }; class DelegatingInit { DelegatingInit(float) : DelegatingInit("no match") {} @@ -373,13 +225,6 @@ void CtorInitializer() { // CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit' // CHECK-NEXT: | `-RecoveryExpr {{.*}} 'DelegatingInit' // CHECK-NEXT: | `-StringLiteral - - DelegatingInit(double) : DelegatingInit(invalid) {} - // CHECK: CXXConstructorDecl {{.*}} DelegatingInit 'void (double)' - // CHECK-NEXT: |-ParmVarDecl - // CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit' - // CHECK-NEXT: | `-ParenListExpr - // CHECK-NEXT: | `-RecoveryExpr {{.*}} '' }; } @@ -423,65 +268,6 @@ void returnInitListFromVoid() { // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 8 } -void RecoveryExprForInvalidDecls(Unknown InvalidDecl) { - InvalidDecl + 1; - // CHECK: BinaryOperator {{.*}} - // CHECK-NEXT: |-RecoveryExpr {{.*}} '' - // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'InvalidDecl' 'int' - // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 - InvalidDecl(); - // CHECK: CallExpr {{.*}} - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' -} - -void InitializerOfInvalidDecl() { - int ValidDecl; - Unkown InvalidDecl = ValidDecl; - // CHECK: VarDecl {{.*}} invalid InvalidDecl - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'ValidDecl' - - Unknown InvalidDeclWithInvalidInit = Invalid; - // CHECK: VarDecl {{.*}} invalid InvalidDeclWithInvalidInit - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NOT: `-TypoExpr -} - -void RecoverToAnInvalidDecl() { - Unknown* foo; // invalid decl - goo; // the typo was correct to the invalid foo. - // Verify that RecoveryExpr has an inner DeclRefExpr. - // CHECK: RecoveryExpr {{.*}} '' contains-errors lvalue - // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *' -} - -void RecoveryToDoWhileStmtCond() { - // CHECK: FunctionDecl {{.*}} RecoveryToDoWhileStmtCond - // CHECK: `-DoStmt {{.*}} - // CHECK-NEXT: |-CompoundStmt {{.*}} - // CHECK-NEXT: `-BinaryOperator {{.*}} '' contains-errors '<' - // CHECK-NEXT: |-BinaryOperator {{.*}} '' contains-errors '+' - // CHECK-NEXT: | |-RecoveryExpr {{.*}} '' contains-errors lvalue - // CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 - // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 10 - do {} while (some_invalid_val + 1 < 10); -} - -void RecoveryForStmtCond() { - // CHECK:FunctionDecl {{.*}} RecoveryForStmtCond - // CHECK-NEXT:`-CompoundStmt {{.*}} - // CHECK-NEXT: `-ForStmt {{.*}} - // CHECK-NEXT: |-DeclStmt {{.*}} - // CHECK-NEXT: | `-VarDecl {{.*}} - // CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0 - // CHECK-NEXT: |-<<>> - // CHECK-NEXT: |-RecoveryExpr {{.*}} 'bool' contains-errors - // CHECK-NEXT: |-UnaryOperator {{.*}} 'int' lvalue prefix '++' - // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'i' 'int' - // CHECK-NEXT: `-CompoundStmt {{.*}} - for (int i = 0; i < invalid; ++i) {} -} - // Fix crash issue https://github.com/llvm/llvm-project/issues/112560. // Make sure clang compiles the following code without crashing: diff --git a/clang/test/AST/ast-dump-recovery.m b/clang/test/AST/ast-dump-recovery.m deleted file mode 100644 index 37fa8045c0b9..000000000000 --- a/clang/test/AST/ast-dump-recovery.m +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s - -@interface Foo -- (void)method:(int)n; -@end - -void k(Foo *foo) { - // CHECK: ObjCMessageExpr {{.*}} 'void' contains-errors - // CHECK-CHECK: |-ImplicitCastExpr {{.*}} 'Foo *' - // CHECK-CHECK: | `-DeclRefExpr {{.*}} 'foo' - // CHECK-CHECK: `-RecoveryExpr {{.*}} - [foo method:undef]; - - // CHECK: ImplicitCastExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors - // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' - foo.undef; -} - -// CHECK: |-VarDecl {{.*}} 'int (^)()' cinit -// CHECK-NEXT: | `-RecoveryExpr {{.*}} ' (^)(void)' contains-errors lvalue -// CHECK-NEXT: | `-BlockExpr {{.*}} ' (^)(void)' -// CHECK-NEXT: | `-BlockDecl {{.*}} invalid -int (^gh63863)() = ^() { - return undef; -}; - -// CHECK: `-BlockExpr {{.*}} 'int (^)(int, int)' -// CHECK-NEXT: `-BlockDecl {{.*}} invalid -int (^gh64005)(int, int) = ^(int, undefined b) { - return 1; -}; diff --git a/clang/test/Analysis/NewDelete-checker-test.cpp b/clang/test/Analysis/NewDelete-checker-test.cpp index 06754f669b1e..da0eef7c52bd 100644 --- a/clang/test/Analysis/NewDelete-checker-test.cpp +++ b/clang/test/Analysis/NewDelete-checker-test.cpp @@ -26,9 +26,10 @@ // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks // // RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \ -// RUN: -verify=expected,leak \ +// RUN: -verify=expected,leak,inspection \ // RUN: -analyzer-checker=core \ -// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks +// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \ +// RUN: -analyzer-checker=debug.ExprInspection #include "Inputs/system-header-simulator-cxx.h" @@ -63,6 +64,39 @@ void testGlobalNoThrowPlacementExprNewBeforeOverload() { int *p = new(std::nothrow) int; } // leak-warning{{Potential leak of memory pointed to by 'p'}} +//----- Standard pointer placement operators +void testGlobalPointerPlacementNew() { + int i; + void *p1 = operator new(0, &i); // no leak: placement new never allocates + void *p2 = operator new[](0, &i); // no leak + int *p3 = new(&i) int; // no leak + int *p4 = new(&i) int[0]; // no leak +} + +template +void clang_analyzer_dump(T x); + +void testPlacementNewBufValue() { + int i = 10; + int *p = new(&i) int; + clang_analyzer_dump(p); // inspection-warning{{&i}} + clang_analyzer_dump(*p); // inspection-warning{{10}} +} + +void testPlacementNewBufValueExplicitOp() { + int i = 10; + int *p = (int*)operator new(sizeof(int), &i); + clang_analyzer_dump(p); // inspection-warning{{&i}} + clang_analyzer_dump(*p); // inspection-warning{{10}} +} + +void testPlacementArrNewBufValueExplicitArrOp() { + int i = 10; + int *p = (int*)operator new[](sizeof(int), &i); + clang_analyzer_dump(p); // inspection-warning{{&i}} + clang_analyzer_dump(*p); // inspection-warning{{10}} +} + //----- Other cases void testNewMemoryIsInHeap() { int *p = new int; diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index 66b9be9795f1..78ee00deea18 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -34,7 +34,6 @@ // CHECK-NEXT: core.uninitialized.CapturedBlockVariable // CHECK-NEXT: core.uninitialized.UndefReturn // CHECK-NEXT: deadcode.DeadStores -// CHECK-NEXT: nullability.NullabilityBase // CHECK-NEXT: nullability.NullPassedToNonnull // CHECK-NEXT: nullability.NullReturnedFromNonnull // CHECK-NEXT: security.insecureAPI.SecuritySyntaxChecker diff --git a/clang/test/Analysis/bitint-z3.c b/clang/test/Analysis/bitint-z3.c new file mode 100644 index 000000000000..4cb97f9de829 --- /dev/null +++ b/clang/test/Analysis/bitint-z3.c @@ -0,0 +1,22 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -w \ +// RUN: -analyzer-config crosscheck-with-z3=true -verify %s +// REQUIRES: z3 + +// Previously these tests were crashing because the SMTConv layer did not +// comprehend the _BitInt types. + +void clang_analyzer_warnIfReached(); + +void c(int b, _BitInt(35) a) { + int d = 0; + if (a) + b = d; + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} +} + +void f(int *d, _BitInt(3) e) { + int g; + d = &g; + e ?: 0; + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} +} diff --git a/clang/test/Analysis/bugfix-124477.m b/clang/test/Analysis/bugfix-124477.m index 80820f4c9344..8bb0196b2f9b 100644 --- a/clang/test/Analysis/bugfix-124477.m +++ b/clang/test/Analysis/bugfix-124477.m @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling,nullability.NullableDereferenced,nullability.NullabilityBase -x objective-c %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling,nullability.NullableDereferenced -x objective-c %s /* This test is reduced from a static analyzer crash. The bug causing the crash is explained in #124477. It can only be triggered in some diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c index 8c6078a49c23..7f9c9ff4c9fd 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c +++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c @@ -42,7 +42,6 @@ // CHECK-NEXT: core.uninitialized.CapturedBlockVariable // CHECK-NEXT: core.uninitialized.UndefReturn // CHECK-NEXT: deadcode.DeadStores -// CHECK-NEXT: nullability.NullabilityBase // CHECK-NEXT: nullability.NullPassedToNonnull // CHECK-NEXT: nullability.NullReturnedFromNonnull // CHECK-NEXT: security.insecureAPI.SecuritySyntaxChecker diff --git a/clang/test/Analysis/taint-generic.c b/clang/test/Analysis/taint-generic.c index 3c520612c5d9..9d6d2942df4a 100644 --- a/clang/test/Analysis/taint-generic.c +++ b/clang/test/Analysis/taint-generic.c @@ -412,6 +412,19 @@ int testTaintedDivFP(void) { return 5/x; // x cannot be 0, so no tainted warning either } +void clang_analyzer_warnIfReached(); + +int testTaintDivZeroNonfatal() { + int x; + scanf("%d", &x); + int y = 5/x; // expected-warning {{Division by a tainted value, possibly zero}} + if (x == 0) + clang_analyzer_warnIfReached(); + else + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} + return y; +} + // Zero-sized VLAs. void testTaintedVLASize(void) { int x; diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index 7b90c1682ec4..26e172a00645 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -473,3 +473,26 @@ void func10(int *a) { // OGCG: %[[ELE:.*]] = getelementptr inbounds i32, ptr %[[TMP_1]], i64 5 // OGCG: %[[TMP_2:.*]] = load i32, ptr %[[ELE]], align 4 // OGCG: store i32 %[[TMP_2]], ptr %[[INIT]], align 4 + +void func11() { int _Complex a[4]; } + +// CIR: %[[ARR:.*]] = cir.alloca !cir.array x 4>, !cir.ptr x 4>>, ["a"] + +// LLVM: %[[ARR:.*]] = alloca [4 x { i32, i32 }], i64 1, align 16 + +// OGCG: %[[ARR:.*]] = alloca [4 x { i32, i32 }], align 16 + +void func12() { + struct Point { + int x; + int y; + }; + + Point a[4]; +} + +// CIR: %[[ARR:.*]] = cir.alloca !cir.array, !cir.ptr>, ["a"] + +// LLVM: %[[ARR:.*]] = alloca [4 x %struct.Point], i64 1, align 16 + +// OGCG: %[[ARR:.*]] = alloca [4 x %struct.Point], align 16 diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c index abc1a45fd433..7ff73ee95f79 100644 --- a/clang/test/CIR/CodeGen/basic.c +++ b/clang/test/CIR/CodeGen/basic.c @@ -309,3 +309,17 @@ size_type max_size(void) { // CHECK: %6 = cir.load{{.*}} %0 : !cir.ptr, !u64i // CHECK: cir.return %6 : !u64i // CHECK: } + +void test_char_literal() { + char c; + c = 'X'; +} + +// CIR: cir.func @test_char_literal +// CIR: cir.const #cir.int<88> + +// LLVM: define void @test_char_literal() +// LLVM: store i8 88, ptr %{{.*}}, align 1 + +// OGCG: define{{.*}} void @test_char_literal() +// OGCG: store i8 88, ptr %{{.*}}, align 1 diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c new file mode 100644 index 000000000000..ff5c6bc1787b --- /dev/null +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +typedef struct { + char a, b, c; + unsigned bits : 3; + unsigned more_bits : 4; + unsigned still_more_bits : 7; +} A; + +// CIR-DAG: !rec_A = !cir.record}> +// LLVM-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }> +// OGCG-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }> + +typedef struct { + int a : 4; + int b : 5; + int c; +} D; + +// CIR-DAG: !rec_D = !cir.record +// LLVM-DAG: %struct.D = type { i16, i32 } +// OGCG-DAG: %struct.D = type { i16, i32 } + +typedef struct { + int a : 4; + int b : 27; + int c : 17; + int d : 2; + int e : 15; + unsigned f; // type other than int above, not a bitfield +} S; +// CIR-DAG: !rec_S = !cir.record +// LLVM-DAG: %struct.S = type { i64, i16, i32 } +// OGCG-DAG: %struct.S = type { i64, i16, i32 } + +typedef struct { + int a : 3; // one bitfield with size < 8 + unsigned b; +} T; + +// CIR-DAG: !rec_T = !cir.record +// LLVM-DAG: %struct.T = type { i8, i32 } +// OGCG-DAG: %struct.T = type { i8, i32 } + +typedef struct { + char a; + char b; + char c; + + // startOffset 24 bits, new storage from here + int d: 2; + int e: 2; + int f: 4; + int g: 25; + int h: 3; + int i: 4; + int j: 3; + int k: 8; + + int l: 14; +} U; + +// CIR-DAG: !rec_U = !cir.record +// LLVM-DAG: %struct.U = type <{ i8, i8, i8, i8, i64 }> +// OGCG-DAG: %struct.U = type <{ i8, i8, i8, i8, i64 }> + +void def() { + A a; + D d; + S s; + T t; + U u; +} diff --git a/clang/test/CIR/CodeGen/bitfields.cpp b/clang/test/CIR/CodeGen/bitfields.cpp new file mode 100644 index 000000000000..762d24988474 --- /dev/null +++ b/clang/test/CIR/CodeGen/bitfields.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +typedef struct { + int a : 4; + int b : 27; + int c : 17; + int d : 2; + int e : 15; + unsigned f; // type other than int above, not a bitfield +} S; +// CIR-DAG: !rec_S = !cir.record +// LLVM-DAG: %struct.S = type { i64, i16, i32 } +// OGCG-DAG: %struct.S = type { i64, i16, i32 } + +typedef struct { + int a : 3; // one bitfield with size < 8 + unsigned b; +} T; + +// CIR-DAG: !rec_T = !cir.record +// LLVM-DAG: %struct.T = type { i8, i32 } +// OGCG-DAG: %struct.T = type { i8, i32 } + +void def() { + S s; + T t; +} diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp new file mode 100644 index 000000000000..0a2226a2cc59 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin_call.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +constexpr extern int cx_var = __builtin_is_constant_evaluated(); + +// CIR: cir.global {{.*}} @cx_var = #cir.int<1> : !s32i +// LLVM: @cx_var = {{.*}} i32 1 +// OGCG: @cx_var = {{.*}} i32 1 + +constexpr extern float cx_var_single = __builtin_huge_valf(); + +// CIR: cir.global {{.*}} @cx_var_single = #cir.fp<0x7F800000> : !cir.float +// LLVM: @cx_var_single = {{.*}} float 0x7FF0000000000000 +// OGCG: @cx_var_single = {{.*}} float 0x7FF0000000000000 + +constexpr extern long double cx_var_ld = __builtin_huge_vall(); + +// CIR: cir.global {{.*}} @cx_var_ld = #cir.fp<0x7FFF8000000000000000> : !cir.long_double +// LLVM: @cx_var_ld = {{.*}} x86_fp80 0xK7FFF8000000000000000 +// OGCG: @cx_var_ld = {{.*}} x86_fp80 0xK7FFF8000000000000000 + +int is_constant_evaluated() { + return __builtin_is_constant_evaluated(); +} + +// CIR: cir.func @_Z21is_constant_evaluatedv() -> !s32i +// CIR: %[[ZERO:.+]] = cir.const #cir.int<0> + +// LLVM: define {{.*}}i32 @_Z21is_constant_evaluatedv() +// LLVM: %[[MEM:.+]] = alloca i32 +// LLVM: store i32 0, ptr %[[MEM]] +// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[MEM]] +// LLVM: ret i32 %[[RETVAL]] +// LLVM: } + +// OGCG: define {{.*}}i32 @_Z21is_constant_evaluatedv() +// OGCG: ret i32 0 +// OGCG: } + +long double constant_fp_builtin_ld() { + return __builtin_fabsl(-0.1L); +} + +// CIR: cir.func @_Z22constant_fp_builtin_ldv() -> !cir.long_double +// CIR: %[[PONE:.+]] = cir.const #cir.fp<1.000000e-01> : !cir.long_double + +// LLVM: define {{.*}}x86_fp80 @_Z22constant_fp_builtin_ldv() +// LLVM: %[[MEM:.+]] = alloca x86_fp80 +// LLVM: store x86_fp80 0xK3FFBCCCCCCCCCCCCCCCD, ptr %[[MEM]] +// LLVM: %[[RETVAL:.+]] = load x86_fp80, ptr %[[MEM]] +// LLVM: ret x86_fp80 %[[RETVAL]] +// LLVM: } + +// OGCG: define {{.*}}x86_fp80 @_Z22constant_fp_builtin_ldv() +// OGCG: ret x86_fp80 0xK3FFBCCCCCCCCCCCCCCCD +// OGCG: } + +float constant_fp_builtin_single() { + return __builtin_fabsf(-0.1f); +} + +// CIR: cir.func @_Z26constant_fp_builtin_singlev() -> !cir.float +// CIR: %[[PONE:.+]] = cir.const #cir.fp<1.000000e-01> : !cir.float + +// LLVM: define {{.*}}float @_Z26constant_fp_builtin_singlev() +// LLVM: %[[MEM:.+]] = alloca float +// LLVM: store float 0x3FB99999A0000000, ptr %[[MEM]] +// LLVM: %[[RETVAL:.+]] = load float, ptr %[[MEM]] +// LLVM: ret float %[[RETVAL]] +// LLVM: } + +// OGCG: define {{.*}}float @_Z26constant_fp_builtin_singlev() +// OGCG: ret float 0x3FB99999A0000000 +// OGCG: } + +void library_builtins() { + __builtin_printf(nullptr); + __builtin_abort(); +} + +// CIR: cir.func @_Z16library_builtinsv() { +// CIR: %[[NULL:.+]] = cir.const #cir.ptr : !cir.ptr +// CIR: cir.call @printf(%[[NULL]]) : (!cir.ptr) -> !s32i +// CIR: cir.call @abort() : () -> () + +// LLVM: define void @_Z16library_builtinsv() +// LLVM: call i32 (ptr, ...) @printf(ptr null) +// LLVM: call void @abort() + +// OGCG: define dso_local void @_Z16library_builtinsv() +// OGCG: call i32 (ptr, ...) @printf(ptr noundef null) +// OGCG: call void @abort() + +void assume(bool arg) { + __builtin_assume(arg); +} + +// CIR: cir.func @_Z6assumeb +// CIR: cir.assume %{{.+}} : !cir.bool +// CIR: } + +// LLVM: define void @_Z6assumeb +// LLVM: call void @llvm.assume(i1 %{{.+}}) +// LLVM: } + +// OGCG: define {{.*}}void @_Z6assumeb +// OGCG: call void @llvm.assume(i1 %{{.+}}) +// OGCG: } diff --git a/clang/test/CIR/CodeGen/builtin_printf.cpp b/clang/test/CIR/CodeGen/builtin_printf.cpp new file mode 100644 index 000000000000..366e474c2b09 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin_printf.cpp @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// CIR: cir.global "private" cir_private dsolocal @".str" = #cir.const_array<"%s\00" : !cir.array> : !cir.array +// CIR: cir.global "private" cir_private dsolocal @".str.1" = #cir.const_array<"%s %d\0A\00" : !cir.array> : !cir.array +// LLVM: @.str = private global [3 x i8] c"%s\00" +// LLVM: @.str.1 = private global [7 x i8] c"%s %d\0A\00" +// OGCG: @.str = private unnamed_addr constant [3 x i8] c"%s\00" +// OGCG: @.str.1 = private unnamed_addr constant [7 x i8] c"%s %d\0A\00" + +void func(char const * const str, int i) { + __builtin_printf(nullptr); + __builtin_printf("%s", str); + __builtin_printf("%s %d\n", str, i); +} + +// CIR: cir.func @printf(!cir.ptr, ...) -> !s32i + +// CIR: cir.func @_Z4funcPKci(%[[arg0:.+]]: !cir.ptr{{.*}}, %[[arg1:.+]]: !s32i{{.*}}) { +// CIR: %[[str_ptr:.+]] = cir.alloca !cir.ptr, !cir.ptr>, ["str", init, const] +// CIR: %[[i_ptr:.+]] = cir.alloca !s32i, !cir.ptr, ["i", init] +// CIR: cir.store %[[arg0]], %[[str_ptr]] : !cir.ptr, !cir.ptr> +// CIR: cir.store %[[arg1]], %[[i_ptr]] : !s32i, !cir.ptr +// CIR: %[[null_ptr:.+]] = cir.const #cir.ptr : !cir.ptr +// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) : (!cir.ptr) -> !s32i +// CIR: %[[str_fmt_global:.+]] = cir.get_global @".str" : !cir.ptr> +// CIR: %[[str_fmt_ptr:.+]] = cir.cast(array_to_ptrdecay, %[[str_fmt_global]] : !cir.ptr>), !cir.ptr +// CIR: %[[str_val:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr>, !cir.ptr +// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) : (!cir.ptr, !cir.ptr) -> !s32i +// CIR: %[[full_fmt_global:.+]] = cir.get_global @".str.1" : !cir.ptr> +// CIR: %[[full_fmt_ptr:.+]] = cir.cast(array_to_ptrdecay, %[[full_fmt_global]] : !cir.ptr>), !cir.ptr +// CIR: %[[str_val2:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr>, !cir.ptr +// CIR: %[[i_val:.+]] = cir.load{{.*}} %[[i_ptr]] : !cir.ptr, !s32i +// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) : (!cir.ptr, !cir.ptr, !s32i) -> !s32i +// CIR: cir.return + +// LLVM: define void @_Z4funcPKci(ptr %[[arg0:.+]], i32 %[[arg1:.+]]) +// LLVM: %[[str_ptr:.+]] = alloca ptr +// LLVM: %[[i_ptr:.+]] = alloca i32 +// LLVM: store ptr %[[arg0]], ptr %[[str_ptr]]{{.*}} +// LLVM: store i32 %[[arg1]], ptr %[[i_ptr]]{{.*}} +// LLVM: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr null) +// LLVM: %[[str_val:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} +// LLVM: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr @.str, ptr %[[str_val]]) +// LLVM: %[[str_val2:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} +// LLVM: %[[i_val:.+]] = load i32, ptr %[[i_ptr]]{{.*}} +// LLVM: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr @.str.1, ptr %[[str_val2]], i32 %[[i_val]]) +// LLVM: ret void + +// OGCG: define dso_local void @_Z4funcPKci(ptr noundef %[[arg0:.+]], i32 noundef %[[arg1:.+]]) +// OGCG: %[[str_ptr:.+]] = alloca ptr +// OGCG: %[[i_ptr:.+]] = alloca i32 +// OGCG: store ptr %[[arg0]], ptr %[[str_ptr]]{{.*}} +// OGCG: store i32 %[[arg1]], ptr %[[i_ptr]]{{.*}} +// OGCG: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr noundef null) +// OGCG: %[[str_val:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} +// OGCG: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %[[str_val]]) +// OGCG: %[[str_val2:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} +// OGCG: %[[i_val:.+]] = load i32, ptr %[[i_ptr]]{{.*}} +// OGCG: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str.1, ptr noundef %[[str_val2]], i32 noundef %[[i_val]]) +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c new file mode 100644 index 000000000000..f6aa41df7439 --- /dev/null +++ b/clang/test/CIR/CodeGen/call.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct S { + int x; + int y; +}; + +void f1(struct S); +void f2() { + struct S s; + f1(s); +} + +// CIR-LABEL: cir.func @f2() +// CIR: %[[S:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !rec_S +// CIR-NEXT: cir.call @f1(%[[S]]) : (!rec_S) -> () + +// LLVM-LABEL: define void @f2() +// LLVM: %[[S:.+]] = load %struct.S, ptr %{{.+}}, align 4 +// LLVM-NEXT: call void @f1(%struct.S %[[S]]) + +// OGCG-LABEL: define dso_local void @f2() +// OGCG: %[[S:.+]] = load i64, ptr %{{.+}}, align 4 +// OGCG-NEXT: call void @f1(i64 %[[S]]) + +struct S f3(); +void f4() { + struct S s = f3(); +} + +// CIR-LABEL: cir.func @f4() { +// CIR: %[[S:.+]] = cir.call @f3() : () -> !rec_S +// CIR-NEXT: cir.store align(4) %[[S]], %{{.+}} : !rec_S, !cir.ptr + +// LLVM-LABEL: define void @f4() { +// LLVM: %[[S:.+]] = call %struct.S (...) @f3() +// LLVM-NEXT: store %struct.S %[[S]], ptr %{{.+}}, align 4 + +// OGCG-LABEL: define dso_local void @f4() #0 { +// OGCG: %[[S:.+]] = call i64 (...) @f3() +// OGCG-NEXT: store i64 %[[S]], ptr %{{.+}}, align 4 + +struct Big { + int data[10]; +}; + +void f5(struct Big); +struct Big f6(); + +void f7() { + struct Big b; + f5(b); +} + +// CIR-LABEL: cir.func @f7() +// CIR: %[[B:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !rec_Big +// CIR-NEXT: cir.call @f5(%[[B]]) : (!rec_Big) -> () + +// LLVM-LABEL: define void @f7() { +// LLVM: %[[B:.+]] = load %struct.Big, ptr %{{.+}}, align 4 +// LLVM-NEXT: call void @f5(%struct.Big %[[B]]) + +// OGCG-LABEL: define dso_local void @f7() #0 { +// OGCG: %[[B:.+]] = alloca %struct.Big, align 8 +// OGCG-NEXT: call void @f5(ptr noundef byval(%struct.Big) align 8 %[[B]]) + +void f8() { + struct Big b = f6(); +} + +// CIR-LABEL: cir.func @f8() +// CIR: %[[B:.+]] = cir.call @f6() : () -> !rec_Big +// CIR: cir.store align(4) %[[B]], %{{.+}} : !rec_Big, !cir.ptr + +// LLVM-LABEL: define void @f8() { +// LLVM: %[[B:.+]] = call %struct.Big (...) @f6() +// LLVM-NEXT: store %struct.Big %[[B]], ptr %{{.+}}, align 4 + +// OGCG-LABEL: define dso_local void @f8() #0 { +// OGCG: %[[B:.+]] = alloca %struct.Big, align 4 +// OGCG-NEXT: call void (ptr, ...) @f6(ptr dead_on_unwind writable sret(%struct.Big) align 4 %[[B]]) + +void f9() { + f1(f3()); +} + +// CIR-LABEL: cir.func @f9() +// CIR: %[[SLOT:.+]] = cir.alloca !rec_S, !cir.ptr, ["agg.tmp0"] {alignment = 4 : i64} +// CIR-NEXT: %[[RET:.+]] = cir.call @f3() : () -> !rec_S +// CIR-NEXT: cir.store align(4) %[[RET]], %[[SLOT]] : !rec_S, !cir.ptr +// CIR-NEXT: %[[ARG:.+]] = cir.load align(4) %[[SLOT]] : !cir.ptr, !rec_S +// CIR-NEXT: cir.call @f1(%[[ARG]]) : (!rec_S) -> () + +// LLVM-LABEL: define void @f9() { +// LLVM: %[[SLOT:.+]] = alloca %struct.S, i64 1, align 4 +// LLVM-NEXT: %[[RET:.+]] = call %struct.S (...) @f3() +// LLVM-NEXT: store %struct.S %[[RET]], ptr %[[SLOT]], align 4 +// LLVM-NEXT: %[[ARG:.+]] = load %struct.S, ptr %[[SLOT]], align 4 +// LLVM-NEXT: call void @f1(%struct.S %[[ARG]]) + +// OGCG-LABEL: define dso_local void @f9() #0 { +// OGCG: %[[SLOT:.+]] = alloca %struct.S, align 4 +// OGCG-NEXT: %[[RET:.+]] = call i64 (...) @f3() +// OGCG-NEXT: store i64 %[[RET]], ptr %[[SLOT]], align 4 +// OGCG-NEXT: %[[ARG:.+]] = load i64, ptr %[[SLOT]], align 4 +// OGCG-NEXT: call void @f1(i64 %[[ARG]]) + +__attribute__((pure)) int f10(int); +__attribute__((const)) int f11(int); +int f12(void) { + return f10(1) + f11(2); +} + +// CIR-LABEL: cir.func @f12() -> !s32i +// CIR: %[[A:.+]] = cir.const #cir.int<1> : !s32i +// CIR-NEXT: %{{.+}} = cir.call @f10(%[[A]]) side_effect(pure) : (!s32i) -> !s32i +// CIR-NEXT: %[[B:.+]] = cir.const #cir.int<2> : !s32i +// CIR-NEXT: %{{.+}} = cir.call @f11(%[[B]]) side_effect(const) : (!s32i) -> !s32i + +// LLVM-LABEL: define i32 @f12() +// LLVM: %{{.+}} = call i32 @f10(i32 1) #[[ATTR0:.+]] +// LLVM-NEXT: %{{.+}} = call i32 @f11(i32 2) #[[ATTR1:.+]] + +// OGCG-LABEL: define dso_local i32 @f12() +// OGCG: %{{.+}} = call i32 @f10(i32 noundef 1) #[[ATTR0:.+]] +// OGCG-NEXT: %{{.+}} = call i32 @f11(i32 noundef 2) #[[ATTR1:.+]] + +// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read, errnomem: none) } +// LLVM: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } + +// OGCG: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } +// OGCG: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp index 741cadeb5c76..cc25afce1e5a 100644 --- a/clang/test/CIR/CodeGen/call.cpp +++ b/clang/test/CIR/CodeGen/call.cpp @@ -70,3 +70,35 @@ void f9() { // LLVM-LABEL: define void @_Z2f9v() // LLVM: call void (i32, ...) @_Z2f8iz(i32 1) // LLVM: call void (i32, ...) @_Z2f8iz(i32 1, i32 2, i32 3, i32 4) + +struct S { + int x; + int y; +}; + +S f10(); +void f11() { + S s = f10(); +} + +// CIR-LABEL: cir.func @_Z3f11v() +// CIR: %[[#s:]] = cir.call @_Z3f10v() : () -> !rec_S +// CIR-NEXT: cir.store align(4) %[[#s]], %{{.+}} : !rec_S, !cir.ptr + +// LLVM-LABEL: define void @_Z3f11v() +// LLVM: %[[#s:]] = call %struct.S @_Z3f10v() +// LLVM-NEXT: store %struct.S %[[#s]], ptr %{{.+}}, align 4 + +void f12() { + f10(); +} + +// CIR-LABEL: cir.func @_Z3f12v() +// CIR: %[[#slot:]] = cir.alloca !rec_S, !cir.ptr, ["agg.tmp0"] +// CIR-NEXT: %[[#ret:]] = cir.call @_Z3f10v() : () -> !rec_S +// CIR-NEXT: cir.store align(4) %[[#ret]], %[[#slot]] : !rec_S, !cir.ptr + +// LLVM-LABEL: define void @_Z3f12v() { +// LLVM: %[[#slot:]] = alloca %struct.S, i64 1, align 4 +// LLVM-NEXT: %[[#ret:]] = call %struct.S @_Z3f10v() +// LLVM-NEXT: store %struct.S %[[#ret]], ptr %[[#slot]], align 4 diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp index a7c11b1939ba..84f55242a611 100644 --- a/clang/test/CIR/CodeGen/cast.cpp +++ b/clang/test/CIR/CodeGen/cast.cpp @@ -73,6 +73,14 @@ int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) { // LLVM: %{{[0-9]+}} = fcmp une float %{{[0-9]+}}, 0.000000e+00 // LLVM: %{{[0-9]+}} = zext i1 %{{[0-9]+}} to i8 + double d2 = f; // float to double + // CIR: %{{[0-9]+}} = cir.cast(floating, %{{[0-9]+}} : !cir.float), !cir.double + // LLVM: %{{[0-9]+}} = fpext float %{{[0-9]+}} to double + + f = d2; // double to float + // CIR: %{{[0-9]+}} = cir.cast(floating, %{{[0-9]+}} : !cir.double), !cir.float + // LLVM: %{{[0-9]+}} = fptrunc double %{{[0-9]+}} to float + return 0; } diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 6fa7bca3749c..cfeed345b4f1 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -27,3 +27,232 @@ float _Complex cf2 = { 1.0f, 2.0f }; // OGCG: {{.*}} = global { float, float } zeroinitializer, align 4 // OGCG: {{.*}} = global { i32, i32 } { i32 1, i32 2 }, align 4 // OGCG: {{.*}} = global { float, float } { float 1.000000e+00, float 2.000000e+00 }, align 4 + +void foo() { int _Complex c = {}; } + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<0> : !s32i, #cir.int<0> : !s32i> : !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: store { i32, i32 } zeroinitializer, ptr %[[INIT]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 0, ptr %[[C_IMAG_PTR]], align 4 + +void foo2() { int _Complex c = {1, 2}; } + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: store { i32, i32 } { i32 1, i32 2 }, ptr %[[INIT]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store i32 1, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 2, ptr %[[C_IMAG_PTR]], align 4 + +void foo3() { + int a; + int b; + int _Complex c = {a, b}; +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !s32i -> !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM: %[[TMP_B:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[TMP_A]], 0 +// LLVM: %[[TMP_2:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 %[[TMP_B]], 1 +// LLVM: store { i32, i32 } %[[TMP_2]], ptr %[[INIT]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[REAL_VAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[IMAG_VAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store i32 %[[REAL_VAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 %[[IMAG_VAL]], ptr %[[C_IMAG_PTR]], align 4 + +void foo4() { + int a; + int _Complex c = {1, a}; +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !s32i +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[CONST_1]], %[[TMP_A]] : !s32i -> !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM: %[[COMPLEX:.*]] = insertvalue { i32, i32 } { i32 1, i32 undef }, i32 %[[TMP_A]], 1 +// LLVM: store { i32, i32 } %[[COMPLEX]], ptr %[[INIT]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[TMP_A:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store i32 1, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 %[[TMP_A]], ptr %[[C_IMAG_PTR]], align 4 + +void foo5() { + float _Complex c = {1.0f, 2.0f}; +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float> : !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[INIT:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } { float 1.000000e+00, float 2.000000e+00 }, ptr %[[INIT]], align 4 + +// OGCG: %[[COMPLEX]] = alloca { float, float }, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store float 1.000000e+00, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4 + +void foo6() { + float a; + float b; + float _Complex c = {a, b}; +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !cir.float +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !cir.float +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !cir.float -> !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[COMPLEX:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load float, ptr {{.*}}, align 4 +// LLVM: %[[TMP_B:.*]] = load float, ptr {{.*}}, align 4 +// LLVM: %[[TMP:.*]] = insertvalue { float, float } undef, float %[[TMP_A]], 0 +// LLVM: %[[TMP_2:.*]] = insertvalue { float, float } %[[TMP]], float %[[TMP_B]], 1 +// LLVM: store { float, float } %[[TMP_2]], ptr %[[COMPLEX]], align 4 + +// OGCG: %[[COMPLEX]] = alloca { float, float }, align 4 +// OGCG: %[[TMP_A:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[TMP_B:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store float %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 4 + +void foo7() { + float a; + float _Complex c = {a, 2.0f}; +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !cir.float +// CIR: %[[CONST_2F:.*]] = cir.const #cir.fp<2.000000e+00> : !cir.float +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_2F]] : !cir.float -> !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[COMPLEX:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load float, ptr {{.*}}, align 4 +// LLVM: %[[TMP:.*]] = insertvalue { float, float } undef, float %[[TMP_A]], 0 +// LLVM: %[[TMP_2:.*]] = insertvalue { float, float } %[[TMP]], float 2.000000e+00, 1 +// LLVM: store { float, float } %[[TMP_2]], ptr %[[COMPLEX]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { float, float }, align 4 +// OGCG: %[[TMP_A:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4 + +void foo8() { + double _Complex c = 2.00i; +} + +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.fp<0.000000e+00> : !cir.double, #cir.fp<2.000000e+00> : !cir.double> : !cir.complex + +// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: store { double, double } { double 0.000000e+00, double 2.000000e+00 }, ptr %[[COMPLEX]], align 8 + +// OGCG: %[[COMPLEX:.*]] = alloca { double, double }, align 8 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store double 0.000000e+00, ptr %[[C_REAL_PTR]], align 8 +// OGCG: store double 2.000000e+00, ptr %[[C_IMAG_PTR]], align 8 + +void foo9(double a, double b) { + double _Complex c = __builtin_complex(a, b); +} + +// CIR: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !cir.double +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr, !cir.double +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !cir.double -> !cir.complex +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8 +// LLVM: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8 +// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[TMP_A]], 0 +// LLVM: %[[TMP_2:.*]] = insertvalue { double, double } %[[TMP]], double %[[TMP_B]], 1 +// LLVM: store { double, double } %[[TMP_2]], ptr %[[COMPLEX]], align 8 + +// OGCG: %[[COMPLEX]] = alloca { double, double }, align 8 +// OGCG: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store double %[[TMP_A]], ptr %[[C_REAL_PTR]], align 8 +// OGCG: store double %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 8 + +void foo14() { + int _Complex c = 2i; +} + +// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<0> : !s32i, #cir.int<2> : !s32i> : !cir.complex + +// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: store { i32, i32 } { i32 0, i32 2 }, ptr %[[COMPLEX]], align 4 + +// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1 +// OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 2, ptr %[[C_IMAG_PTR]], align 4 + +void foo15() { + int _Complex a; + int _Complex b = a; +} + +// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] +// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["b", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr>, !cir.complex +// CIR: cir.store{{.*}} %[[TMP_A]], %[[COMPLEX_B]] : !cir.complex, !cir.ptr> + +// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4 +// LLVM: store { i32, i32 } %[[TMP_A]], ptr %[[COMPLEX_B]], align 4 + +// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1 +// OGCG: store i32 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 4 +// OGCG: store i32 %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/ctor.cpp b/clang/test/CIR/CodeGen/ctor.cpp index 3a1e82e338c1..1a36eb0d9d3a 100644 --- a/clang/test/CIR/CodeGen/ctor.cpp +++ b/clang/test/CIR/CodeGen/ctor.cpp @@ -3,7 +3,7 @@ struct Struk { int a; - Struk(); + Struk() {} }; void baz() { @@ -12,8 +12,104 @@ void baz() { // CHECK: !rec_Struk = !cir.record -// CHECK: cir.func @_ZN5StrukC1Ev(!cir.ptr) +// Note: In the absence of the '-mconstructor-aliases' option, we emit two +// constructors here. The handling of constructor aliases is currently +// NYI, but when it is added this test should be updated to add a RUN +// line that passes '-mconstructor-aliases' to clang_cc1. +// CHECK: cir.func @_ZN5StrukC2Ev(%arg0: !cir.ptr +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.return + +// CHECK: cir.func @_ZN5StrukC1Ev(%arg0: !cir.ptr +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.call @_ZN5StrukC2Ev(%[[THIS]]) : (!cir.ptr) -> () +// CHECK-NEXT: cir.return + // CHECK: cir.func @_Z3bazv() // CHECK-NEXT: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr, ["s", init] {alignment = 4 : i64} // CHECK-NEXT: cir.call @_ZN5StrukC1Ev(%[[S_ADDR]]) : (!cir.ptr) -> () // CHECK-NEXT: cir.return + +struct VariadicStruk { + int a; + VariadicStruk(int n, ...) { a = n;} +}; + +void bar() { + VariadicStruk s(1, 2, 3); +} + +// When a variadic constructor is present, we call the C2 constructor directly. + +// CHECK-NOT: cir.func @_ZN13VariadicStrukC2Eiz + +// CHECK: cir.func @_ZN13VariadicStrukC1Eiz(%arg0: !cir.ptr +// CHECK-SAME: %arg1: !s32i +// CHECK-SAME: ...) { +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CHECK-NEXT: %[[N_ADDR:.*]] = cir.alloca {{.*}} ["n", init] +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] +// CHECK-NEXT: cir.store %arg1, %[[N_ADDR]] +// CHECK-NEXT: %[[THIS:.*]] = cir.load{{.*}} %[[THIS_ADDR]] +// CHECK-NEXT: %[[N:.*]] = cir.load{{.*}} %[[N_ADDR]] +// CHECK-NEXT: %[[A_ADDR:.*]] = cir.get_member %[[THIS]][0] {name = "a"} +// CHECK-NEXT: cir.store{{.*}} %[[N]], %[[A_ADDR]] +// CHECK-NEXT: cir.return + +// CHECK: cir.func @_Z3barv +// CHECK-NEXT: %[[S_ADDR:.*]] = cir.alloca !rec_VariadicStruk, !cir.ptr, ["s", init] +// CHECK-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i +// CHECK-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i +// CHECK-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i +// CHECK-NEXT: cir.call @_ZN13VariadicStrukC1Eiz(%[[S_ADDR]], %[[ONE]], %[[TWO]], %[[THREE]]) +// CHECK-NEXT: cir.return + +struct DelegatingStruk { + int a; + DelegatingStruk(int n) { a = n; } + DelegatingStruk() : DelegatingStruk(0) {} +}; + +void bam() { + DelegatingStruk s; +} + +// CHECK: cir.func @_ZN15DelegatingStrukC2Ei(%arg0: !cir.ptr +// CHECK-SAME: %arg1: !s32i +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CHECK-NEXT: %[[N_ADDR:.*]] = cir.alloca {{.*}} ["n", init] +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] +// CHECK-NEXT: cir.store %arg1, %[[N_ADDR]] +// CHECK-NEXT: %[[THIS:.*]] = cir.load{{.*}} %[[THIS_ADDR]] +// CHECK-NEXT: %[[N:.*]] = cir.load{{.*}} %[[N_ADDR]] +// CHECK-NEXT: %[[A_ADDR:.*]] = cir.get_member %[[THIS]][0] {name = "a"} +// CHECK-NEXT: cir.store{{.*}} %[[N]], %[[A_ADDR]] +// CHECK-NEXT: cir.return + +// CHECK: cir.func @_ZN15DelegatingStrukC1Ei(%arg0: !cir.ptr +// CHECK-SAME: %arg1: !s32i +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CHECK-NEXT: %[[N_ADDR:.*]] = cir.alloca {{.*}} ["n", init] +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] +// CHECK-NEXT: cir.store %arg1, %[[N_ADDR]] +// CHECK-NEXT: %[[THIS:.*]] = cir.load{{.*}} %[[THIS_ADDR]] +// CHECK-NEXT: %[[N:.*]] = cir.load{{.*}} %[[N_ADDR]] +// CHECK-NEXT: cir.call @_ZN15DelegatingStrukC2Ei(%[[THIS]], %[[N]]) +// CHECK-NEXT: cir.return + +// CHECK: cir.func @_ZN15DelegatingStrukC1Ev(%arg0: !cir.ptr +// CHECK-NEXT: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CHECK-NEXT: cir.store %arg0, %[[THIS_ADDR]] +// CHECK-NEXT: %[[THIS:.*]] = cir.load{{.*}} %[[THIS_ADDR]] +// CHECK-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CHECK-NEXT: cir.call @_ZN15DelegatingStrukC1Ei(%[[THIS]], %[[ZERO]]) +// CHECK-NEXT: cir.return + +// CHECK: cir.func @_Z3bamv +// CHECK-NEXT: %[[S_ADDR:.*]] = cir.alloca {{.*}} ["s", init] +// CHECK-NEXT: cir.call @_ZN15DelegatingStrukC1Ev(%[[S_ADDR]]) +// CHECK-NEXT: cir.return diff --git a/clang/test/CIR/CodeGen/forrange.cpp b/clang/test/CIR/CodeGen/forrange.cpp index 6b6ccc79e59d..45e146e9091d 100644 --- a/clang/test/CIR/CodeGen/forrange.cpp +++ b/clang/test/CIR/CodeGen/forrange.cpp @@ -115,8 +115,8 @@ void for_range3() { // CIR: %[[C_ADDR:.*]] = cir.alloca !rec_C3{{.*}} ["c"] // CIR: cir.scope { // CIR: %[[RANGE_ADDR:.*]] = cir.alloca !cir.ptr{{.*}} ["__range1", init, const] -// CIR: %[[BEGIN_ADDR:.*]] = cir.alloca !rec_Iterator, !cir.ptr{{.*}} ["__begin1"] -// CIR: %[[END_ADDR:.*]] = cir.alloca !rec_Iterator, !cir.ptr{{.*}} ["__end1"] +// CIR: %[[BEGIN_ADDR:.*]] = cir.alloca !rec_Iterator, !cir.ptr{{.*}} ["__begin1", init] +// CIR: %[[END_ADDR:.*]] = cir.alloca !rec_Iterator, !cir.ptr{{.*}} ["__end1", init] // CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr{{.*}} ["e", init, const] // CIR: cir.store{{.*}} %[[C_ADDR]], %[[RANGE_ADDR]] // CIR: cir.for : cond { diff --git a/clang/test/CIR/CodeGen/libc.c b/clang/test/CIR/CodeGen/libc.c new file mode 100644 index 000000000000..f65fe92cd36a --- /dev/null +++ b/clang/test/CIR/CodeGen/libc.c @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +// Note: In the final implementation, we will want these to generate +// CIR-specific libc operations. This test is just a placeholder +// to make sure we can compile these to normal function calls +// until the special handling is implemented. + +void *memcpy(void *, const void *, unsigned long); +void testMemcpy(void *dst, const void *src, unsigned long size) { + memcpy(dst, src, size); + // CHECK: cir.call @memcpy +} + +void *memmove(void *, const void *, unsigned long); +void testMemmove(void *src, const void *dst, unsigned long size) { + memmove(dst, src, size); + // CHECK: cir.call @memmove +} + +void *memset(void *, int, unsigned long); +void testMemset(void *dst, int val, unsigned long size) { + memset(dst, val, size); + // CHECK: cir.call @memset +} + +double fabs(double); +double testFabs(double x) { + return fabs(x); + // CHECK: cir.call @fabs +} + +float fabsf(float); +float testFabsf(float x) { + return fabsf(x); + // CHECK: cir.call @fabsf +} + +int abs(int); +int testAbs(int x) { + return abs(x); + // CHECK: cir.call @abs +} + +long labs(long); +long testLabs(long x) { + return labs(x); + // CHECK: cir.call @labs +} + +long long llabs(long long); +long long testLlabs(long long x) { + return llabs(x); + // CHECK: cir.call @llabs +} diff --git a/clang/test/CIR/CodeGen/static-vars.c b/clang/test/CIR/CodeGen/static-vars.c new file mode 100644 index 000000000000..f45a41d9a00f --- /dev/null +++ b/clang/test/CIR/CodeGen/static-vars.c @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +void func1(void) { + // Should lower default-initialized static vars. + static int i; + // CHECK-DAG: cir.global "private" internal dsolocal @func1.i = #cir.int<0> : !s32i + + // Should lower constant-initialized static vars. + static int j = 1; + // CHECK-DAG: cir.global "private" internal dsolocal @func1.j = #cir.int<1> : !s32i + + // Should properly shadow static vars in nested scopes. + { + static int j = 2; + // CHECK-DAG: cir.global "private" internal dsolocal @func1.j.1 = #cir.int<2> : !s32i + } + { + static int j = 3; + // CHECK-DAG: cir.global "private" internal dsolocal @func1.j.2 = #cir.int<3> : !s32i + } + + // Should lower basic static vars arithmetics. + j++; + // CHECK-DAG: %[[#V2:]] = cir.get_global @func1.j : !cir.ptr + // CHECK-DAG: %[[#V3:]] = cir.load{{.*}} %[[#V2]] : !cir.ptr, !s32i + // CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i + // CHECK-DAG: cir.store{{.*}} %[[#V4]], %[[#V2]] : !s32i, !cir.ptr +} + +// Should shadow static vars on different functions. +void func2(void) { + static char i; + // CHECK-DAG: cir.global "private" internal dsolocal @func2.i = #cir.int<0> : !s8i + static float j; + // CHECK-DAG: cir.global "private" internal dsolocal @func2.j = #cir.fp<0.000000e+00> : !cir.float +} diff --git a/clang/test/CIR/CodeGen/static-vars.cpp b/clang/test/CIR/CodeGen/static-vars.cpp new file mode 100644 index 000000000000..9b892c69a6fe --- /dev/null +++ b/clang/test/CIR/CodeGen/static-vars.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t1.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t1.ll %s + +void func1(void) { + // Should lower default-initialized static vars. + static int i; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func1vE1i = #cir.int<0> : !s32i + + // Should lower constant-initialized static vars. + static int j = 1; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func1vE1j = #cir.int<1> : !s32i + + // Should properly shadow static vars in nested scopes. + { + static int j = 2; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func1vE1j_0 = #cir.int<2> : !s32i + } + { + static int j = 3; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func1vE1j_1 = #cir.int<3> : !s32i + } + + // Should lower basic static vars arithmetics. + j++; + // CHECK-DAG: %[[#V2:]] = cir.get_global @_ZZ5func1vE1j : !cir.ptr + // CHECK-DAG: %[[#V3:]] = cir.load{{.*}} %[[#V2]] : !cir.ptr, !s32i + // CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i + // CHECK-DAG: cir.store{{.*}} %[[#V4]], %[[#V2]] : !s32i, !cir.ptr +} + +// Should shadow static vars on different functions. +void func2(void) { + static char i; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func2vE1i = #cir.int<0> : !s8i + static float j; + // CHECK-DAG: cir.global "private" internal dsolocal @_ZZ5func2vE1j = #cir.fp<0.000000e+00> : !cir.float +} + +// CHECK-DAG: cir.global linkonce_odr comdat @_ZZ4testvE1c = #cir.int<0> : !s32i + +// LLVM-DAG: $_ZZ4testvE1c = comdat any +// LLVM-DAG: @_ZZ4testvE1c = linkonce_odr global i32 0, comdat, align 4 + +inline void test() { static int c; } +// CHECK-LABEL: @_Z4testv +// CHECK: {{%.*}} = cir.get_global @_ZZ4testvE1c : !cir.ptr +void foo() { test(); } diff --git a/clang/test/CIR/CodeGen/string-literals.c b/clang/test/CIR/CodeGen/string-literals.c index 00f59b09400c..90ea21906f36 100644 --- a/clang/test/CIR/CodeGen/string-literals.c +++ b/clang/test/CIR/CodeGen/string-literals.c @@ -5,6 +5,18 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s +char g_str[] = "1234"; + +// CIR: cir.global external @g_str = #cir.const_array<"1234\00" : !cir.array> : !cir.array + +char g_oversized[100] = "123"; + +// CIR: cir.global external @g_oversized = #cir.const_array<"123" : !cir.array, trailing_zeros> : !cir.array + +char g_exact[4] = "123"; + +// CIR: cir.global external @g_exact = #cir.const_array<"123\00" : !cir.array> : !cir.array + // CIR: cir.global "private" cir_private dsolocal @[[STR1_GLOBAL:.*]] = #cir.const_array<"1\00" : !cir.array> : !cir.array // CIR: cir.global "private" cir_private dsolocal @[[STR2_GLOBAL:.*]] = #cir.zero : !cir.array // CIR: cir.global "private" cir_private dsolocal @[[STR3_GLOBAL:.*]] = #cir.zero : !cir.array diff --git a/clang/test/CIR/CodeGen/string-literals.cpp b/clang/test/CIR/CodeGen/string-literals.cpp new file mode 100644 index 000000000000..c56eb7438732 --- /dev/null +++ b/clang/test/CIR/CodeGen/string-literals.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// CIR: cir.global "private" cir_private dsolocal @[[STR1_GLOBAL:.*]] = #cir.const_array<"abcd\00" : !cir.array> : !cir.array + +// LLVM: @[[STR1_GLOBAL:.*]] = private global [5 x i8] c"abcd\00" + +// OGCG: @[[STR1_GLOBAL:.*]] = private unnamed_addr constant [5 x i8] c"abcd\00" + +decltype(auto) returns_literal() { + return "abcd"; +} + +// CIR: cir.func{{.*}} @_Z15returns_literalv() -> !cir.ptr> +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["__retval"] +// CIR: %[[STR_ADDR:.*]] = cir.get_global @[[STR1_GLOBAL]] : !cir.ptr> +// CIR: cir.store{{.*}} %[[STR_ADDR]], %[[RET_ADDR]] +// CIR: %[[RET:.*]] = cir.load %[[RET_ADDR]] +// CIR: cir.return %[[RET]] diff --git a/clang/test/CIR/CodeGen/struct.c b/clang/test/CIR/CodeGen/struct.c index ed84edd97e5d..b722b64eeb58 100644 --- a/clang/test/CIR/CodeGen/struct.c +++ b/clang/test/CIR/CodeGen/struct.c @@ -19,6 +19,7 @@ // CIR-DAG: !rec_CycleEnd = !cir.record>}>>}>>}> // CIR-DAG: !rec_CycleMiddle = !cir.record}> // CIR-DAG: !rec_CycleStart = !cir.record}> +// CIR-DAG: !rec_IncompleteArray = !cir.record}> // LLVM-DAG: %struct.CompleteS = type { i32, i8 } // LLVM-DAG: %struct.OuterS = type { %struct.InnerS, i32 } // LLVM-DAG: %struct.InnerS = type { i32, i8 } @@ -30,6 +31,7 @@ // LLVM-DAG: %struct.CycleStart = type { ptr } // LLVM-DAG: %struct.CycleMiddle = type { ptr } // LLVM-DAG: %struct.CycleEnd = type { ptr } +// LLVM-DAG: %struct.IncompleteArray = type { [0 x i32] } // OGCG-DAG: %struct.CompleteS = type { i32, i8 } // OGCG-DAG: %struct.OuterS = type { %struct.InnerS, i32 } // OGCG-DAG: %struct.InnerS = type { i32, i8 } @@ -41,6 +43,7 @@ // OGCG-DAG: %struct.CycleStart = type { ptr } // OGCG-DAG: %struct.CycleMiddle = type { ptr } // OGCG-DAG: %struct.CycleEnd = type { ptr } +// OGCG-DAG: %struct.IncompleteArray = type { [0 x i32] } struct CompleteS { int a; @@ -149,6 +152,16 @@ struct CycleEnd { // LLVM-DAG: @end = global %struct.CycleEnd zeroinitializer // OGCG-DAG: @end = global %struct.CycleEnd zeroinitializer +struct IncompleteArray { + int array[]; +} incomplete; + +// CIR: cir.global external @incomplete = #cir.zero : !rec_IncompleteArray + +// LLVM-DAG: global %struct.IncompleteArray zeroinitializer + +// OGCG-DAG: global %struct.IncompleteArray zeroinitializer + void f(void) { struct IncompleteS *p; } @@ -313,3 +326,4 @@ void f6(struct CycleStart *start) { // OGCG: %[[MIDDLE:.*]] = getelementptr inbounds nuw %struct.CycleStart, ptr %{{.*}}, i32 0, i32 0 // OGCG: %[[END:.*]] = getelementptr inbounds nuw %struct.CycleMiddle, ptr %{{.*}}, i32 0, i32 0 // OGCG: %[[START2:.*]] = getelementptr inbounds nuw %struct.CycleEnd, ptr %{{.*}}, i32 0, i32 0 + diff --git a/clang/test/CIR/CodeGen/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp index e1814f216f6b..fe4919ec0478 100644 --- a/clang/test/CIR/CodeGen/vector-ext.cpp +++ b/clang/test/CIR/CodeGen/vector-ext.cpp @@ -77,12 +77,8 @@ void foo() { // CIR: %[[VEC_F:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["f", init] // CIR: %[[VEC_G:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["g", init] // CIR: %[[VEC_H:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["h", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_E_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_E_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_E_VAL]], %[[VEC_E]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[GLOBAL_X:.*]] = cir.get_global @x : !cir.ptr // CIR: %[[X_VAL:.*]] = cir.load{{.*}} %[[GLOBAL_X]] : !cir.ptr, !s32i @@ -95,13 +91,11 @@ void foo() { // CIR: %[[VEC_F_VAL:.*]] = cir.vec.create(%[[X_VAL]], %[[CONST_5]], %[[CONST_6]], %[[X_PLUS_1]] : // CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_F_VAL]], %[[VEC_F]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i -// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i -// CIR: %[[VEC_G_VAL:.*]] = cir.vec.create(%[[CONST_5]], %[[CONST_0]], %[[CONST_0]], %[[CONST_0]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_G_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<0> : !s32i, +// CIR-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_G_VAL]], %[[VEC_G]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i -// CIR: %[[VEC_H_VAL:.*]] = cir.vec.create(%[[ZERO]], %[[ZERO]], %[[ZERO]], %[[ZERO]] : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_H_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, +// CIR-SAME; #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_H_VAL]], %[[VEC_H]] : !cir.vector<4 x !s32i>, !cir.ptr> // LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 @@ -148,12 +142,8 @@ void foo3() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr, ["e", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP:.*]] = cir.load{{.*}} %[[VEC]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i @@ -184,12 +174,8 @@ void foo4() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr, ["idx", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr, ["e", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i // CIR: cir.store{{.*}} %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr @@ -225,12 +211,8 @@ void foo5() { } // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i @@ -260,12 +242,8 @@ void foo6() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr, ["idx", init] // CIR: %[[VAL:.*]] = cir.alloca !s32i, !cir.ptr, ["value", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i // CIR: cir.store{{.*}} %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr @@ -307,12 +285,8 @@ void foo7() { } // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i @@ -353,12 +327,8 @@ void foo8() { // CIR: %[[PLUS_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["plus_res", init] // CIR: %[[MINUS_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["minus_res", init] // CIR: %[[NOT_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["not_res", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP1:.*]] = cir.load{{.*}} %[[VEC]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[PLUS:.*]] = cir.unary(plus, %[[TMP1]]) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> @@ -410,19 +380,11 @@ void foo9() { // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] // CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] // CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shr", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i -// CIR: %[[CONST_6:.*]] = cir.const #cir.int<6> : !s32i -// CIR: %[[CONST_7:.*]] = cir.const #cir.int<7> : !s32i -// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !s32i -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%[[CONST_5]], %[[CONST_6]], %[[CONST_7]], %[[CONST_8]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -475,9 +437,11 @@ void foo10() { // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] // CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] // CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["shr", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !u32i, !u32i, !u32i, !u32i) : !cir.vector<4 x !u32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !u32i, #cir.int<6> : !u32i, +// CIR-SAME: #cir.int<7> : !u32i, #cir.int<8> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> @@ -534,11 +498,11 @@ void foo11() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -661,11 +625,11 @@ void foo12() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -776,11 +740,11 @@ void foo13() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !u32i, !u32i, !u32i, !u32i) : -// CIR-SAME: !cir.vector<4 x !u32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !u32i, #cir.int<2> : !u32i, +// CIR-SAME: #cir.int<3> : !u32i, #cir.int<4> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !u32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !u32i, !u32i, !u32i, !u32i) : -// CIR-SAME: !cir.vector<4 x !u32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !u32i, #cir.int<6> : !u32i, +// CIR-SAME: #cir.int<7> : !u32i, #cir.int<8> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !u32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> @@ -891,11 +855,11 @@ void foo14() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !cir.float>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !cir.float>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !cir.float, !cir.float, !cir.float, !cir.float) : -// CIR-SAME: !cir.vector<4 x !cir.float> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float, +// CIR-SAME: #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !cir.float>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !cir.float, !cir.float, !cir.float, !cir.float) : -// CIR-SAME: !cir.vector<4 x !cir.float> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> : !cir.float, +// CIR-SAME: #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !cir.float>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !cir.float> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !cir.float> @@ -990,6 +954,7 @@ void foo14() { // OGCG: %[[TMP_B:.*]] = load <4 x float>, ptr %[[VEC_B]], align 16 // OGCG: %[[GE:.*]] = fcmp oge <4 x float> %[[TMP_A]], %[[TMP_B]] // OGCG: %[[RES:.*]] = sext <4 x i1> %[[GE]] to <4 x i32> +// OGCG: store <4 x i32> %[[RES]], ptr {{.*}}, align 16 void foo15() { vi4 a; @@ -1092,6 +1057,61 @@ void foo17() { // OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16 // OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16> +void foo18() { + vi4 a = {1, 2, 3, 4}; + vi4 shl = a << 3; + + uvi4 b = {1u, 2u, 3u, 4u}; + uvi4 shr = b >> 3u; +} + +// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] +// CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] +// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] +// CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["shr", init] +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, +// CIR-SAME: #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> +// CIR: %[[SH_AMOUNT:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[SPLAT_VEC:.*]] = cir.vec.splat %[[SH_AMOUNT]] : !s32i, !cir.vector<4 x !s32i> +// CIR: %[[SHL:.*]] = cir.shift(left, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[SPLAT_VEC]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[SHL]], %[[SHL_RES]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !u32i, #cir.int<2> : !u32i, +// CIR-SAME: #cir.int<3> : !u32i, #cir.int<4> : !u32i]> : !cir.vector<4 x !u32i> +// CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> +// CIR: %[[SH_AMOUNT:.*]] = cir.const #cir.int<3> : !u32i +// CIR: %[[SPLAT_VEC:.*]] = cir.vec.splat %[[SH_AMOUNT]] : !u32i, !cir.vector<4 x !u32i> +// CIR: %[[SHR:.*]] = cir.shift(right, %[[TMP_B]] : !cir.vector<4 x !u32i>, %[[SPLAT_VEC]] : !cir.vector<4 x !u32i>) -> !cir.vector<4 x !u32i> +// CIR: cir.store{{.*}} %[[SHR]], %[[SHR_RES]] : !cir.vector<4 x !u32i>, !cir.ptr> + +// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHL_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHR_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> , ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], splat (i32 3) +// LLVM: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// LLVM: store <4 x i32> , ptr %[[VEC_B]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHR:.*]] = lshr <4 x i32> %[[TMP_B]], splat (i32 3) +// LLVM: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + +// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHL_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHR_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> , ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], splat (i32 3) +// OGCG: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// OGCG: store <4 x i32> , ptr %[[VEC_B]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHR:.*]] = lshr <4 x i32> %[[TMP_B]], splat (i32 3) +// OGCG: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + void foo19() { vi4 a; vi4 b; diff --git a/clang/test/CIR/CodeGen/vector.cpp b/clang/test/CIR/CodeGen/vector.cpp index 4f116faa7a1a..d0c5b83cd5b0 100644 --- a/clang/test/CIR/CodeGen/vector.cpp +++ b/clang/test/CIR/CodeGen/vector.cpp @@ -66,12 +66,8 @@ void foo() { // CIR: %[[VEC_E:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["e", init] // CIR: %[[VEC_F:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["f", init] // CIR: %[[VEC_G:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["g", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_D_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_D_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_D_VAL]], %[[VEC_D]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[GLOBAL_X:.*]] = cir.get_global @x : !cir.ptr // CIR: %[[X_VAL:.*]] = cir.load{{.*}} %[[GLOBAL_X]] : !cir.ptr, !s32i @@ -84,14 +80,11 @@ void foo() { // CIR: %[[VEC_E_VAL:.*]] = cir.vec.create(%[[X_VAL]], %[[CONST_5]], %[[CONST_6]], %[[X_PLUS_1]] : // CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_E_VAL]], %[[VEC_E]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i -// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i -// CIR: %[[VEC_F_VAL:.*]] = cir.vec.create(%[[CONST_5]], %[[CONST_0]], %[[CONST_0]], %[[CONST_0]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_F_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<0> : !s32i, +// CIR-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_F_VAL]], %[[VEC_F]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i -// CIR: %[[VEC_G_VAL:.*]] = cir.vec.create(%[[CONST_0]], %[[CONST_0]], %[[CONST_0]], %[[CONST_0]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_G_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, +// CIR-SAME; #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_G_VAL]], %[[VEC_G]] : !cir.vector<4 x !s32i>, !cir.ptr> // LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 @@ -136,12 +129,8 @@ void foo3() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr, ["e", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP:.*]] = cir.load{{.*}} %[[VEC]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i @@ -172,12 +161,8 @@ void foo4() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr, ["idx", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr, ["e", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i // CIR: cir.store{{.*}} %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr @@ -213,12 +198,8 @@ void foo5() { } // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i @@ -248,12 +229,8 @@ void foo6() { // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr, ["idx", init] // CIR: %[[VAL:.*]] = cir.alloca !s32i, !cir.ptr, ["value", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i // CIR: cir.store{{.*}} %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr @@ -295,12 +272,8 @@ void foo7() { } // CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i // CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i @@ -341,12 +314,8 @@ void foo8() { // CIR: %[[PLUS_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["plus_res", init] // CIR: %[[MINUS_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["minus_res", init] // CIR: %[[NOT_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["not_res", init] -// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i -// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i -// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i -// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : -// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP1:.*]] = cir.load{{.*}} %[[VEC]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[PLUS:.*]] = cir.unary(plus, %[[TMP1]]) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> @@ -398,9 +367,11 @@ void foo9() { // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] // CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] // CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shr", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -453,9 +424,11 @@ void foo10() { // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] // CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] // CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["shr", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !u32i, !u32i, !u32i, !u32i) : !cir.vector<4 x !u32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !u32i, #cir.int<6> : !u32i, +// CIR-SAME: #cir.int<7> : !u32i, #cir.int<8> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> @@ -512,11 +485,11 @@ void foo11() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -639,11 +612,11 @@ void foo12() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !s32i, !s32i, !s32i, !s32i) : -// CIR-SAME: !cir.vector<4 x !s32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !s32i> @@ -754,11 +727,11 @@ void foo13() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !u32i, !u32i, !u32i, !u32i) : -// CIR-SAME: !cir.vector<4 x !u32i> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !u32i, #cir.int<2> : !u32i, +// CIR-SAME: #cir.int<3> : !u32i, #cir.int<4> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !u32i>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !u32i, !u32i, !u32i, !u32i) : -// CIR-SAME: !cir.vector<4 x !u32i> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<5> : !u32i, #cir.int<6> : !u32i, +// CIR-SAME: #cir.int<7> : !u32i, #cir.int<8> : !u32i]> : !cir.vector<4 x !u32i> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !u32i> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> @@ -869,11 +842,11 @@ void foo14() { // CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !cir.float>, !cir.ptr>, ["a", init] // CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !cir.float>, !cir.ptr>, ["b", init] -// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !cir.float, !cir.float, !cir.float, !cir.float) : -// CIR-SAME: !cir.vector<4 x !cir.float> +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float, +// CIR-SAME: #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> // CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !cir.float>, !cir.ptr> -// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create({{.*}}, {{.*}}, {{.*}}, {{.*}} : !cir.float, !cir.float, !cir.float, !cir.float) : -// CIR-SAME: !cir.vector<4 x !cir.float> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> : !cir.float, +// CIR-SAME: #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> // CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !cir.float>, !cir.ptr> // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !cir.float> // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !cir.float> @@ -1071,6 +1044,61 @@ void foo17() { // OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16 // OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16> +void foo18() { + vi4 a = {1, 2, 3, 4}; + vi4 shl = a << 3; + + uvi4 b = {1u, 2u, 3u, 4u}; + uvi4 shr = b >> 3u; +} + +// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] +// CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] +// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["b", init] +// CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !u32i>, !cir.ptr>, ["shr", init] +// CIR: %[[VEC_A_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, +// CIR-SAME: #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr>, !cir.vector<4 x !s32i> +// CIR: %[[SH_AMOUNT:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[SPLAT_VEC:.*]] = cir.vec.splat %[[SH_AMOUNT]] : !s32i, !cir.vector<4 x !s32i> +// CIR: %[[SHL:.*]] = cir.shift(left, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[SPLAT_VEC]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store{{.*}} %[[SHL]], %[[SHL_RES]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CIR: %[[VEC_B_VAL:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !u32i, #cir.int<2> : !u32i, +// CIR-SAME: #cir.int<3> : !u32i, #cir.int<4> : !u32i]> : !cir.vector<4 x !u32i> +// CIR: cir.store{{.*}} %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !u32i>, !cir.ptr> +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr>, !cir.vector<4 x !u32i> +// CIR: %[[SH_AMOUNT:.*]] = cir.const #cir.int<3> : !u32i +// CIR: %[[SPLAT_VEC:.*]] = cir.vec.splat %[[SH_AMOUNT]] : !u32i, !cir.vector<4 x !u32i> +// CIR: %[[SHR:.*]] = cir.shift(right, %[[TMP_B]] : !cir.vector<4 x !u32i>, %[[SPLAT_VEC]] : !cir.vector<4 x !u32i>) -> !cir.vector<4 x !u32i> +// CIR: cir.store{{.*}} %[[SHR]], %[[SHR_RES]] : !cir.vector<4 x !u32i>, !cir.ptr> + +// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHL_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHR_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> , ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], splat (i32 3) +// LLVM: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// LLVM: store <4 x i32> , ptr %[[VEC_B]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHR:.*]] = lshr <4 x i32> %[[TMP_B]], splat (i32 3) +// LLVM: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + +// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHL_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHR_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> , ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], splat (i32 3) +// OGCG: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// OGCG: store <4 x i32> , ptr %[[VEC_B]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHR:.*]] = lshr <4 x i32> %[[TMP_B]], splat (i32 3) +// OGCG: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + void foo19() { vi4 a; vi4 b; diff --git a/clang/test/CIR/CodeGenOpenACC/combined.cpp b/clang/test/CIR/CodeGenOpenACC/combined.cpp index 1f3c9f1a8d3f..5b83a9cb9189 100644 --- a/clang/test/CIR/CodeGenOpenACC/combined.cpp +++ b/clang/test/CIR/CodeGenOpenACC/combined.cpp @@ -74,7 +74,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.serial combined(loop) { // CHECK: acc.loop combined(serial) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {seq = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {seq = [#acc.device_type, #acc.device_type, #acc.device_type]} loc // CHECK: acc.yield // CHECK-NEXT: } loc #pragma acc kernels loop seq device_type(nvidia, radeon) @@ -99,7 +99,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.serial combined(loop) { // CHECK: acc.loop combined(serial) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {auto_ = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type, #acc.device_type], seq = [#acc.device_type]} loc // CHECK: acc.yield // CHECK-NEXT: } loc #pragma acc kernels loop auto device_type(nvidia, radeon) @@ -124,7 +124,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.serial combined(loop) { // CHECK: acc.loop combined(serial) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {independent = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {independent = [#acc.device_type, #acc.device_type], seq = [#acc.device_type]} loc // CHECK: acc.yield // CHECK-NEXT: } loc #pragma acc kernels loop independent device_type(nvidia, radeon) @@ -143,7 +143,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.parallel combined(loop) { // CHECK: acc.loop combined(parallel) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1], collapseDeviceType = [#acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1], collapseDeviceType = [#acc.device_type], independent = [#acc.device_type]} // CHECK: acc.yield // CHECK-NEXT: } loc @@ -154,7 +154,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.serial combined(loop) { // CHECK: acc.loop combined(serial) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2], collapseDeviceType = [#acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1, 2], collapseDeviceType = [#acc.device_type, #acc.device_type], seq = [#acc.device_type]} // CHECK: acc.yield // CHECK-NEXT: } loc @@ -165,7 +165,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.kernels combined(loop) { // CHECK: acc.loop combined(kernels) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2, 2], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type], collapse = [1, 2, 2], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type]} // CHECK: acc.terminator // CHECK-NEXT: } loc #pragma acc parallel loop collapse(1) device_type(radeon, nvidia) collapse(2) device_type(host) collapse(3) @@ -175,7 +175,7 @@ extern "C" void acc_combined(int N, int cond) { // CHECK: acc.parallel combined(loop) { // CHECK: acc.loop combined(parallel) { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2, 2, 3], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1, 2, 2, 3], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type, #acc.device_type], independent = [#acc.device_type]} // CHECK: acc.yield // CHECK-NEXT: } loc @@ -1184,4 +1184,59 @@ extern "C" void acc_combined_data_clauses(int *arg1, int *arg2) { // CHECK-NEXT: } loc // CHECK-NEXT: acc.detach accPtr(%[[ATTACH2]] : !cir.ptr>) async([#acc.device_type]) {dataClause = #acc, name = "arg2"} // CHECK-NEXT: acc.detach accPtr(%[[ATTACH1]] : !cir.ptr>) async([#acc.device_type]) {dataClause = #acc, name = "arg1"} + + // Checking the automatic-addition of parallelism clauses. +#pragma acc parallel loop + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.parallel combined(loop) { + // CHECK-NEXT: acc.loop combined(parallel) { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {independent = [#acc.device_type]} loc + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc kernels loop + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.kernels combined(loop) { + // CHECK-NEXT: acc.loop combined(kernels) { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + // CHECK-NEXT: acc.terminator + // CHECK-NEXT: } loc + +#pragma acc serial loop + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.serial combined(loop) { + // CHECK-NEXT: acc.loop combined(serial) { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {seq = [#acc.device_type]} loc + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial loop worker + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.serial combined(loop) { + // CHECK-NEXT: acc.loop combined(serial) worker { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial loop vector + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.serial combined(loop) { + // CHECK-NEXT: acc.loop combined(serial) vector { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial loop gang + for(unsigned I = 0; I < 5; ++I); + // CHECK-NEXT: acc.serial combined(loop) { + // CHECK-NEXT: acc.loop combined(serial) gang { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc } diff --git a/clang/test/CIR/CodeGenOpenACC/loop.cpp b/clang/test/CIR/CodeGenOpenACC/loop.cpp index db94e2819b30..c0bf11e35395 100644 --- a/clang/test/CIR/CodeGenOpenACC/loop.cpp +++ b/clang/test/CIR/CodeGenOpenACC/loop.cpp @@ -41,12 +41,12 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {seq = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {independent = [#acc.device_type], seq = [#acc.device_type, #acc.device_type]} loc #pragma acc loop device_type(radeon) seq for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {seq = [#acc.device_type]} loc + // CHECK-NEXT: } attributes {independent = [#acc.device_type], seq = [#acc.device_type]} loc #pragma acc loop seq device_type(nvidia, radeon) for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { @@ -67,12 +67,12 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {independent = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {independent = [#acc.device_type, #acc.device_type, #acc.device_type]} loc #pragma acc loop device_type(radeon) independent for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {independent = [#acc.device_type]} loc + // CHECK-NEXT: } attributes {independent = [#acc.device_type, #acc.device_type]} loc #pragma acc loop independent device_type(nvidia, radeon) for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { @@ -93,12 +93,12 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {auto_ = [#acc.device_type, #acc.device_type]} loc + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type, #acc.device_type], independent = [#acc.device_type]} loc #pragma acc loop device_type(radeon) auto for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type], independent = [#acc.device_type]} loc #pragma acc loop auto device_type(nvidia, radeon) for(unsigned I = 0; I < N; ++I); // CHECK: acc.loop { @@ -116,7 +116,7 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned K = 0; K < N; ++K); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1], collapseDeviceType = [#acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1], collapseDeviceType = [#acc.device_type], independent = [#acc.device_type]} #pragma acc loop collapse(1) device_type(radeon) collapse (2) for(unsigned I = 0; I < N; ++I) @@ -124,7 +124,7 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned K = 0; K < N; ++K); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2], collapseDeviceType = [#acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1, 2], collapseDeviceType = [#acc.device_type, #acc.device_type], independent = [#acc.device_type]} #pragma acc loop collapse(1) device_type(radeon, nvidia) collapse (2) for(unsigned I = 0; I < N; ++I) @@ -132,14 +132,14 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { for(unsigned K = 0; K < N; ++K); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2, 2], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1, 2, 2], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type], independent = [#acc.device_type]} #pragma acc loop collapse(1) device_type(radeon, nvidia) collapse(2) device_type(host) collapse(3) for(unsigned I = 0; I < N; ++I) for(unsigned J = 0; J < N; ++J) for(unsigned K = 0; K < N; ++K); // CHECK: acc.loop { // CHECK: acc.yield - // CHECK-NEXT: } attributes {collapse = [1, 2, 2, 3], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type, #acc.device_type]} + // CHECK-NEXT: } attributes {collapse = [1, 2, 2, 3], collapseDeviceType = [#acc.device_type, #acc.device_type, #acc.device_type, #acc.device_type], independent = [#acc.device_type]} #pragma acc loop tile(1, 2, 3) for(unsigned I = 0; I < N; ++I) @@ -392,4 +392,85 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) { // CHECK: acc.yield // CHECK-NEXT: } loc } + // CHECK-NEXT: acc.terminator + // CHECK-NEXT: } loc + + // Checking the automatic-addition of parallelism clauses. +#pragma acc loop + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {independent = [#acc.device_type]} loc + +#pragma acc parallel + { + // CHECK-NEXT: acc.parallel { +#pragma acc loop + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {independent = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc kernels + { + // CHECK-NEXT: acc.kernels { +#pragma acc loop + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.terminator + // CHECK-NEXT: } loc + +#pragma acc serial + { + // CHECK-NEXT: acc.serial { +#pragma acc loop + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {seq = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial + { + // CHECK-NEXT: acc.serial { +#pragma acc loop worker + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop worker { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial + { + // CHECK-NEXT: acc.serial { +#pragma acc loop vector + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop vector { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc + +#pragma acc serial + { + // CHECK-NEXT: acc.serial { +#pragma acc loop gang + for(unsigned I = 0; I < N; ++I); + // CHECK-NEXT: acc.loop gang { + // CHECK: acc.yield + // CHECK-NEXT: } attributes {auto_ = [#acc.device_type]} loc + } + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc } diff --git a/clang/test/CIR/IR/call.cir b/clang/test/CIR/IR/call.cir index e35c201b6ed4..5f0916775479 100644 --- a/clang/test/CIR/IR/call.cir +++ b/clang/test/CIR/IR/call.cir @@ -8,11 +8,15 @@ cir.func @f1() cir.func @f2() { cir.call @f1() : () -> () + cir.call @f1() side_effect(pure) : () -> () + cir.call @f1() side_effect(const) : () -> () cir.return } // CHECK: cir.func @f2() { // CHECK-NEXT: cir.call @f1() : () -> () +// CHECK-NEXT: cir.call @f1() side_effect(pure) : () -> () +// CHECK-NEXT: cir.call @f1() side_effect(const) : () -> () // CHECK-NEXT: cir.return // CHECK-NEXT: } diff --git a/clang/test/CIR/IR/invalid-vector-shuffle-wrong-index.cir b/clang/test/CIR/IR/invalid-vector-shuffle-wrong-index.cir new file mode 100644 index 000000000000..375b2d3dc563 --- /dev/null +++ b/clang/test/CIR/IR/invalid-vector-shuffle-wrong-index.cir @@ -0,0 +1,16 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!s32i = !cir.int +!s64i = !cir.int + +module { + cir.func @fold_shuffle_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + + // expected-error @below {{index for __builtin_shufflevector must be less than the total number of vector elements}} + %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<4 x !s32i>) [#cir.int<9> : !s64i, #cir.int<4> : !s64i, + #cir.int<1> : !s64i, #cir.int<5> : !s64i] : !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } +} diff --git a/clang/test/CIR/IR/vector.cir b/clang/test/CIR/IR/vector.cir index a455acf92ab6..f23f5de9692d 100644 --- a/clang/test/CIR/IR/vector.cir +++ b/clang/test/CIR/IR/vector.cir @@ -187,4 +187,37 @@ cir.func @vector_shuffle_dynamic_test() { // CHECK: cir.return // CHECK: } +cir.func @vector_splat_test() { + %0 = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] + %1 = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] + %2 = cir.const #cir.int<1> : !s32i + %3 = cir.const #cir.int<2> : !s32i + %4 = cir.const #cir.int<3> : !s32i + %5 = cir.const #cir.int<4> : !s32i + %6 = cir.vec.create(%2, %3, %4, %5 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> + cir.store %6, %0 : !cir.vector<4 x !s32i>, !cir.ptr> + %7 = cir.load %0 : !cir.ptr>, !cir.vector<4 x !s32i> + %8 = cir.const #cir.int<3> : !s32i + %9 = cir.vec.splat %8 : !s32i, !cir.vector<4 x !s32i> + %10 = cir.shift(left, %7 : !cir.vector<4 x !s32i>, %9 : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> + cir.store %10, %1 : !cir.vector<4 x !s32i>, !cir.ptr> + cir.return +} + +// CHECK: cir.func @vector_splat_test() { +// CHECK-NEXT: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["a", init] +// CHECK-NEXT: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr>, ["shl", init] +// CHECK-NEXT: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CHECK-NEXT: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CHECK-NEXT: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CHECK-NEXT: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CHECK-NEXT: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CHECK-NEXT: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CHECK-NEXT: %[[TMP:.*]] = cir.load %[[VEC]] : !cir.ptr>, !cir.vector<4 x !s32i> +// CHECK-NEXT: %[[SPLAT_VAL:.*]] = cir.const #cir.int<3> : !s32i +// CHECK-NEXT: %[[SPLAT_VEC:.*]] = cir.vec.splat %[[SPLAT_VAL]] : !s32i, !cir.vector<4 x !s32i> +// CHECK-NEXT: %[[SHL:.*]] = cir.shift(left, %[[TMP]] : !cir.vector<4 x !s32i>, %[[SPLAT_VEC]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CHECK-NEXT: cir.store %[[SHL]], %[[SHL_RES:.*]] : !cir.vector<4 x !s32i>, !cir.ptr> +// CHECK-NEXT: cir.return + } diff --git a/clang/test/CIR/Transforms/complex-create-fold.cir b/clang/test/CIR/Transforms/complex-create-fold.cir new file mode 100644 index 000000000000..5d9d22112c8b --- /dev/null +++ b/clang/test/CIR/Transforms/complex-create-fold.cir @@ -0,0 +1,30 @@ +// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_complex_create_test() -> !cir.complex { + %0 = cir.alloca !cir.complex, !cir.ptr>, ["__retval"] + %1 = cir.alloca !cir.complex, !cir.ptr>, ["c", init] + %2 = cir.const #cir.int<1> : !s32i + %3 = cir.const #cir.int<2> : !s32i + %4 = cir.complex.create %2, %3 : !s32i -> !cir.complex + cir.store align(4) %4, %1 : !cir.complex, !cir.ptr> + %5 = cir.load align(4) %1 : !cir.ptr>, !cir.complex + cir.store align(4) %5, %0 : !cir.complex, !cir.ptr> + %6 = cir.load %0 : !cir.ptr>, !cir.complex + cir.return %6 : !cir.complex + } + +// CHECK: cir.func @fold_complex_create_test() -> !cir.complex { +// CHECK: %[[RET:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["__retval"] +// CHECK: %[[INIT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CHECK: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex +// CHECK: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex, !cir.ptr> +// CHECK: %[[TMP:.*]] = cir.load{{.*}} %[[INIT]] : !cir.ptr>, !cir.complex +// CHECK: cir.store{{.*}} %[[TMP:.*]], %[[RET]] : !cir.complex, !cir.ptr> +// CHECK: %[[TMP_2:.*]] = cir.load %[[RET]] : !cir.ptr>, !cir.complex +// CHECK: cir.return %[[TMP_2]] : !cir.complex +// CHECK: } + +} diff --git a/clang/test/CIR/Transforms/vector-cmp-fold.cir b/clang/test/CIR/Transforms/vector-cmp-fold.cir new file mode 100644 index 000000000000..b207fc08748e --- /dev/null +++ b/clang/test/CIR/Transforms/vector-cmp-fold.cir @@ -0,0 +1,227 @@ +// RUN: cir-opt %s -cir-canonicalize -o - -split-input-file | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(eq, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(ne, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(lt, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(le, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(gt, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i, #cir.int<7> : !s32i]> : !cir.vector<4 x !s32i> + %vec_2 = cir.const #cir.const_vector<[#cir.int<2> : !s32i, #cir.int<4> : !s32i, #cir.int<6> : !s32i, #cir.int<8> : !s32i]> : !cir.vector<4 x !s32i> + %new_vec = cir.vec.cmp(gt, %vec_1, %vec_2) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(eq, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(ne, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(lt, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(le, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<1> : !s32i, + // CHECK-SAME: #cir.int<1> : !s32i, #cir.int<1> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(gt, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} + +// ----- + +!s32i = !cir.int + +module { + cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + %vec_1 = cir.const #cir.const_vector<[#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> + : !cir.float, #cir.fp<3.000000e+00> : !cir.float, #cir.fp<4.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %vec_2 = cir.const #cir.const_vector<[#cir.fp<5.000000e+00> : !cir.float, #cir.fp<6.000000e+00> + : !cir.float, #cir.fp<7.000000e+00> : !cir.float, #cir.fp<8.000000e+00> : !cir.float]> : !cir.vector<4 x !cir.float> + %new_vec = cir.vec.cmp(ge, %vec_1, %vec_2) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> + cir.return %new_vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_cmp_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<0> : !s32i, #cir.int<0> : !s32i, + // CHECK-SAME: #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector<4 x !s32i> +} diff --git a/clang/test/CIR/Transforms/vector-create-fold.cir b/clang/test/CIR/Transforms/vector-create-fold.cir new file mode 100644 index 000000000000..fb8f66dc4deb --- /dev/null +++ b/clang/test/CIR/Transforms/vector-create-fold.cir @@ -0,0 +1,19 @@ +// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_create_vector_op_test() -> !cir.vector<4 x !s32i> { + %2 = cir.const #cir.int<1> : !s32i + %3 = cir.const #cir.int<2> : !s32i + %4 = cir.const #cir.int<3> : !s32i + %5 = cir.const #cir.int<4> : !s32i + %vec = cir.vec.create(%2, %3, %4, %5 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> + cir.return %vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_create_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %[[VEC:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, + // CHECK-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %[[VEC]] : !cir.vector<4 x !s32i> +} diff --git a/clang/test/CIR/Transforms/vector-splat.cir b/clang/test/CIR/Transforms/vector-splat.cir new file mode 100644 index 000000000000..e2274b8627b1 --- /dev/null +++ b/clang/test/CIR/Transforms/vector-splat.cir @@ -0,0 +1,16 @@ +// RUN: cir-opt %s -cir-simplify -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_shuffle_vector_op_test() -> !cir.vector<4 x !s32i> { + %v = cir.const #cir.int<3> : !s32i + %vec = cir.vec.splat %v : !s32i, !cir.vector<4 x !s32i> + cir.return %vec : !cir.vector<4 x !s32i> + } + + // CHECK: cir.func @fold_shuffle_vector_op_test() -> !cir.vector<4 x !s32i> { + // CHECK-NEXT: %0 = cir.const #cir.const_vector<[#cir.int<3> : !s32i, #cir.int<3> : !s32i, + // CHECK-SAME: #cir.int<3> : !s32i, #cir.int<3> : !s32i]> : !cir.vector<4 x !s32i> + // CHECK-NEXT: cir.return %0 : !cir.vector<4 x !s32i> +} diff --git a/clang/test/CXX/basic/basic.link/p1.cpp b/clang/test/CXX/basic/basic.link/p1.cpp index c6a119aa7f47..26a5f025f42f 100644 --- a/clang/test/CXX/basic/basic.link/p1.cpp +++ b/clang/test/CXX/basic/basic.link/p1.cpp @@ -1,57 +1,128 @@ -// RUN: %clang_cc1 -std=c++2a -verify %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_PRIVATE_FRAG %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_PRIVATE_FRAG %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL %s -// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s -// RUN: %clang_cc1 -std=c++2a -verify -DEXPORT_FRAGS %s +// RUN: rm -rf %t +// RUN: split-file %s %t -#ifndef NO_GLOBAL_FRAG -#ifdef EXPORT_FRAGS -export // expected-error {{global module fragment cannot be exported}} -#endif +// RUN: %clang_cc1 -std=c++2a -verify %t/M.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFrag.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoModuleDecl.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoPrivateFrag.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoModuleDeclAndNoPrivateFrag.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoPrivateFrag.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoModuleDecl.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoModuleDeclAndNoPrivateFrag.cppm +// RUN: %clang_cc1 -std=c++2a -verify %t/ExportFrags.cppm + +//--- M.cppm module; -#ifdef NO_MODULE_DECL -// expected-error@-2 {{missing 'module' declaration at end of global module fragment introduced here}} -#endif -#endif +extern int a; // #a1 +export module Foo; + +int a; // expected-error {{declaration of 'a' in module Foo follows declaration in the global module}} + // expected-note@#a1 {{previous decl}} +extern int b; + +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +module :private; // #priv-frag +int b; // ok +module :private; // expected-error {{private module fragment redefined}} + // expected-note@#priv-frag {{previous definition is here}} + +//--- NoGlobalFrag.cppm extern int a; // #a1 - -#ifndef NO_MODULE_DECL -export module Foo; -#ifdef NO_GLOBAL_FRAG -// expected-error@-2 {{module declaration must occur at the start of the translation unit}} -// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}} -#endif +export module Foo; // expected-error {{module declaration must occur at the start of the translation unit}} + // expected-note@-2 {{add 'module;' to the start of the file to introduce a global module fragment}} + +// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}} +// expected-note@#a1 {{previous decl}} + +int a; // #a2 +extern int b; +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +module :private; // #priv-frag +int b; // ok +module :private; // expected-error {{private module fragment redefined}} +// expected-note@#priv-frag {{previous definition is here}} + +//--- NoModuleDecl.cppm +module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}} +extern int a; // #a1 +int a; // #a2 +extern int b; +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +module :private; // expected-error {{private module fragment declaration with no preceding module declaration}} +int b; // ok + +//--- NoPrivateFrag.cppm +module; +extern int a; // #a1 +export module Foo; + +// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}} +// expected-note@#a1 {{previous decl}} +int a; // #a2 +extern int b; + +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +int b; // ok + + +//--- NoModuleDeclAndNoPrivateFrag.cppm +module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}} +extern int a; // #a1 +int a; // #a2 +extern int b; + +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} + +int b; // ok + +//--- NoGlobalFragAndNoPrivateFrag.cppm +extern int a; // #a1 +export module Foo; // expected-error {{module declaration must occur at the start of the translation unit}} +// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}} // expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}} // expected-note@#a1 {{previous decl}} -#endif int a; // #a2 extern int b; module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} -#ifndef NO_PRIVATE_FRAG -#ifdef EXPORT_FRAGS -export // expected-error {{private module fragment cannot be exported}} -#endif -module :private; // #priv-frag -#ifdef NO_MODULE_DECL -// expected-error@-2 {{private module fragment declaration with no preceding module declaration}} -#endif -#endif +int b; // ok +//--- NoGlobalFragAndNoModuleDecl.cppm +extern int a; // #a1 +int a; // #a2 +extern int b; +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +module :private; // #priv-frag +// expected-error@-1 {{private module fragment declaration with no preceding module declaration}} int b; // ok -#ifndef NO_PRIVATE_FRAG -#ifndef NO_MODULE_DECL +//--- NoGlobalFragAndNoModuleDeclAndNoPrivateFrag.cppm +extern int a; // #a1 +int a; // #a2 +extern int b; + +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +int b; // ok + +//--- ExportFrags.cppm +export module; // expected-error {{global module fragment cannot be exported}} +extern int a; // #a1 +export module Foo; +// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}} +// expected-note@#a1 {{previous decl}} + +int a; // #a2 +extern int b; + +module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} + +module :private; // #priv-frag + +int b; // ok module :private; // expected-error {{private module fragment redefined}} -// expected-note@#priv-frag {{previous definition is here}} -#endif -#endif + // expected-note@#priv-frag {{previous definition is here}} diff --git a/clang/test/CXX/basic/basic.link/p2.cpp b/clang/test/CXX/basic/basic.link/p2.cpp index ccad42022ee8..94cbc62490b2 100644 --- a/clang/test/CXX/basic/basic.link/p2.cpp +++ b/clang/test/CXX/basic/basic.link/p2.cpp @@ -1,16 +1,16 @@ -// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -verify -// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -emit-module-interface -o %t.pcm -// RUN: %clang_cc1 -std=c++2a -UEXPORT %s -verify -fmodule-file=M=%t.pcm +// RUN: rm -rf %t +// RUN: split-file %s %t -#ifdef EXPORT +// RUN: %clang_cc1 -std=c++2a %t/pmf_in_interface.cpp -verify +// RUN: %clang_cc1 -std=c++2a %t/pmf_in_interface.cpp -emit-module-interface -o %t.pcm +// RUN: %clang_cc1 -std=c++2a %t/pmf_in_implementation.cpp -verify -fmodule-file=M=%t.pcm + + +//--- pmf_in_interface.cpp // expected-no-diagnostics -export -#else -// expected-note@+2 {{add 'export' here}} -#endif -module M; - -#ifndef EXPORT -// expected-error@+2 {{private module fragment in module implementation unit}} -#endif +export module M; module :private; + +//--- pmf_in_implementation.cpp +module M; // expected-note {{add 'export' here}} +module :private; // expected-error {{private module fragment in module implementation unit}} diff --git a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp index d70eb7de22c6..fd0038b3f774 100644 --- a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp +++ b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp @@ -1,14 +1,16 @@ // RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: echo '#ifndef FOO_H' > %t/foo.h -// RUN: echo '#define FOO_H' >> %t/foo.h -// RUN: echo 'extern int in_header;' >> %t/foo.h -// RUN: echo '#endif' >> %t/foo.h -// RUN: %clang_cc1 -std=c++2a -I%t -emit-module-interface -DINTERFACE %s -o %t.pcm -// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm -DIMPLEMENTATION %s -verify -fno-modules-error-recovery -// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %s -verify -fno-modules-error-recovery +// RUN: split-file %s %t +// RUN: %clang_cc1 -std=c++2a -I%t -emit-module-interface %t/interface.cppm -o %t.pcm +// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %t/implA.cppm -verify -fno-modules-error-recovery +// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %t/implB.cppm -verify -fno-modules-error-recovery -#ifdef INTERFACE +//--- foo.h +#ifndef FOO_H +#define FOO_H +extern int in_header; +#endif + +//--- interface.cppm module; #include "foo.h" // FIXME: The following need to be moved to a header file. The global module @@ -22,11 +24,9 @@ static int internal; module :private; int not_exported_private; static int internal_private; -#else -#ifdef IMPLEMENTATION +//--- implA.cppm module; -#endif void test_early() { in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}} @@ -46,11 +46,7 @@ void test_early() { internal_private = 1; // expected-error {{undeclared identifier}} } -#ifdef IMPLEMENTATION module A; -#else -import A; -#endif void test_late() { in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} @@ -61,20 +57,54 @@ void test_late() { exported = 1; not_exported = 1; -#ifndef IMPLEMENTATION - // expected-error@-2 {{use of undeclared identifier 'not_exported'; did you mean 'exported'?}} - // expected-note@p2.cpp:18 {{'exported' declared here}} -#endif internal = 1; // expected-error {{use of undeclared identifier 'internal'}} not_exported_private = 1; -#ifndef IMPLEMENTATION - // FIXME: should not be visible here - // expected-error@-3 {{undeclared identifier}} -#endif internal_private = 1; // expected-error {{use of undeclared identifier 'internal_private'}} } -#endif +//--- implB.cppm +module; + +void test_early() { + in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}} + // expected-note@* {{not visible}} + + global_module_fragment = 1; // expected-error {{use of undeclared identifier 'global_module_fragment'}} + + exported = 1; // expected-error {{use of undeclared identifier 'exported'}} + + not_exported = 1; // expected-error {{use of undeclared identifier 'not_exported'}} + + // FIXME: We need better diagnostic message for static variable. + internal = 1; // expected-error {{use of undeclared identifier 'internal'}} + + not_exported_private = 1; // expected-error {{undeclared identifier}} + + internal_private = 1; // expected-error {{undeclared identifier}} +} + +export module B; +import A; + +void test_late() { + in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} + // expected-note@* {{not visible}} + + global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}} + + exported = 1; + + not_exported = 1; // expected-error {{use of undeclared identifier 'not_exported'; did you mean 'exported'?}} + // expected-note@* {{'exported' declared here}} + + internal = 1; // expected-error {{use of undeclared identifier 'internal'}} + + not_exported_private = 1; + // FIXME: should not be visible here + // expected-error@-2 {{undeclared identifier}} + + internal_private = 1; // expected-error {{use of undeclared identifier 'internal_private'}} +} \ No newline at end of file diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp index 8b84de0ab5a9..c9dce77b772d 100644 --- a/clang/test/CXX/drs/cwg1xx.cpp +++ b/clang/test/CXX/drs/cwg1xx.cpp @@ -702,8 +702,7 @@ namespace cwg141 { // cwg141: 3.1 // cxx98-error@#cwg141-a {{lookup of 'S' in member access expression is ambiguous; using member of 'struct A'}} // cxx98-note@#cwg141-A-S {{lookup in the object type 'struct A' refers here}} // cxx98-note@#cwg141-S {{lookup from the current scope refers here}} - // expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S'; did you mean '::cwg141::S::n'?}} - // expected-note@#cwg141-S {{'::cwg141::S::n' declared here}} + // expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S'}} // FIXME: we issue a useful diagnostic first, then some bogus ones. b.f(); // expected-error@-1 {{no member named 'f' in 'cwg141::B'}} diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index ab4d3695b6e2..60d896443ecd 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -220,7 +220,6 @@ int x = cwg2640_a\N{abc}); int y = cwg2640_a\N{LOTUS}); // expected-error@-1 {{character not allowed in an identifier}} // expected-error@-2 {{use of undeclared identifier 'cwg2640_a🪷'}} -// expected-error@-3 {{extraneous ')' before ';'}} } // namespace cwg2640 // cwg2642: na diff --git a/clang/test/CXX/module/basic/basic.def.odr/p6.cppm b/clang/test/CXX/module/basic/basic.def.odr/p6.cppm index 8e7917dc63ea..c532e7ad40a1 100644 --- a/clang/test/CXX/module/basic/basic.def.odr/p6.cppm +++ b/clang/test/CXX/module/basic/basic.def.odr/p6.cppm @@ -3,29 +3,28 @@ // RUN: split-file %s %t // // RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm -// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm -DEXPORT -// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm -DUSING +// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module-export.cppm +// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module-using.cppm // -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/global-vs-module.cppm -o %t/M.pcm -DNO_GLOBAL -DEXPORT +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/M.cppm -o %t/M.pcm // RUN: %clang_cc1 -std=c++20 -verify %t/module-vs-global.cpp -fmodule-file=M=%t/M.pcm // // Some of the following tests intentionally have no -verify in their RUN // lines; we are testing that those cases do not produce errors. // -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -DMODULE_INTERFACE -verify -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -DMODULE_INTERFACE -DNO_IMPORT +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -verify +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -DNO_IMPORT // -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N.pcm -DMODULE_INTERFACE -DNO_ERRORS -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -verify +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N.pcm -DNO_ERRORS +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -verify // -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT -verify +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT -verify // -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DMODULE_INTERFACE -DNO_ERRORS -DNO_IMPORT -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N-no-M.pcm -verify -// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=N=%t/N-no-M.pcm -DNO_IMPORT +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DNO_ERRORS -DNO_IMPORT +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N-no-M.pcm -verify +// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=N=%t/N-no-M.pcm -DNO_IMPORT //--- global-vs-module.cppm -#ifndef NO_GLOBAL module; extern int var; // expected-note {{previous declaration is here}} int func(); // expected-note {{previous declaration is here}} @@ -40,25 +39,9 @@ template using type_tpl = int; // expected-note {{previous declaration typedef int type; namespace ns { using ::func; } namespace ns_alias = ns; -#endif export module M; -#ifdef USING -using ::var; -using ::func; -using ::str; -using ::type; -using ::var_tpl; -using ::func_tpl; -using ::str_tpl; -using ::type_tpl; -#endif - -#ifdef EXPORT -export { -#endif - extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}} int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}} struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}} @@ -73,51 +56,162 @@ typedef int type; namespace ns { using ::func; } namespace ns_alias = ns; -#ifdef EXPORT -} -#endif - -//--- module-vs-global.cpp -import M; - -extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:35 {{previous}} -int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:36 {{previous}} -struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:37 {{previous}} +//--- global-vs-module-export.cppm +module; +extern int var; // expected-note {{previous declaration is here}} +int func(); // expected-note {{previous declaration is here}} +struct str; // expected-note {{previous declaration is here}} using type = int; -template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:40 {{previous}} -template int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:41 {{previous}} -template struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:42 {{previous}} -template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:43 {{previous}} +template extern int var_tpl; // expected-note {{previous declaration is here}} +template int func_tpl(); // expected-note {{previous declaration is here}} +template struct str_tpl; // expected-note {{previous declaration is here}} +template using type_tpl = int; // expected-note {{previous declaration is here}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; + +export module M; + +export { +extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}} +int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}} +struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}} +using type = int; + +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; +} + +//--- global-vs-module-using.cppm +module; +extern int var; // expected-note {{previous declaration is here}} +int func(); // expected-note {{previous declaration is here}} +struct str; // expected-note {{previous declaration is here}} +using type = int; + +template extern int var_tpl; // expected-note {{previous declaration is here}} +template int func_tpl(); // expected-note {{previous declaration is here}} +template struct str_tpl; // expected-note {{previous declaration is here}} +template using type_tpl = int; // expected-note {{previous declaration is here}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; + +export module M; + +using ::var; +using ::func; +using ::str; +using ::type; +using ::var_tpl; +using ::func_tpl; +using ::str_tpl; +using ::type_tpl; + +extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}} +int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}} +struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}} +using type = int; + +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; + +//--- M.cppm +export module M; + +export { +extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}} +int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}} +struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}} +using type = int; + +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; +} + +//--- module-vs-global.cpp +module; +import M; + +extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@M.cppm:4 {{previous}} +int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@M.cppm:5 {{previous}} +struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@M.cppm:6 {{previous}} +using type = int; + +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:9 {{previous}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:10 {{previous}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:11 {{previous}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:12 {{previous}} typedef int type; namespace ns { using ::func; } namespace ns_alias = ns; -//--- module-vs-module.cpp -#ifdef MODULE_INTERFACE export module N; -#else -module N; -#endif + +//--- module-vs-module-interface.cpp +export module N; #ifndef NO_IMPORT import M; #endif #ifndef NO_ERRORS -extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:35 {{previous}} -int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:36 {{previous}} -struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:37 {{previous}} +extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@M.cppm:4 {{previous}} +int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@M.cppm:5 {{previous}} +struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@M.cppm:6 {{previous}} using type = int; -template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:40 {{previous}} -template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:41 {{previous}} -template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:42 {{previous}} -template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:43 {{previous}} +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@M.cppm:9 {{previous}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@M.cppm:10 {{previous}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@M.cppm:11 {{previous}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@M.cppm:12 {{previous}} typedef int type; namespace ns { using ::func; } namespace ns_alias = ns; #endif +//--- module-vs-module-impl.cpp +module N; + +#ifndef NO_IMPORT +import M; +#endif + +#ifndef NO_ERRORS +extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@M.cppm:4 {{previous}} +int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@M.cppm:5 {{previous}} +struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@M.cppm:6 {{previous}} +using type = int; + +template extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@M.cppm:9 {{previous}} +template int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@M.cppm:10 {{previous}} +template struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@M.cppm:11 {{previous}} +template using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@M.cppm:12 {{previous}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; +#endif diff --git a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp index d71358cc7a57..4bdcc9e5f278 100644 --- a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp +++ b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp @@ -8,27 +8,19 @@ // RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm // // Module implementation for unknown and known module. (The former is ill-formed.) -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \ -// RUN: -DTEST=1 -DEXPORT= -DMODULE_NAME=z -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x=%t/x.pcm -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \ -// RUN: -DTEST=2 -DEXPORT= -DMODULE_NAME=x +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/z_impl.cppm +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x=%t/x.pcm -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/x_impl.cppm // // Module interface for unknown and known module. (The latter is ill-formed due to // redefinition.) -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=3 -DEXPORT=export -DMODULE_NAME=z -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=4 -DEXPORT=export -DMODULE_NAME=x +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/z_interface.cppm +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/x_interface.cppm // // Miscellaneous syntax. -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=7 -DEXPORT=export -DMODULE_NAME='z elderberry' -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=8 -DEXPORT=export -DMODULE_NAME='z [[]]' -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=9 -DEXPORT=export -DMODULE_NAME='z [[fancy]]' -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=10 -DEXPORT=export -DMODULE_NAME='z [[maybe_unused]]' +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/invalid_module_name.cppm +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/empty_attribute.cppm +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/fancy_attribute.cppm +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/maybe_unused_attribute.cppm //--- x.cppm export module x; @@ -38,17 +30,31 @@ int a, b; export module x.y; int c; -//--- M.cpp +//--- z_impl.cppm +module z; // expected-error {{module 'z' not found}} -EXPORT module MODULE_NAME; -#if TEST == 7 -// expected-error@-2 {{expected ';'}} expected-error@-2 {{a type specifier is required}} -#elif TEST == 9 -// expected-warning@-4 {{unknown attribute 'fancy' ignored}} -#elif TEST == 10 -// expected-error-re@-6 {{'maybe_unused' attribute cannot be applied to a module{{$}}}} -#elif TEST == 1 -// expected-error@-8 {{module 'z' not found}} -#else +//--- x_impl.cppm // expected-no-diagnostics -#endif +module x; + +//--- z_interface.cppm +// expected-no-diagnostics +export module z; + +//--- x_interface.cppm +// expected-no-diagnostics +export module x; + +//--- invalid_module_name.cppm +export module z elderberry; // expected-error {{expected ';'}} \ + // expected-error {{a type specifier is required}} + +//--- empty_attribute.cppm +// expected-no-diagnostics +export module z [[]]; + +//--- fancy_attribute.cppm +export module z [[fancy]]; // expected-warning {{unknown attribute 'fancy' ignored}} + +//--- maybe_unused_attribute.cppm +export module z [[maybe_unused]]; // expected-error-re {{'maybe_unused' attribute cannot be applied to a module{{$}}}} diff --git a/clang/test/CXX/module/basic/basic.link/p2.cppm b/clang/test/CXX/module/basic/basic.link/p2.cppm index d7d2b5992a23..6a2c67526c9a 100644 --- a/clang/test/CXX/module/basic/basic.link/p2.cppm +++ b/clang/test/CXX/module/basic/basic.link/p2.cppm @@ -51,7 +51,7 @@ void use_from_module_impl() { (void)external_linkage_var; (void)module_linkage_var; - (void)internal_linkage_class{}; // expected-error {{use of undeclared identifier 'internal_linkage_class'}} //expected-error{{}} + (void)internal_linkage_class{}; // expected-error {{use of undeclared identifier 'internal_linkage_class'}} // expected-note@* {{}} (void)internal_linkage_var; // expected-error {{use of undeclared identifier 'internal_linkage_var'}} } @@ -64,7 +64,7 @@ void use_from_module_impl() { internal_linkage_fn(); // expected-error {{use of undeclared identifier 'internal_linkage_fn'}} (void)external_linkage_class{}; (void)module_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} // expected-note@* {{}} - (void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} + (void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} // expected-note@* {{}} (void)external_linkage_var; (void)module_linkage_var; // expected-error {{undeclared identifier}} (void)internal_linkage_var; // expected-error {{undeclared identifier}} diff --git a/clang/test/CXX/module/cpp.pre/module_decl.cpp b/clang/test/CXX/module/cpp.pre/module_decl.cpp new file mode 100644 index 000000000000..6238347c167a --- /dev/null +++ b/clang/test/CXX/module/cpp.pre/module_decl.cpp @@ -0,0 +1,8 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o %t/M.pcm + +// This is a comment +#define I32 int // expected-note {{add 'module;' to the start of the file to introduce a global module fragment}} +export module M; // expected-error {{module declaration must occur at the start of the translation unit}} +export I32 i32; diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm index 873e4c0edeac..f65f050a3c7b 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm @@ -6,10 +6,10 @@ // RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm // RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.b.cppm -o %t/a.b.pcm // -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.cpp \ -// RUN: -DMODULE_NAME=z -DINTERFACE // RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \ -// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp -DMODULE_NAME=a.b +// RUN: -verify %t/test.interface.cpp +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \ +// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.implementation.cpp // RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.x.cpp //--- x.cppm @@ -33,19 +33,33 @@ int use_2 = b; // ok // There is no relation between module x and module x.y. int use_3 = c; // expected-error {{use of undeclared identifier 'c'}} -//--- test.cpp -#ifdef INTERFACE -export module MODULE_NAME; -#else -module MODULE_NAME; -#endif +//--- test.interface.cpp +export module z; import x; import x [[]]; import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}} import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}} -import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}} +import x [[blarg::noreturn]]; // expected-warning-re {{unknown attribute 'blarg::noreturn' ignored{{.*}}}} + +import x.y; +import x.; // expected-error {{expected a module name after 'import'}} +import .x; // expected-error {{expected a module name after 'import'}} + +import blarg; // expected-error {{module 'blarg' not found}} + +int use_4 = c; // ok + +//--- test.implementation.cpp +module a.b; + +import x; + +import x [[]]; +import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}} +import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}} +import x [[blarg::noreturn]]; // expected-warning-re {{unknown attribute 'blarg::noreturn' ignored{{.*}}}} import x.y; import x.; // expected-error {{expected a module name after 'import'}} diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.interface/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.interface/p1.cppm index 84ef85126c36..2158d7fa84b8 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.interface/p1.cppm +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.interface/p1.cppm @@ -1,29 +1,26 @@ -// RUN: %clang_cc1 -std=c++20 %s -verify -emit-module-interface -o /dev/null -// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -verify -emit-module-interface -o %t -// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -verify -fmodule-file=A=%t -o /dev/null -// -// RUN: %clang_cc1 -std=c++20 %s -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null -// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null -// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null +// RUN: rm -rf %t +// RUN: split-file %s %t -#if INTERFACE +// RUN: %clang_cc1 -std=c++20 %t/ExportDeclNotInModulePurview.cppm -verify -emit-module-interface -o /dev/null +// RUN: %clang_cc1 -std=c++20 %t/A.cppm -verify -emit-module-interface -o %t/A.pcm +// RUN: %clang_cc1 -std=c++20 %t/AddExport.cppm -verify -fmodule-file=A=%t/A.pcm -o /dev/null +// +// RUN: %clang_cc1 -std=c++20 %t/AddExport2.cppm -emit-module-interface -verify -o /dev/null + +//--- ExportDeclNotInModulePurview.cppm +// expected-error@* {{missing 'export module' declaration in module interface unit}} +export int b; // expected-error {{export declaration can only be used within a module purview}} + +//--- A.cppm // expected-no-diagnostics export module A; -#elif IMPLEMENTATION -module A; // #module-decl - #ifdef BUILT_AS_INTERFACE - // expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}} - #define INTERFACE - #endif -#else // Not in a module -// expected-error@* {{missing 'export module' declaration in module interface unit}} -#endif - -#ifndef INTERFACE -export int b; // expected-error {{export declaration can only be used within a module purview}} -#ifdef IMPLEMENTATION -// expected-note@#module-decl {{add 'export' here}} -#endif -#else export int a; -#endif + +//--- AddExport.cppm +module A; // #module-decl +export int b; // expected-error {{export declaration can only be used within a module purview}} +// expected-note@#module-decl {{add 'export' here}} + +//--- AddExport2.cppm +module A; // expected-error {{missing 'export' specifier in module declaration while building module interface}} +export int a; diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/p1.cpp b/clang/test/CXX/module/dcl.dcl/dcl.module/p1.cpp index db86b5dd34c3..95d087e0f6c7 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/p1.cpp +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/p1.cpp @@ -1,14 +1,30 @@ -// RUN: %clang_cc1 -std=c++20 -verify %s -DFOO=export -DBAR=export -// RUN: %clang_cc1 -std=c++20 -verify %s -DFOO=export -DBAR= -// RUN: %clang_cc1 -std=c++20 %s -DFOO=export -emit-module-interface -o %t -// RUN: %clang_cc1 -std=c++20 %s -fmodule-file=foo=%t -DFOO= -// RUN: %clang_cc1 -std=c++20 %s -fmodule-file=foo=%t -DBAR=export -// RUN: %clang_cc1 -std=c++20 -verify %s -fmodule-file=foo=%t -DFOO= -DBAR=export +// RUN: rm -rf %t +// RUN: split-file %s %t -#ifdef FOO -FOO module foo; // expected-note {{previous module declaration is here}} -#endif +// RUN: %clang_cc1 -std=c++20 -verify %t/A.cppm +// RUN: %clang_cc1 -std=c++20 -verify %t/B.cppm +// RUN: %clang_cc1 -std=c++20 %t/C.cppm -emit-module-interface -o %t/C.pcm +// RUN: %clang_cc1 -std=c++20 %t/D.cppm -fmodule-file=foo=%t/C.pcm +// RUN: %clang_cc1 -std=c++20 %t/E.cppm -fmodule-file=foo=%t/C.pcm +// RUN: %clang_cc1 -std=c++20 -verify %t/F.cppm -fmodule-file=foo=%t/C.pcm -#ifdef BAR -BAR module bar; // expected-error {{translation unit contains multiple module declarations}} -#endif +//--- A.cppm +export module foo; // expected-note {{previous module declaration is here}} +export module bar; // expected-error {{translation unit contains multiple module declarations}} + +//--- B.cppm +export module foo; // expected-note {{previous module declaration is here}} +module bar; // expected-error {{translation unit contains multiple module declarations}} + +//--- C.cppm +export module foo; + +//--- D.cppm +module foo; + +//--- E.cppm +export module bar; + +//--- F.cppm +module foo; // expected-note {{previous module declaration is here}} +export module bar; // expected-error {{translation unit contains multiple module declarations}} diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/p5.cpp b/clang/test/CXX/module/dcl.dcl/dcl.module/p5.cpp index ca100443a4c6..a0d30233809f 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/p5.cpp +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/p5.cpp @@ -1,22 +1,14 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t -DINTERFACE -// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DIMPLEMENTATION -// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DEARLY_IMPLEMENTATION -// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DUSER +// RUN: split-file %s %t +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/interface.cppm -o %t/interface.pcm +// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/implementation.cppm -verify -DIMPLEMENTATION +// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/early_impl.cppm -verify -DEARLY_IMPLEMENTATION +// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/user.cppm -verify -DUSER + +//--- interface.cppm // expected-no-diagnostics - -#if defined(INTERFACE) || defined(EARLY_IMPLEMENTATION) || defined(IMPLEMENTATION) module; -#endif - -#ifdef USER -import Foo; -#endif - -#ifdef EARLY_IMPLEMENTATION -module Foo; -#endif template struct type_template { typedef T type; @@ -28,10 +20,49 @@ template void type_template::f(type) {} template class = type_template> struct default_template_args {}; -#ifdef INTERFACE export module Foo; -#endif -#ifdef IMPLEMENTATION +//--- implementation.cppm +// expected-no-diagnostics +module; + +template struct type_template { + typedef T type; + void f(type); +}; + +template void type_template::f(type) {} + +template class = type_template> +struct default_template_args {}; + module Foo; -#endif + +//--- early_impl.cppm +// expected-no-diagnostics +module; +module Foo; + +template struct type_template { + typedef T type; + void f(type); +}; + +template void type_template::f(type) {} + +template class = type_template> +struct default_template_args {}; + +//--- user.cppm +// expected-no-diagnostics +import Foo; + +template struct type_template { + typedef T type; + void f(type); +}; + +template void type_template::f(type) {} + +template class = type_template> +struct default_template_args {}; diff --git a/clang/test/CXX/module/module.interface/p2.cpp b/clang/test/CXX/module/module.interface/p2.cpp index 4f06b9f38686..8221c400ecd6 100644 --- a/clang/test/CXX/module/module.interface/p2.cpp +++ b/clang/test/CXX/module/module.interface/p2.cpp @@ -1,24 +1,26 @@ // RUN: rm -rf %t // RUN: mkdir -p %t +// RUN: split-file %s %t +// // RUN: %clang_cc1 -std=c++20 -x c++-header %S/Inputs/header.h -emit-header-unit -o %t/h.pcm -// RUN: %clang_cc1 -std=c++20 %s -DX_INTERFACE -emit-module-interface -o %t/x.pcm -// RUN: %clang_cc1 -std=c++20 %s -DY_INTERFACE -emit-module-interface -o %t/y.pcm -// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -emit-module-interface -o %t/m.pcm -// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -I%S/Inputs -fmodule-file=%t/h.pcm \ +// RUN: %clang_cc1 -std=c++20 %t/x.cppm -emit-module-interface -o %t/x.pcm +// RUN: %clang_cc1 -std=c++20 %t/y.cppm -emit-module-interface -o %t/y.pcm +// RUN: %clang_cc1 -std=c++20 %t/interface.cppm -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -emit-module-interface -o %t/m.pcm +// RUN: %clang_cc1 -std=c++20 %t/impl.cppm -I%S/Inputs -fmodule-file=%t/h.pcm \ // RUN: -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -fmodule-file=p2=%t/m.pcm -verify \ // RUN: -Wno-experimental-header-units -// RUN: %clang_cc1 -std=c++20 %s -DUSER -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=p2=%t/m.pcm \ +// RUN: %clang_cc1 -std=c++20 %t/user.cppm -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=p2=%t/m.pcm \ // RUN: -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -Wno-experimental-header-units -verify -#if defined(X_INTERFACE) +//--- x.cppm export module X; export int x; -#elif defined(Y_INTERFACE) +//--- y.cppm export module Y; export int y; -#elif defined(INTERFACE) +//--- interface.cppm export module p2; export import X; import Y; // not exported @@ -39,7 +41,7 @@ namespace C {} namespace D { int f(); } export namespace D {} -#elif defined(IMPLEMENTATION) +//--- impl.cppm module p2; import "header.h"; @@ -66,7 +68,7 @@ void use() { int use_header() { return foo + bar::baz(); } -#elif defined(USER) +//--- user.cppm import p2; import "header.h"; @@ -96,7 +98,3 @@ void use() { } int use_header() { return foo + bar::baz(); } - -#else -#error unknown mode -#endif diff --git a/clang/test/CXX/module/module.unit/p8.cpp b/clang/test/CXX/module/module.unit/p8.cpp index a5c01c493558..fb190257d3a2 100644 --- a/clang/test/CXX/module/module.unit/p8.cpp +++ b/clang/test/CXX/module/module.unit/p8.cpp @@ -1,37 +1,45 @@ -// RUN: echo 'export module foo; export int n;' > %t.cppm +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// RUN: echo 'export module foo;' > %t.cppm +// RUN: echo 'export int n;' >> %t.cppm // RUN: %clang_cc1 -std=c++2a %t.cppm -emit-module-interface -o %t.pcm -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=0 %s -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=1 %s -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=2 %s -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=3 %s -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=4 %s -// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=5 %s +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=0 %t/A.cppm +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=1 %t/B.cppm +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=2 %t/C.cppm +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=3 %t/D.cppm +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=4 %t/E.cppm +// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=5 %t/F.cppm -#if MODE == 0 +//--- A.cppm // no module declaration +// expected-no-diagnostics -#elif MODE == 1 +//--- B.cppm // expected-no-diagnostics module foo; // Implementation, implicitly imports foo. #define IMPORTED -#elif MODE == 2 +int k = n; + +//--- C.cppm export module foo; -#elif MODE == 3 +int k = n; // expected-error {{use of undeclared identifier 'n'}} + +//--- D.cppm export module bar; // A different module -#elif MODE == 4 +int k = n; // expected-error {{use of undeclared identifier 'n'}} + +//--- E.cppm module foo:bar; // Partition implementation //#define IMPORTED (we don't import foo here) -#elif MODE == 5 +int k = n; // expected-error {{use of undeclared identifier 'n'}} + +//--- F.cppm export module foo:bar; // Partition interface //#define IMPORTED (we don't import foo here) -#endif - -int k = n; -#ifndef IMPORTED -// expected-error@-2 {{use of undeclared identifier 'n'}} -#endif +int k = n; // expected-error {{use of undeclared identifier 'n'}} diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp index a41f315340b5..b1232921df36 100644 --- a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp +++ b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp @@ -139,7 +139,7 @@ struct Srp { // CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8 // CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8 // CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0 -// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8, !nonnull [[META2:![0-9]+]], !align [[META3:![0-9]+]] // CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4 // CHECK-A64-NEXT: ret void // @@ -149,7 +149,7 @@ struct Srp { // CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 4 // CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4 // CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0 -// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4, !nonnull [[META2:![0-9]+]], !align [[META3:![0-9]+]] // CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4 // CHECK-A64_32-NEXT: ret void // @@ -618,3 +618,180 @@ struct SpSempty { // CHECK-A64_32-NEXT: ret void // void TpSempty(SpSempty s) { *s.x = 1; } + + +struct Spaddrspace { + __attribute__((address_space(100))) int *x; +}; +// CHECK-A64-LABEL: define dso_local void @_Z11Tpaddrspace11Spaddrspace( +// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr addrspace(100) +// CHECK-A64-NEXT: store ptr addrspace(100) [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[X]], align 8 +// CHECK-A64-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z11Tpaddrspace11Spaddrspace( +// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32 +// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[X]], align 4 +// CHECK-A64_32-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64_32-NEXT: ret void +// +void Tpaddrspace(Spaddrspace s) { *s.x = 1; } +// CHECK-A64-LABEL: define dso_local void @_Z11Cpaddrspacev( +// CHECK-A64-SAME: ) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SPADDRSPACE]], align 8 +// CHECK-A64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_TMP]], ptr align 8 [[S]], i64 8, i1 false) +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: [[COERCE_VAL_PI:%.*]] = ptrtoint ptr addrspace(100) [[TMP0]] to i64 +// CHECK-A64-NEXT: call void @_Z11Tpaddrspace11Spaddrspace(i64 [[COERCE_VAL_PI]]) +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z11Cpaddrspacev( +// CHECK-A64_32-SAME: ) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SPADDRSPACE]], align 4 +// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TMP]], ptr align 4 [[S]], i32 4, i1 false) +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_VAL_PI:%.*]] = ptrtoint ptr addrspace(100) [[TMP0]] to i32 +// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = zext i32 [[COERCE_VAL_PI]] to i64 +// CHECK-A64_32-NEXT: call void @_Z11Tpaddrspace11Spaddrspace(i64 [[COERCE_VAL_II]]) +// CHECK-A64_32-NEXT: ret void +// +void Cpaddrspace() { Spaddrspace s; Tpaddrspace(s); } + +struct Sp2addrspace { + __attribute__((address_space(100))) int *x[2]; +}; +// CHECK-A64-LABEL: define dso_local void @_Z12Tp2addrspace12Sp2addrspace( +// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SP2ADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr addrspace(100)], ptr [[X]], i64 0, i64 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[ARRAYIDX]], align 8 +// CHECK-A64-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z12Tp2addrspace12Sp2addrspace( +// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SP2ADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr addrspace(100)], ptr [[X]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[ARRAYIDX]], align 4 +// CHECK-A64_32-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64_32-NEXT: ret void +// +void Tp2addrspace(Sp2addrspace s) { *s.x[0] = 1; } +// CHECK-A64-LABEL: define dso_local void @_Z12Cp2addrspacev( +// CHECK-A64-SAME: ) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SP2ADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SP2ADDRSPACE]], align 8 +// CHECK-A64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_TMP]], ptr align 8 [[S]], i64 16, i1 false) +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load [2 x i64], ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: call void @_Z12Tp2addrspace12Sp2addrspace([2 x i64] [[TMP0]]) +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z12Cp2addrspacev( +// CHECK-A64_32-SAME: ) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SP2ADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SP2ADDRSPACE]], align 4 +// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TMP]], ptr align 4 [[S]], i32 8, i1 false) +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP2ADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load i64, ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: call void @_Z12Tp2addrspace12Sp2addrspace(i64 [[TMP0]]) +// CHECK-A64_32-NEXT: ret void +// +void Cp2addrspace() { Sp2addrspace s; Tp2addrspace(s); } + +struct Sraddrspace { + __attribute__((address_space(100))) int &x; +}; +// CHECK-A64-LABEL: define dso_local void @_Z11Traddrspace11Sraddrspace( +// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SRADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr addrspace(100) +// CHECK-A64-NEXT: store ptr addrspace(100) [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[X]], align 8, !align [[META3]] +// CHECK-A64-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z11Traddrspace11Sraddrspace( +// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32 +// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[X]], align 4, !align [[META3]] +// CHECK-A64_32-NEXT: store i32 1, ptr addrspace(100) [[TMP0]], align 4 +// CHECK-A64_32-NEXT: ret void +// +void Traddrspace(Sraddrspace s) { s.x = 1; } +// CHECK-A64-LABEL: define dso_local void @_Z11Craddrspace11Sraddrspace( +// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64-NEXT: [[ENTRY:.*:]] +// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SRADDRSPACE:%.*]], align 8 +// CHECK-A64-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SRADDRSPACE]], align 8 +// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr addrspace(100) +// CHECK-A64-NEXT: store ptr addrspace(100) [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8 +// CHECK-A64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_TMP]], ptr align 8 [[S]], i64 8, i1 false) +// CHECK-A64-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[COERCE_DIVE1]], align 8 +// CHECK-A64-NEXT: [[COERCE_VAL_PI:%.*]] = ptrtoint ptr addrspace(100) [[TMP0]] to i64 +// CHECK-A64-NEXT: call void @_Z11Traddrspace11Sraddrspace(i64 [[COERCE_VAL_PI]]) +// CHECK-A64-NEXT: ret void +// +// CHECK-A64_32-LABEL: define void @_Z11Craddrspace11Sraddrspace( +// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-A64_32-NEXT: [[ENTRY:.*:]] +// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRADDRSPACE:%.*]], align 4 +// CHECK-A64_32-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_SRADDRSPACE]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[S]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32 +// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4 +// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TMP]], ptr align 4 [[S]], i32 4, i1 false) +// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SRADDRSPACE]], ptr [[AGG_TMP]], i32 0, i32 0 +// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr addrspace(100), ptr [[COERCE_DIVE1]], align 4 +// CHECK-A64_32-NEXT: [[COERCE_VAL_PI:%.*]] = ptrtoint ptr addrspace(100) [[TMP0]] to i32 +// CHECK-A64_32-NEXT: [[COERCE_VAL_II2:%.*]] = zext i32 [[COERCE_VAL_PI]] to i64 +// CHECK-A64_32-NEXT: call void @_Z11Traddrspace11Sraddrspace(i64 [[COERCE_VAL_II2]]) +// CHECK-A64_32-NEXT: ret void +// +void Craddrspace(Sraddrspace s) { Traddrspace(s); } + +//. +// CHECK-A64: [[META2]] = !{} +// CHECK-A64: [[META3]] = !{i64 4} +//. +// CHECK-A64_32: [[META2]] = !{} +// CHECK-A64_32: [[META3]] = !{i64 4} +//. diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-dmf.c b/clang/test/CodeGen/PowerPC/builtins-ppc-dmf.c new file mode 100644 index 000000000000..41f13155847b --- /dev/null +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-dmf.c @@ -0,0 +1,94 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -O3 -triple powerpc64le-unknown-unknown -target-cpu future \ +// RUN: -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -O3 -triple powerpc64-ibm-aix -target-cpu future \ +// RUN: -emit-llvm %s -o - | FileCheck %s + + +// CHECK-LABEL: @test_dmxvi8gerx4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.dmxvi8gerx4(<256 x i1> [[TMP0]], <16 x i8> [[VC:%.*]]) +// CHECK-NEXT: store <1024 x i1> [[TMP1]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6:![0-9]+]] +// CHECK-NEXT: ret void +// +void test_dmxvi8gerx4(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_dmxvi8gerx4(&vdmr, vp, vc); + *((__dmr1024 *)resp) = vdmr; +} + +// CHECK-LABEL: @test_pmdmxvi8gerx4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.pmdmxvi8gerx4(<256 x i1> [[TMP0]], <16 x i8> [[VC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: store <1024 x i1> [[TMP1]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: ret void +// +void test_pmdmxvi8gerx4(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_pmdmxvi8gerx4(&vdmr, vp, vc, 0, 0, 0); + *((__dmr1024 *)resp) = vdmr; +} + +// CHECK-LABEL: @test_dmxvi8gerx4pp( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <1024 x i1>, ptr [[VDMRP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: [[TMP1:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.dmxvi8gerx4pp(<1024 x i1> [[TMP0]], <256 x i1> [[TMP1]], <16 x i8> [[VC:%.*]]) +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: ret void +// +void test_dmxvi8gerx4pp(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_dmxvi8gerx4pp(&vdmr, vp, vc); + *((__dmr1024 *)resp) = vdmr; +} + +// CHECK-LABEL: @test_pmdmxvi8gerx4pp( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <1024 x i1>, ptr [[VDMRP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: [[TMP1:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.pmdmxvi8gerx4pp(<1024 x i1> [[TMP0]], <256 x i1> [[TMP1]], <16 x i8> [[VC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: ret void +// +void test_pmdmxvi8gerx4pp(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_pmdmxvi8gerx4pp(&vdmr, vp, vc, 0, 0, 0); + *((__dmr1024 *)resp) = vdmr; +} + +// CHECK-LABEL: @test_dmxvi8gerx4spp( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <1024 x i1>, ptr [[VDMRP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: [[TMP1:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.dmxvi8gerx4spp(<1024 x i1> [[TMP0]], <256 x i1> [[TMP1]], <16 x i8> [[VC:%.*]]) +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: ret void +// +void test_dmxvi8gerx4spp(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_dmxvi8gerx4spp(&vdmr, vp, vc); + *((__dmr1024 *)resp) = vdmr; +} + +// CHECK-LABEL: @test_pmdmxvi8gerx4spp( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load <1024 x i1>, ptr [[VDMRP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: [[TMP1:%.*]] = load <256 x i1>, ptr [[VPP:%.*]], align 32, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = tail call <1024 x i1> @llvm.ppc.mma.pmdmxvi8gerx4spp(<1024 x i1> [[TMP0]], <256 x i1> [[TMP1]], <16 x i8> [[VC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[RESP:%.*]], align 128, !tbaa [[TBAA6]] +// CHECK-NEXT: ret void +// +void test_pmdmxvi8gerx4spp(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc, unsigned char *resp) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_pmdmxvi8gerx4spp(&vdmr, vp, vc, 0, 0, 0); + *((__dmr1024 *)resp) = vdmr; +} diff --git a/clang/test/CodeGen/PowerPC/ppc-dmf-paired-vec-memops-builtin-err.c b/clang/test/CodeGen/PowerPC/ppc-dmf-paired-vec-memops-builtin-err.c new file mode 100644 index 000000000000..eef1abca2241 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc-dmf-paired-vec-memops-builtin-err.c @@ -0,0 +1,20 @@ +// RUN: not %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu future \ +// RUN: %s -emit-llvm-only 2>&1 | FileCheck %s + +__attribute__((target("no-paired-vector-memops"))) +void test_pair(unsigned char *vdmr, unsigned char *vpp, vector unsigned char vc) { + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_dmxvi8gerx4((__dmr1024 *)vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4((__dmr1024 *)vdmr, vp, vc, 0, 0, 0); + __builtin_mma_dmxvi8gerx4pp((__dmr1024 *)vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4pp((__dmr1024 *)vdmr, vp, vc, 0, 0, 0); + __builtin_mma_dmxvi8gerx4spp((__dmr1024 *)vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4spp((__dmr1024 *)vdmr, vp, vc, 0, 0, 0); + +// CHECK: error: '__builtin_mma_dmxvi8gerx4' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_dmxvi8gerx4pp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4pp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_dmxvi8gerx4spp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4spp' needs target feature mma,paired-vector-memops +} diff --git a/clang/test/CodeGen/PowerPC/ppc-dmf-types.c b/clang/test/CodeGen/PowerPC/ppc-dmf-types.c new file mode 100644 index 000000000000..9dff289370eb --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc-dmf-types.c @@ -0,0 +1,177 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple powerpc64le-linux-unknown -target-cpu future \ +// RUN: -emit-llvm -o - %s | FileCheck %s + + +// CHECK-LABEL: @test_dmr_copy( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PTR1_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PTR2_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR1:%.*]], ptr [[PTR1_ADDR]], align 8 +// CHECK-NEXT: store ptr [[PTR2:%.*]], ptr [[PTR2_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR1_ADDR]], align 8 +// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds <1024 x i1>, ptr [[TMP0]], i64 2 +// CHECK-NEXT: [[TMP1:%.*]] = load <1024 x i1>, ptr [[ADD_PTR]], align 128 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PTR2_ADDR]], align 8 +// CHECK-NEXT: [[ADD_PTR1:%.*]] = getelementptr inbounds <1024 x i1>, ptr [[TMP2]], i64 1 +// CHECK-NEXT: store <1024 x i1> [[TMP1]], ptr [[ADD_PTR1]], align 128 +// CHECK-NEXT: ret void +// +void test_dmr_copy(__dmr1024 *ptr1, __dmr1024 *ptr2) { + *(ptr2 + 1) = *(ptr1 + 2); +} + +// CHECK-LABEL: @test_dmr_typedef( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[INP_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[OUTP_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRIN:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMROUT:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[INP:%.*]], ptr [[INP_ADDR]], align 8 +// CHECK-NEXT: store ptr [[OUTP:%.*]], ptr [[OUTP_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[INP_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRIN]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[OUTP_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[VDMROUT]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[VDMRIN]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load <1024 x i1>, ptr [[TMP2]], align 128 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[VDMROUT]], align 8 +// CHECK-NEXT: store <1024 x i1> [[TMP3]], ptr [[TMP4]], align 128 +// CHECK-NEXT: ret void +// +void test_dmr_typedef(int *inp, int *outp) { + __dmr1024 *vdmrin = (__dmr1024 *)inp; + __dmr1024 *vdmrout = (__dmr1024 *)outp; + *vdmrout = *vdmrin; +} + +// CHECK-LABEL: @test_dmr_arg( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VDMR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[VDMR:%.*]], ptr [[VDMR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMR_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load <1024 x i1>, ptr [[TMP1]], align 128 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[TMP3]], align 128 +// CHECK-NEXT: ret void +// +void test_dmr_arg(__dmr1024 *vdmr, int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = *vdmr; +} + +// CHECK-LABEL: @test_dmr_const_arg( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VDMR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[VDMR:%.*]], ptr [[VDMR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMR_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load <1024 x i1>, ptr [[TMP1]], align 128 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[TMP3]], align 128 +// CHECK-NEXT: ret void +// +void test_dmr_const_arg(const __dmr1024 *const vdmr, int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = *vdmr; +} + +// CHECK-LABEL: @test_dmr_array_arg( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VDMRA_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[VDMRA:%.*]], ptr [[VDMRA_ADDR]], align 8 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMRA_ADDR]], align 8 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds <1024 x i1>, ptr [[TMP1]], i64 0 +// CHECK-NEXT: [[TMP2:%.*]] = load <1024 x i1>, ptr [[ARRAYIDX]], align 128 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[TMP3]], align 128 +// CHECK-NEXT: ret void +// +void test_dmr_array_arg(__dmr1024 vdmra[], int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = vdmra[0]; +} + +// CHECK-LABEL: @test_dmr_ret( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds <1024 x i1>, ptr [[TMP1]], i64 2 +// CHECK-NEXT: ret ptr [[ADD_PTR]] +// +__dmr1024 *test_dmr_ret(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + return vdmrp + 2; +} + +// CHECK-LABEL: @test_dmr_ret_const( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds <1024 x i1>, ptr [[TMP1]], i64 2 +// CHECK-NEXT: ret ptr [[ADD_PTR]] +// +const __dmr1024 *test_dmr_ret_const(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + return vdmrp + 2; +} + +// CHECK-LABEL: @test_dmr_sizeof_alignof( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMRP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[VDMR:%.*]] = alloca <1024 x i1>, align 128 +// CHECK-NEXT: [[SIZET:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ALIGNT:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SIZEV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ALIGNV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[PTR:%.*]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VDMRP]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load <1024 x i1>, ptr [[TMP1]], align 128 +// CHECK-NEXT: store <1024 x i1> [[TMP2]], ptr [[VDMR]], align 128 +// CHECK-NEXT: store i32 128, ptr [[SIZET]], align 4 +// CHECK-NEXT: store i32 128, ptr [[ALIGNT]], align 4 +// CHECK-NEXT: store i32 128, ptr [[SIZEV]], align 4 +// CHECK-NEXT: store i32 128, ptr [[ALIGNV]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[SIZET]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ALIGNT]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP3]], [[TMP4]] +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[SIZEV]], align 4 +// CHECK-NEXT: [[ADD1:%.*]] = add i32 [[ADD]], [[TMP5]] +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[ALIGNV]], align 4 +// CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[TMP6]] +// CHECK-NEXT: ret i32 [[ADD2]] +// +int test_dmr_sizeof_alignof(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + __dmr1024 vdmr = *vdmrp; + unsigned sizet = sizeof(__dmr1024); + unsigned alignt = __alignof__(__dmr1024); + unsigned sizev = sizeof(vdmr); + unsigned alignv = __alignof__(vdmr); + return sizet + alignt + sizev + alignv; +} diff --git a/clang/test/CodeGen/PowerPC/ppc-future-mma-builtin-err.c b/clang/test/CodeGen/PowerPC/ppc-future-mma-builtin-err.c new file mode 100644 index 000000000000..1b8d345ac7ec --- /dev/null +++ b/clang/test/CodeGen/PowerPC/ppc-future-mma-builtin-err.c @@ -0,0 +1,21 @@ +// RUN: not %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu future \ +// RUN: %s -emit-llvm-only 2>&1 | FileCheck %s + +__attribute__((target("no-mma"))) +void test_mma(unsigned char *vdmrp, unsigned char *vpp, vector unsigned char vc) { + __dmr1024 vdmr = *((__dmr1024 *)vdmrp); + __vector_pair vp = *((__vector_pair *)vpp); + __builtin_mma_dmxvi8gerx4(&vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4(&vdmr, vp, vc, 0, 0, 0); + __builtin_mma_dmxvi8gerx4pp(&vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4pp(&vdmr, vp, vc, 0, 0, 0); + __builtin_mma_dmxvi8gerx4spp(&vdmr, vp, vc); + __builtin_mma_pmdmxvi8gerx4spp(&vdmr, vp, vc, 0, 0, 0); + +// CHECK: error: '__builtin_mma_dmxvi8gerx4' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_dmxvi8gerx4pp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4pp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_dmxvi8gerx4spp' needs target feature mma,paired-vector-memops +// CHECK: error: '__builtin_mma_pmdmxvi8gerx4spp' needs target feature mma,paired-vector-memops +} diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vrgatherei16.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vrgatherei16.c index 32469731d114..41214f7cdce2 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vrgatherei16.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vrgatherei16.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslidedown.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslidedown.c index c4e7d86e7d53..8b97ce8f760c 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslidedown.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslidedown.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslideup.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslideup.c index 0ab387525f6a..c302b2940bc6 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslideup.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vslideup.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vrgatherei16.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vrgatherei16.c index f69613c4777f..a63f0a59a34e 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vrgatherei16.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vrgatherei16.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslidedown.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslidedown.c index 14b3a99a6f0f..fb99a750a670 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslidedown.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslidedown.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslideup.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslideup.c index 1b3c3f6c0f85..77e8122890ab 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslideup.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/overloaded/vslideup.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vrgatherei16.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vrgatherei16.c index e22da32dbfa8..cf98549c41af 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vrgatherei16.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vrgatherei16.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslidedown.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslidedown.c index 205866db3566..4f1c00bef076 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslidedown.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslidedown.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslideup.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslideup.c index b32264fd88e7..c9fa994e51b3 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslideup.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/non-overloaded/vslideup.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vrgatherei16.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vrgatherei16.c index 3d53e46b4885..c50f1f731ffb 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vrgatherei16.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vrgatherei16.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslidedown.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslidedown.c index c275ee9bb2f6..476b9b59dc19 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslidedown.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslidedown.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslideup.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslideup.c index 9bd602fa5d76..1e0228e17caf 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslideup.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/policy/overloaded/vslideup.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ -// RUN: -target-feature +zvfh -disable-O0-optnone \ +// RUN: -target-feature +zvfhmin -disable-O0-optnone \ // RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ // RUN: FileCheck --check-prefix=CHECK-RV64 %s diff --git a/clang/test/CodeGen/X86/avx-cxx-record.cpp b/clang/test/CodeGen/X86/avx-cxx-record.cpp index bcd9c361fda9..6ce6815a521a 100644 --- a/clang/test/CodeGen/X86/avx-cxx-record.cpp +++ b/clang/test/CodeGen/X86/avx-cxx-record.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -O2 -target-cpu x86-64-v3 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -O2 -target-cpu x86-64-v3 -fclang-abi-compat=20 -o - | FileCheck --check-prefix CLANG-20 %s using UInt64x2 = unsigned long long __attribute__((__vector_size__(16), may_alias)); @@ -11,6 +12,7 @@ struct XMM2 : XMM1<0>, XMM1<1> { }; // CHECK: define{{.*}} @_Z3foov({{.*}} [[ARG:%.*]]){{.*}} +// CLANG-20: define{{.*}} <4 x double> @_Z3foov() // CHECK: entry: // CHECK-NEXT: store {{.*}}, ptr [[ARG]]{{.*}} // CHECK-NEXT: [[TMP1:%.*]] = getelementptr {{.*}}, ptr [[ARG]]{{.*}} diff --git a/clang/test/CodeGen/aarch64-always-inline-feature-bug.c b/clang/test/CodeGen/aarch64-always-inline-feature-bug.c new file mode 100644 index 000000000000..27c3983c66d2 --- /dev/null +++ b/clang/test/CodeGen/aarch64-always-inline-feature-bug.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple aarch64-- -target-feature +neon -target-feature +sve\ +// RUN: -target-feature -sve -emit-llvm %s -o - | FileCheck %s + +// Reproducer for bug where clang would reject always_inline for unrelated +// target features if they were disable with `-feature` on the command line. +// CHECK: @bar +__attribute__((always_inline)) __attribute__((target("neon"))) void foo() {} +void bar() { foo(); } diff --git a/clang/test/CodeGen/alias.c b/clang/test/CodeGen/alias.c index bc4167adf53f..9403c55beae0 100644 --- a/clang/test/CodeGen/alias.c +++ b/clang/test/CodeGen/alias.c @@ -29,20 +29,20 @@ const int wacom_usb_ids[] = {1, 1, 2, 3, 5, 8, 13, 0}; extern const int __mod_usb_device_table __attribute__ ((alias("wacom_usb_ids"))); // CHECKBASIC-DAG: @__mod_usb_device_table ={{.*}} alias i32, ptr @wacom_usb_ids // CHECKASM-DAG: .globl __mod_usb_device_table -// CHECKASM-DAG: .set __mod_usb_device_table, wacom_usb_ids +// CHECKASM-DAG: __mod_usb_device_table = wacom_usb_ids // CHECKASM-NOT: .size __mod_usb_device_table extern int g1; extern int g1 __attribute((alias("g0"))); // CHECKBASIC-DAG: @g1 ={{.*}} alias i32, ptr @g0 // CHECKASM-DAG: .globl g1 -// CHECKASM-DAG: .set g1, g0 +// CHECKASM-DAG: g1 = g0 // CHECKASM-NOT: .size g1 extern __thread int __libc_errno __attribute__ ((alias ("TL_WITH_ALIAS"))); // CHECKBASIC-DAG: @__libc_errno ={{.*}} thread_local alias i32, ptr @TL_WITH_ALIAS // CHECKASM-DAG: .globl __libc_errno -// CHECKASM-DAG: .set __libc_errno, TL_WITH_ALIAS +// CHECKASM-DAG: __libc_errno = TL_WITH_ALIAS // CHECKASM-NOT: .size __libc_errno void f0(void) { } diff --git a/clang/test/CodeGen/builtin_vectorelements.c b/clang/test/CodeGen/builtin_vectorelements.c index b0ff6f83b1e4..45f7a3c34562 100644 --- a/clang/test/CodeGen/builtin_vectorelements.c +++ b/clang/test/CodeGen/builtin_vectorelements.c @@ -85,7 +85,7 @@ int test_builtin_vectorelements_neon64x1() { long test_builtin_vectorelements_sve32() { // SVE: i64 @test_builtin_vectorelements_sve32( // SVE: [[VSCALE:%.+]] = call i64 @llvm.vscale.i64() - // SVE: [[RES:%.+]] = mul i64 [[VSCALE]], 4 + // SVE: [[RES:%.+]] = mul nuw i64 [[VSCALE]], 4 // SVE: ret i64 [[RES]] return __builtin_vectorelements(svuint32_t); } @@ -93,7 +93,7 @@ long test_builtin_vectorelements_sve32() { long test_builtin_vectorelements_sve8() { // SVE: i64 @test_builtin_vectorelements_sve8( // SVE: [[VSCALE:%.+]] = call i64 @llvm.vscale.i64() - // SVE: [[RES:%.+]] = mul i64 [[VSCALE]], 16 + // SVE: [[RES:%.+]] = mul nuw i64 [[VSCALE]], 16 // SVE: ret i64 [[RES]] return __builtin_vectorelements(svuint8_t); } @@ -105,7 +105,7 @@ long test_builtin_vectorelements_sve8() { long test_builtin_vectorelements_riscv8() { // RISCV: i64 @test_builtin_vectorelements_riscv8( // RISCV: [[VSCALE:%.+]] = call i64 @llvm.vscale.i64() - // RISCV: [[RES:%.+]] = mul i64 [[VSCALE]], 8 + // RISCV: [[RES:%.+]] = mul nuw i64 [[VSCALE]], 8 // RISCV: ret i64 [[RES]] return __builtin_vectorelements(vuint8m1_t); } @@ -120,7 +120,7 @@ long test_builtin_vectorelements_riscv64() { long test_builtin_vectorelements_riscv32m2() { // RISCV: i64 @test_builtin_vectorelements_riscv32m2( // RISCV: [[VSCALE:%.+]] = call i64 @llvm.vscale.i64() - // RISCV: [[RES:%.+]] = mul i64 [[VSCALE]], 4 + // RISCV: [[RES:%.+]] = mul nuw i64 [[VSCALE]], 4 // RISCV: ret i64 [[RES]] return __builtin_vectorelements(vuint32m2_t); } diff --git a/clang/test/CodeGen/debug-info-version-coff.c b/clang/test/CodeGen/debug-info-version-coff.c new file mode 100644 index 000000000000..6497a5829236 --- /dev/null +++ b/clang/test/CodeGen/debug-info-version-coff.c @@ -0,0 +1,8 @@ +// REQUIRES: x86-registered-target +// RUN: %clang --target=x86_64-windows -g -S -emit-llvm -o - %s | FileCheck %s +// RUN: %clang --target=x86_64-windows -S -emit-llvm -o - %s | FileCheck %s +int main (void) { + return 0; +} + +// CHECK: i32 2, !"Debug Info Version", i32 3} diff --git a/clang/test/CodeGen/debug-info-version.c b/clang/test/CodeGen/debug-info-version.c index fa7e20e7f527..c7c2bb95017a 100644 --- a/clang/test/CodeGen/debug-info-version.c +++ b/clang/test/CodeGen/debug-info-version.c @@ -1,3 +1,4 @@ +// REQUIRES: !system-windows // RUN: %clang -g -S -emit-llvm -o - %s | FileCheck %s // RUN: %clang -S -emit-llvm -o - %s | FileCheck %s --check-prefix=NO_DEBUG int main (void) { diff --git a/clang/test/CodeGen/epilog-unwind.c b/clang/test/CodeGen/epilog-unwind.c index 991ff09fb37c..b2f7497b455b 100644 --- a/clang/test/CodeGen/epilog-unwind.c +++ b/clang/test/CodeGen/epilog-unwind.c @@ -1,9 +1,11 @@ // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED -// RUN: %clang_cc1 -fwinx64-eh-unwindv2 -emit-llvm %s -o - | FileCheck %s -check-prefix=ENABLED -// RUN: %clang -fwinx64-eh-unwindv2 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=ENABLED -// RUN: %clang -fno-winx64-eh-unwindv2 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED +// RUN: %clang_cc1 -fwinx64-eh-unwindv2=disabled -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED +// RUN: %clang_cc1 -fwinx64-eh-unwindv2=best-effort -emit-llvm %s -o - | FileCheck %s -check-prefix=BESTEFFORT +// RUN: %clang_cc1 -fwinx64-eh-unwindv2=required -emit-llvm %s -o - | FileCheck %s -check-prefix=REQUIRED +// RUN: %clang -fwinx64-eh-unwindv2=best-effort -S -emit-llvm %s -o - | FileCheck %s -check-prefix=BESTEFFORT void f(void) {} -// ENABLED: !"winx64-eh-unwindv2", i32 1} +// BESTEFFORT: !"winx64-eh-unwindv2", i32 1} +// REQUIRED: !"winx64-eh-unwindv2", i32 2} // DISABLED-NOT: "winx64-eh-unwindv2" diff --git a/clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp b/clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp index cd5a18f39060..a0e76e8a9a0b 100644 --- a/clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp +++ b/clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp @@ -35,5 +35,5 @@ int &g() { return r; } // DARWIN-LABEL: define internal cxx_fast_tlscc void @__tls_init() // CHECK: call void @[[R_INIT]]() -// LINUX_AIX: attributes [[ATTR0]] = { {{.*}}"target-features"{{.*}} } +// LINUX_AIX: attributes [[ATTR0]] = { {{.*}} } // DARWIN: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}}"target-features"{{.*}} } diff --git a/clang/test/CodeGenCXX/debug-info-coff.cpp b/clang/test/CodeGenCXX/debug-info-coff.cpp new file mode 100644 index 000000000000..2535c5cc7511 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-coff.cpp @@ -0,0 +1,37 @@ +// REQUIRES: x86-registered-target + +// Check that CodeView compiler version is emitted even when debug info is otherwise disabled. + +// RUN: %clang --target=i686-pc-windows-msvc -S -emit-llvm %s -o - | FileCheck --check-prefix=IR %s +// IR: !llvm.dbg.cu = !{!0} +// IR: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "{{.*}}", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None) + +// RUN: %clang --target=i686-pc-windows-msvc -c %s -o %t.o +// RUN: llvm-readobj --codeview %t.o | FileCheck %s +// CHECK: CodeViewDebugInfo [ +// CHECK-NEXT: Section: .debug$S (4) +// CHECK-NEXT: Magic: 0x4 +// CHECK-NEXT: Subsection [ +// CHECK-NEXT: SubSectionType: Symbols (0xF1) +// CHECK-NEXT: SubSectionSize: +// CHECK-NEXT: ObjNameSym { +// CHECK-NEXT: Kind: S_OBJNAME (0x1101) +// CHECK-NEXT: Signature: 0x0 +// CHECK-NEXT: ObjectName: +// CHECK-NEXT: } +// CHECK-NEXT: Compile3Sym { +// CHECK-NEXT: Kind: S_COMPILE3 (0x113C) +// CHECK-NEXT: Language: Cpp (0x1) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Machine: Pentium3 (0x7) +// CHECK-NEXT: FrontendVersion: +// CHECK-NEXT: BackendVersion: +// CHECK-NEXT: VersionName: {{.*}}clang version +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: ] + +int main() { + return 0; +} diff --git a/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp b/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp index 10fb1750f2c5..ff2dfc19961c 100644 --- a/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp +++ b/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp @@ -11,12 +11,9 @@ // RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH // HOTPATCH: S_COMPILE3 [size = [[#]]] // HOTPATCH: flags = hot patchable -/// -/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3. -/// +// // RUN: %clang_cl --target=aarch64-pc-windows-msvc /c -o %t.obj -- %s -// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH -// NO-HOTPATCH-NOT: flags = hot patchable +// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH int main() { return 0; diff --git a/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp b/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp index 48a61f7fb197..e31c762b0887 100644 --- a/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp +++ b/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp @@ -11,12 +11,9 @@ // RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH // HOTPATCH: S_COMPILE3 [size = [[#]]] // HOTPATCH: flags = hot patchable -/// -/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3. -/// +// // RUN: %clang_cl --target=arm-pc-windows-msvc /c -o %t.obj -- %s -// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH -// NO-HOTPATCH-NOT: flags = hot patchable +// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH int main() { return 0; diff --git a/clang/test/CodeGenCXX/ppc-mangle-mma-types.cpp b/clang/test/CodeGenCXX/ppc-mangle-mma-types.cpp index 74e50ceea386..1e213e7f7512 100644 --- a/clang/test/CodeGenCXX/ppc-mangle-mma-types.cpp +++ b/clang/test/CodeGenCXX/ppc-mangle-mma-types.cpp @@ -1,3 +1,5 @@ +// RUN: %clang_cc1 -triple powerpc64le-linux-unknown -target-cpu future %s \ +// RUN: -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple powerpc64le-linux-unknown -target-cpu pwr10 %s \ // RUN: -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple powerpc64le-linux-unknown -target-cpu pwr9 %s \ @@ -5,6 +7,9 @@ // RUN: %clang_cc1 -triple powerpc64le-linux-unknown -target-cpu pwr8 %s \ // RUN: -emit-llvm -o - | FileCheck %s +// CHECK: _Z2f0Pu9__dmr1024 +void f0(__dmr1024 *vdmr) {} + // CHECK: _Z2f1Pu13__vector_quad void f1(__vector_quad *vq) {} diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl index c3204570d6ef..aaa486eff10b 100644 --- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl +++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl @@ -7,10 +7,10 @@ struct S { // CHECK: [[CBLayout:%.*]] = type <{ [2 x float], [2 x <4 x i32>], [2 x [2 x i32]], [1 x target("dx.Layout", %S, 8, 0, 4)] }> // CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", [[CBLayout]], 136, 0, 32, 64, 128)) -// CHECK: @c1 = external addrspace(2) global [2 x float], align 4 -// CHECK: @c2 = external addrspace(2) global [2 x <4 x i32>], align 16 -// CHECK: @c3 = external addrspace(2) global [2 x [2 x i32]], align 4 -// CHECK: @c4 = external addrspace(2) global [1 x target("dx.Layout", %S, 8, 0, 4)], align 1 +// CHECK: @c1 = external hidden addrspace(2) global [2 x float], align 4 +// CHECK: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 16 +// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x i32]], align 4 +// CHECK: @c4 = external hidden addrspace(2) global [1 x target("dx.Layout", %S, 8, 0, 4)], align 1 cbuffer CBArrays : register(b0) { float c1[2]; @@ -19,7 +19,7 @@ cbuffer CBArrays : register(b0) { S c4[1]; } -// CHECK-LABEL: define void {{.*}}arr_assign1 +// CHECK-LABEL: define hidden void {{.*}}arr_assign1 // CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 // CHECK-NOT: alloca @@ -33,7 +33,7 @@ void arr_assign1() { Arr = Arr2; } -// CHECK-LABEL: define void {{.*}}arr_assign2 +// CHECK-LABEL: define hidden void {{.*}}arr_assign2 // CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4 @@ -51,7 +51,7 @@ void arr_assign2() { Arr = Arr2 = Arr3; } -// CHECK-LABEL: define void {{.*}}arr_assign3 +// CHECK-LABEL: define hidden void {{.*}}arr_assign3 // CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NOT: alloca @@ -65,7 +65,7 @@ void arr_assign3() { Arr2 = Arr3; } -// CHECK-LABEL: define void {{.*}}arr_assign4 +// CHECK-LABEL: define hidden void {{.*}}arr_assign4 // CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 // CHECK-NOT: alloca @@ -81,7 +81,7 @@ void arr_assign4() { (Arr = Arr2)[0] = 6; } -// CHECK-LABEL: define void {{.*}}arr_assign5 +// CHECK-LABEL: define hidden void {{.*}}arr_assign5 // CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4 @@ -101,7 +101,7 @@ void arr_assign5() { (Arr = Arr2 = Arr3)[0] = 6; } -// CHECK-LABEL: define void {{.*}}arr_assign6 +// CHECK-LABEL: define hidden void {{.*}}arr_assign6 // CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NOT: alloca @@ -118,7 +118,7 @@ void arr_assign6() { (Arr = Arr2)[0][0] = 6; } -// CHECK-LABEL: define void {{.*}}arr_assign7 +// CHECK-LABEL: define hidden void {{.*}}arr_assign7 // CHECK: [[Arr:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NOT: alloca @@ -138,7 +138,7 @@ void arr_assign7() { // Verify you can assign from a cbuffer array -// CHECK-LABEL: define void {{.*}}arr_assign8 +// CHECK-LABEL: define hidden void {{.*}}arr_assign8 // CHECK: [[C:%.*]] = alloca [2 x float], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c1, i32 8, i1 false) @@ -148,7 +148,7 @@ void arr_assign8() { C = c1; } -// CHECK-LABEL: define void {{.*}}arr_assign9 +// CHECK-LABEL: define hidden void {{.*}}arr_assign9 // CHECK: [[C:%.*]] = alloca [2 x <4 x i32>], align 16 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[C]], ptr align 16 {{.*}}, i32 32, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 16 [[C]], ptr addrspace(2) align 16 @c2, i32 32, i1 false) @@ -158,7 +158,7 @@ void arr_assign9() { C = c2; } -// CHECK-LABEL: define void {{.*}}arr_assign10 +// CHECK-LABEL: define hidden void {{.*}}arr_assign10 // CHECK: [[C:%.*]] = alloca [2 x [2 x i32]], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 16, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c3, i32 16, i1 false) @@ -168,7 +168,7 @@ void arr_assign10() { C = c3; } -// CHECK-LABEL: define void {{.*}}arr_assign11 +// CHECK-LABEL: define hidden void {{.*}}arr_assign11 // CHECK: [[C:%.*]] = alloca [1 x %struct.S], align 1 // CHECK: call void @llvm.memcpy.p0.p2.i32(ptr align 1 [[C]], ptr addrspace(2) align 1 @c4, i32 8, i1 false) // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenHLSL/ArrayTemporary.hlsl b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl index 29ea896045bb..42a469ae8795 100644 --- a/clang/test/CodeGenHLSL/ArrayTemporary.hlsl +++ b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl @@ -3,7 +3,7 @@ void fn(float x[2]) { } -// CHECK-LABEL: define void {{.*}}call{{.*}} +// CHECK-LABEL: define hidden void {{.*}}call{{.*}} // CHECK: [[Arr:%.*]] = alloca [2 x float] // CHECK: [[Tmp:%.*]] = alloca [2 x float] // CHECK: call void @llvm.memset.p0.i32(ptr align 4 [[Arr]], i8 0, i32 8, i1 false) @@ -21,7 +21,7 @@ struct Obj { void fn2(Obj O[4]) { } -// CHECK-LABEL: define void {{.*}}call2{{.*}} +// CHECK-LABEL: define hidden void {{.*}}call2{{.*}} // CHECK: [[Arr:%.*]] = alloca [4 x %struct.Obj] // CHECK: [[Tmp:%.*]] = alloca [4 x %struct.Obj] // CHECK: call void @llvm.memset.p0.i32(ptr align 1 [[Arr]], i8 0, i32 32, i1 false) @@ -35,7 +35,7 @@ void call2() { void fn3(float x[2][2]) { } -// CHECK-LABEL: define void {{.*}}call3{{.*}} +// CHECK-LABEL: define hidden void {{.*}}call3{{.*}} // CHECK: [[Arr:%.*]] = alloca [2 x [2 x float]] // CHECK: [[Tmp:%.*]] = alloca [2 x [2 x float]] // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{.*}}, i32 16, i1 false) @@ -46,7 +46,7 @@ void call3() { fn3(Arr); } -// CHECK-LABEL: define void {{.*}}call4{{.*}}(ptr +// CHECK-LABEL: define hidden void {{.*}}call4{{.*}}(ptr // CHECK-SAME: noundef byval([2 x [2 x float]]) align 4 [[Arr:%.*]]) // CHECK: [[Tmp:%.*]] = alloca [2 x [2 x float]] // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 16, i1 false) @@ -59,7 +59,7 @@ void call4(float Arr[2][2]) { // Verify that each template instantiation codegens to a unique and correctly // mangled function name. -// CHECK-LABEL: define void {{.*}}template_call{{.*}}(ptr +// CHECK-LABEL: define hidden void {{.*}}template_call{{.*}}(ptr // CHECK-SAME: noundef byval([2 x float]) align 4 [[FA2:%[0-9A-Z]+]], // CHECK-SAME: ptr noundef byval([4 x float]) align 4 [[FA4:%[0-9A-Z]+]], @@ -86,7 +86,7 @@ void template_call(float FA2[2], float FA4[4], int IA3[3]) { // Verify that Array parameter element access correctly codegens. -// CHECK-LABEL: define void {{.*}}element_access{{.*}}(ptr +// CHECK-LABEL: define hidden void {{.*}}element_access{{.*}}(ptr // CHECK-SAME: noundef byval([2 x float]) align 4 [[FA2:%[0-9A-Z]+]] // CHECK: [[Addr:%.*]] = getelementptr inbounds [2 x float], ptr [[FA2]], i32 0, i32 0 diff --git a/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl index eb7d755bca61..bccfaf597f0e 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl @@ -11,7 +11,7 @@ void increment(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void @{{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -32,7 +32,7 @@ void fn2(out int Arr[2]) { // CHECK: [[A:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}fn2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void @{{.*}}fn2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -56,7 +56,7 @@ void nestedCall(inout int Arr[2], uint index) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}nestedCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]], i32 noundef 0) #3 +// CHECK-NEXT: call void @{{.*}}nestedCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]], i32 noundef 0) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 1 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -70,7 +70,7 @@ export int arrayCall3() { // CHECK-LABEL: outerCall // CHECK: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 %{{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void {{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void {{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{.*}}, ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: ret void void outerCall(inout int Arr[2]) { @@ -82,7 +82,7 @@ void outerCall(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}outerCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void @{{.*}}outerCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -99,7 +99,7 @@ void fn3(int Arr[2]) {} // CHECK-LABEL: outerCall2 // CHECK: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 {{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void {{.*}}fn3{{.*}}(ptr noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void {{.*}}fn3{{.*}}(ptr noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: ret void void outerCall2(inout int Arr[2]) { fn3(Arr); @@ -110,7 +110,7 @@ void outerCall2(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}outerCall2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) #3 +// CHECK-NEXT: call void @{{.*}}outerCall2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl index 371f31c9e4af..c30c640519cd 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl @@ -46,7 +46,7 @@ struct SlicyBits { }; // Case 1: Extraneous braces get ignored in literal instantiation. -// CHECK-LABEL: define void @_Z5case1v( +// CHECK-LABEL: define hidden void @_Z5case1v( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_RESULT]], ptr align 1 @__const._Z5case1v.TF1, i32 8, i1 false) @@ -58,7 +58,7 @@ TwoFloats case1() { } // Case 2: Valid C/C++ initializer is handled appropriately. -// CHECK-LABEL: define void @_Z5case2v( +// CHECK-LABEL: define hidden void @_Z5case2v( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_RESULT]], ptr align 1 @__const._Z5case2v.TF2, i32 8, i1 false) @@ -70,7 +70,7 @@ TwoFloats case2() { } // Case 3: Simple initialization with conversion of an argument. -// CHECK-LABEL: define void @_Z5case3i( +// CHECK-LABEL: define hidden void @_Z5case3i( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], i32 noundef [[VAL:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i32, align 4 @@ -90,7 +90,7 @@ TwoFloats case3(int Val) { // Case 4: Initialization from a scalarized vector into a structure with element // conversions. -// CHECK-LABEL: define void @_Z5case4Dv2_i( +// CHECK-LABEL: define hidden void @_Z5case4Dv2_i( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], <2 x i32> noundef [[TWOVALS:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TWOVALS_ADDR:%.*]] = alloca <2 x i32>, align 8 @@ -113,7 +113,7 @@ TwoFloats case4(int2 TwoVals) { } // Case 5: Initialization from a scalarized vector of matching type. -// CHECK-LABEL: define void @_Z5case5Dv2_i( +// CHECK-LABEL: define hidden void @_Z5case5Dv2_i( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 1 [[AGG_RESULT:%.*]], <2 x i32> noundef [[TWOVALS:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TWOVALS_ADDR:%.*]] = alloca <2 x i32>, align 8 @@ -135,7 +135,7 @@ TwoInts case5(int2 TwoVals) { // Case 6: Initialization from a scalarized structure of different type with // different element types. -// CHECK-LABEL: define void @_Z5case69TwoFloats( +// CHECK-LABEL: define hidden void @_Z5case69TwoFloats( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 1 [[TF4:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -157,7 +157,7 @@ TwoInts case6(TwoFloats TF4) { // Case 7: Initialization of a complex structure, with bogus braces and element // conversions from a collection of scalar values, and structures. -// CHECK-LABEL: define void @_Z5case77TwoIntsS_i9TwoFloatsS0_S0_S0_( +// CHECK-LABEL: define hidden void @_Z5case77TwoIntsS_i9TwoFloatsS0_S0_S0_( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_DOGGO:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 1 [[TI1:%.*]], ptr noundef byval([[STRUCT_TWOINTS]]) align 1 [[TI2:%.*]], i32 noundef [[VAL:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 1 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 1 [[TF2:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 1 [[TF3:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 1 [[TF4:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i32, align 4 @@ -221,7 +221,7 @@ Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2, // Case 8: Initialization of a structure from a different structure with // significantly different element types and grouping. -// CHECK-LABEL: define void @_Z5case85Doggo( +// CHECK-LABEL: define hidden void @_Z5case85Doggo( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_ANIMALBITS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_DOGGO:%.*]]) align 1 [[D1:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[LEGS:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -307,7 +307,7 @@ AnimalBits case8(Doggo D1) { // Case 9: Everything everywhere all at once... Initializing mismatched // structures from different layouts, different component groupings, with no // top-level bracing separation. -// CHECK-LABEL: define void @_Z5case95Doggo10AnimalBits( +// CHECK-LABEL: define hidden void @_Z5case95Doggo10AnimalBits( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_ZOO:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_DOGGO:%.*]]) align 1 [[D1:%.*]], ptr noundef byval([[STRUCT_ANIMALBITS:%.*]]) align 1 [[A1:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[DOGS:%.*]] = getelementptr inbounds nuw [[STRUCT_ZOO]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -723,7 +723,7 @@ Zoo case9(Doggo D1, AnimalBits A1) { } // Case 10: Initialize an object with a base class from two objects. -// CHECK-LABEL: define void @_Z6case109TwoFloatsS_( +// CHECK-LABEL: define hidden void @_Z6case109TwoFloatsS_( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 1 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 1 [[TF2:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -750,7 +750,7 @@ FourFloats case10(TwoFloats TF1, TwoFloats TF2) { } // Case 11: Initialize an object with a base class from a vector splat. -// CHECK-LABEL: define void @_Z6case11f( +// CHECK-LABEL: define hidden void @_Z6case11f( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], float noundef nofpclass(nan inf) [[F:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[F_ADDR:%.*]] = alloca float, align 4 @@ -799,7 +799,7 @@ FourFloats case11(float F) { } // Case 12: Initialize bitfield from two integers. -// CHECK-LABEL: define void @_Z6case12ii( +// CHECK-LABEL: define hidden void @_Z6case12ii( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 1 [[AGG_RESULT:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 @@ -821,7 +821,7 @@ SlicyBits case12(int I, int J) { } // Case 13: Initialize bitfield from a struct of two ints. -// CHECK-LABEL: define void @_Z6case137TwoInts( +// CHECK-LABEL: define hidden void @_Z6case137TwoInts( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 1 [[TI:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0 @@ -841,7 +841,7 @@ SlicyBits case13(TwoInts TI) { } // Case 14: Initialize struct of ints from struct with bitfields. -// CHECK-LABEL: define void @_Z6case149SlicyBits( +// CHECK-LABEL: define hidden void @_Z6case149SlicyBits( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 1 [[SB:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -861,7 +861,7 @@ TwoInts case14(SlicyBits SB) { } // Case 15: Initialize struct of floats from struct with bitfields. -// CHECK-LABEL: define void @_Z6case159SlicyBits( +// CHECK-LABEL: define hidden void @_Z6case159SlicyBits( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 1 [[SB:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0 @@ -884,7 +884,7 @@ TwoFloats case15(SlicyBits SB) { // Case 16: Side-effecting initialization list arguments. The important thing // here is that case16 only has _one_ call to makeTwo. -// CHECK-LABEL: define void @_Z7makeTwoRf( +// CHECK-LABEL: define hidden void @_Z7makeTwoRf( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noalias noundef nonnull align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X_ADDR:%.*]] = alloca ptr, align 4 @@ -910,7 +910,7 @@ TwoFloats makeTwo(inout float X) { return TF; } -// CHECK-LABEL: define void @_Z6case16v( +// CHECK-LABEL: define hidden void @_Z6case16v( // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 1 [[AGG_RESULT:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X:%.*]] = alloca float, align 4 @@ -948,7 +948,7 @@ int case17Helper(int x) { } // InitList with OpaqueValueExpr -// CHECK-LABEL: define void {{.*}}case17 +// CHECK-LABEL: define hidden void {{.*}}case17 // CHECK: [[X:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: [[C:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 0) // CHECK-NEXT: [[C1:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 1) diff --git a/clang/test/CodeGenHLSL/BasicFeatures/OutputArguments.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/OutputArguments.hlsl index 1f45a7f9b46d..d0ba8f447b73 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/OutputArguments.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/OutputArguments.hlsl @@ -6,7 +6,7 @@ // integer. It is converted to an integer on call and converted back after the // function. -// CHECK: define void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) +// CHECK: define hidden void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) void trunc_Param(inout int X) {} // ALL-LABEL: define noundef nofpclass(nan inf) float {{.*}}case1 @@ -32,7 +32,7 @@ export float case1(float F) { // uninitialized in the function. If they are not initialized before the // function returns the value is undefined. -// CHECK: define void {{.*}}undef{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) +// CHECK: define hidden void {{.*}}undef{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) void undef(out int Z) { } // ALL-LABEL: define noundef i32 {{.*}}case2 @@ -54,7 +54,7 @@ export int case2() { // This test should verify that an out parameter value is written to as // expected. -// CHECK: define void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) +// CHECK: define hidden void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) void zero(out int Z) { Z = 0; } // ALL-LABEL: define noundef i32 {{.*}}case3 @@ -76,7 +76,7 @@ export int case3() { // Vector swizzles in HLSL produce lvalues, so they can be used as arguments to // inout parameters and the swizzle is reversed on writeback. -// CHECK: define void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) +// CHECK: define hidden void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) void funky(inout int3 X) { X.x += 1; X.y += 2; @@ -116,7 +116,7 @@ export int3 case4() { // Case 5: Straightforward inout of a scalar value. -// CHECK: define void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) +// CHECK: define hidden void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) void increment(inout int I) { I += 1; } @@ -144,7 +144,7 @@ struct S { float Y; }; -// CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 1 dereferenceable(8) {{%.*}}) +// CHECK: define hidden void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 1 dereferenceable(8) {{%.*}}) void init(out S s) { s.X = 3; s.Y = 4; @@ -170,7 +170,7 @@ struct R { float Y; }; -// CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 1 dereferenceable(8) {{%.*}}) +// CHECK: define hidden void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 1 dereferenceable(8) {{%.*}}) void init(inout R s) { s.X = 3; s.Y = 4; @@ -194,7 +194,7 @@ export int case7() { // Case 8: Non-scalars with a cast expression. -// CHECK: define void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) +// CHECK: define hidden void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) void trunc_vec(inout int3 V) {} // ALL-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}case8 diff --git a/clang/test/CodeGenHLSL/Bool.hlsl b/clang/test/CodeGenHLSL/Bool.hlsl index fb0f32b11241..21328c1f9d4d 100644 --- a/clang/test/CodeGenHLSL/Bool.hlsl +++ b/clang/test/CodeGenHLSL/Bool.hlsl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK-LABEL: define noundef i1 {{.*}}fn{{.*}}(i1 noundef %x) +// CHECK-LABEL: define hidden noundef i1 {{.*}}fn{{.*}}(i1 noundef %x) // CHECK: [[X:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[Y:%.*]] = zext i1 {{%.*}} to i32 // CHECK-NEXT: store i32 [[Y]], ptr [[X]], align 4 diff --git a/clang/test/CodeGenHLSL/BoolVector.hlsl b/clang/test/CodeGenHLSL/BoolVector.hlsl index 35d8b9dac801..d5054a5a92b5 100644 --- a/clang/test/CodeGenHLSL/BoolVector.hlsl +++ b/clang/test/CodeGenHLSL/BoolVector.hlsl @@ -9,7 +9,7 @@ struct S { float f; }; -// CHECK-LABEL: define noundef i1 {{.*}}fn1{{.*}} +// CHECK-LABEL: define hidden noundef i1 {{.*}}fn1{{.*}} // CHECK: [[B:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[B]], align 8 // CHECK-NEXT: [[BoolVec:%.*]] = load <2 x i32>, ptr [[B]], align 8 @@ -21,7 +21,7 @@ bool fn1() { return B[0]; } -// CHECK-LABEL: define noundef <2 x i1> {{.*}}fn2{{.*}} +// CHECK-LABEL: define hidden noundef <2 x i1> {{.*}}fn2{{.*}} // CHECK: [[VAddr:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[A:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: [[StoreV:%.*]] = zext i1 {{.*}} to i32 @@ -40,7 +40,7 @@ bool2 fn2(bool V) { return A; } -// CHECK-LABEL: define noundef i1 {{.*}}fn3{{.*}} +// CHECK-LABEL: define hidden noundef i1 {{.*}}fn3{{.*}} // CHECK: [[s:%.*]] = alloca %struct.S, align 1 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[s]], ptr align 1 [[ConstS]], i32 12, i1 false) // CHECK-NEXT: [[BV:%.*]] = getelementptr inbounds nuw %struct.S, ptr [[s]], i32 0, i32 0 @@ -53,7 +53,7 @@ bool fn3() { return s.bv[0]; } -// CHECK-LABEL: define noundef i1 {{.*}}fn4{{.*}} +// CHECK-LABEL: define hidden noundef i1 {{.*}}fn4{{.*}} // CHECK: [[Arr:%.*]] = alloca [2 x <2 x i32>], align 8 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[Arr]], ptr align 8 [[ConstArr]], i32 16, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x <2 x i32>], ptr [[Arr]], i32 0, i32 0 @@ -66,7 +66,7 @@ bool fn4() { return Arr[0][1]; } -// CHECK-LABEL: define void {{.*}}fn5{{.*}} +// CHECK-LABEL: define hidden void {{.*}}fn5{{.*}} // CHECK: [[Arr:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[Arr]], align 8 // CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[Arr]], align 8 @@ -78,7 +78,7 @@ void fn5() { Arr[1] = false; } -// CHECK-LABEL: define void {{.*}}fn6{{.*}} +// CHECK-LABEL: define hidden void {{.*}}fn6{{.*}} // CHECK: [[V:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[S:%.*]] = alloca %struct.S, align 1 // CHECK-NEXT: store i32 0, ptr [[V]], align 4 @@ -97,7 +97,7 @@ void fn6() { s.bv[1] = V; } -// CHECK-LABEL: define void {{.*}}fn7{{.*}} +// CHECK-LABEL: define hidden void {{.*}}fn7{{.*}} // CHECK: [[Arr:%.*]] = alloca [2 x <2 x i32>], align 8 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[Arr]], ptr align 8 {{.*}}, i32 16, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x <2 x i32>], ptr [[Arr]], i32 0, i32 0 diff --git a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl index 9090e9e85ed9..afda714106fa 100644 --- a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl +++ b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl @@ -33,7 +33,7 @@ void SecondEntry() {} // Verify the constructor is alwaysinline // NOINLINE: ; Function Attrs: {{.*}}alwaysinline -// NOINLINE-NEXT: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2EjijjPKc({{.*}} [[CtorAttr:\#[0-9]+]] +// NOINLINE-NEXT: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIfEC2EjijjPKc({{.*}} [[CtorAttr:\#[0-9]+]] // NOINLINE: ; Function Attrs: {{.*}}alwaysinline // NOINLINE-NEXT: define internal void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl() [[InitAttr:\#[0-9]+]] diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl index ca843ffbb1ce..6618ca741aa9 100644 --- a/clang/test/CodeGenHLSL/RootSignature.hlsl +++ b/clang/test/CodeGenHLSL/RootSignature.hlsl @@ -3,14 +3,14 @@ // CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]], // CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]], ![[#RD_ENTRY:]], ![[#SS_ENTRY:]]} -// CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]} +// CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]], i32 2} // CHECK: ![[#EMPTY]] = !{} [shader("compute"), RootSignature("")] [numthreads(1,1,1)] void EmptyEntry() {} -// CHECK: ![[#DT_ENTRY]] = !{ptr @DescriptorTableEntry, ![[#DT_RS:]]} +// CHECK: ![[#DT_ENTRY]] = !{ptr @DescriptorTableEntry, ![[#DT_RS:]], i32 2} // CHECK: ![[#DT_RS]] = !{![[#TABLE:]]} // CHECK: ![[#TABLE]] = !{!"DescriptorTable", i32 0, ![[#CBV:]], ![[#SRV:]]} // CHECK: ![[#CBV]] = !{!"CBV", i32 1, i32 0, i32 0, i32 -1, i32 4} @@ -25,7 +25,7 @@ void EmptyEntry() {} [numthreads(1,1,1)] void DescriptorTableEntry() {} -// CHECK: ![[#RF_ENTRY]] = !{ptr @RootFlagsEntry, ![[#RF_RS:]]} +// CHECK: ![[#RF_ENTRY]] = !{ptr @RootFlagsEntry, ![[#RF_RS:]], i32 2} // CHECK: ![[#RF_RS]] = !{![[#ROOT_FLAGS:]]} // CHECK: ![[#ROOT_FLAGS]] = !{!"RootFlags", i32 2114} @@ -38,7 +38,7 @@ void DescriptorTableEntry() {} [numthreads(1,1,1)] void RootFlagsEntry() {} -// CHECK: ![[#RC_ENTRY]] = !{ptr @RootConstantsEntry, ![[#RC_RS:]]} +// CHECK: ![[#RC_ENTRY]] = !{ptr @RootConstantsEntry, ![[#RC_RS:]], i32 2} // CHECK: ![[#RC_RS]] = !{![[#ROOT_CONSTANTS:]]} // CHECK: ![[#ROOT_CONSTANTS]] = !{!"RootConstants", i32 5, i32 1, i32 2, i32 1} @@ -52,7 +52,7 @@ void RootFlagsEntry() {} [numthreads(1,1,1)] void RootConstantsEntry() {} -// CHECK: ![[#RD_ENTRY]] = !{ptr @RootDescriptorsEntry, ![[#RD_RS:]]} +// CHECK: ![[#RD_ENTRY]] = !{ptr @RootDescriptorsEntry, ![[#RD_RS:]], i32 2} // CHECK: ![[#RD_RS]] = !{![[#ROOT_CBV:]], ![[#ROOT_UAV:]], ![[#ROOT_SRV:]]} // CHECK: ![[#ROOT_CBV]] = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4} // CHECK: ![[#ROOT_UAV]] = !{!"RootUAV", i32 0, i32 42, i32 3, i32 2} @@ -66,7 +66,7 @@ void RootConstantsEntry() {} [numthreads(1,1,1)] void RootDescriptorsEntry() {} -// CHECK: ![[#SS_ENTRY]] = !{ptr @StaticSamplerEntry, ![[#SS_RS:]]} +// CHECK: ![[#SS_ENTRY]] = !{ptr @StaticSamplerEntry, ![[#SS_RS:]], i32 2} // CHECK: ![[#SS_RS]] = !{![[#STATIC_SAMPLER:]]} // checking filter = 0x4 diff --git a/clang/test/CodeGenHLSL/basic_types.hlsl b/clang/test/CodeGenHLSL/basic_types.hlsl index 362042654ea8..37fb5195e976 100644 --- a/clang/test/CodeGenHLSL/basic_types.hlsl +++ b/clang/test/CodeGenHLSL/basic_types.hlsl @@ -6,38 +6,38 @@ // RUN: -emit-llvm -disable-llvm-passes -o - -DNAMESPACED| FileCheck %s -// CHECK: @uint16_t_Val = external addrspace(2) global i16, align 2 -// CHECK: @int16_t_Val = external addrspace(2) global i16, align 2 -// CHECK: @uint_Val = external addrspace(2) global i32, align 4 -// CHECK: @uint64_t_Val = external addrspace(2) global i64, align 8 -// CHECK: @int64_t_Val = external addrspace(2) global i64, align 8 -// CHECK: @int16_t2_Val = external addrspace(2) global <2 x i16>, align 4 -// CHECK: @int16_t3_Val = external addrspace(2) global <3 x i16>, align 8 -// CHECK: @int16_t4_Val = external addrspace(2) global <4 x i16>, align 8 -// CHECK: @uint16_t2_Val = external addrspace(2) global <2 x i16>, align 4 -// CHECK: @uint16_t3_Val = external addrspace(2) global <3 x i16>, align 8 -// CHECK: @uint16_t4_Val = external addrspace(2) global <4 x i16>, align 8 -// CHECK: @int2_Val = external addrspace(2) global <2 x i32>, align 8 -// CHECK: @int3_Val = external addrspace(2) global <3 x i32>, align 16 -// CHECK: @int4_Val = external addrspace(2) global <4 x i32>, align 16 -// CHECK: @uint2_Val = external addrspace(2) global <2 x i32>, align 8 -// CHECK: @uint3_Val = external addrspace(2) global <3 x i32>, align 16 -// CHECK: @uint4_Val = external addrspace(2) global <4 x i32>, align 16 -// CHECK: @int64_t2_Val = external addrspace(2) global <2 x i64>, align 16 -// CHECK: @int64_t3_Val = external addrspace(2) global <3 x i64>, align 32 -// CHECK: @int64_t4_Val = external addrspace(2) global <4 x i64>, align 32 -// CHECK: @uint64_t2_Val = external addrspace(2) global <2 x i64>, align 16 -// CHECK: @uint64_t3_Val = external addrspace(2) global <3 x i64>, align 32 -// CHECK: @uint64_t4_Val = external addrspace(2) global <4 x i64>, align 32 -// CHECK: @half2_Val = external addrspace(2) global <2 x half>, align 4 -// CHECK: @half3_Val = external addrspace(2) global <3 x half>, align 8 -// CHECK: @half4_Val = external addrspace(2) global <4 x half>, align 8 -// CHECK: @float2_Val = external addrspace(2) global <2 x float>, align 8 -// CHECK: @float3_Val = external addrspace(2) global <3 x float>, align 16 -// CHECK: @float4_Val = external addrspace(2) global <4 x float>, align 16 -// CHECK: @double2_Val = external addrspace(2) global <2 x double>, align 16 -// CHECK: @double3_Val = external addrspace(2) global <3 x double>, align 32 -// CHECK: @double4_Val = external addrspace(2) global <4 x double>, align 32 +// CHECK: @uint16_t_Val = external hidden addrspace(2) global i16, align 2 +// CHECK: @int16_t_Val = external hidden addrspace(2) global i16, align 2 +// CHECK: @uint_Val = external hidden addrspace(2) global i32, align 4 +// CHECK: @uint64_t_Val = external hidden addrspace(2) global i64, align 8 +// CHECK: @int64_t_Val = external hidden addrspace(2) global i64, align 8 +// CHECK: @int16_t2_Val = external hidden addrspace(2) global <2 x i16>, align 4 +// CHECK: @int16_t3_Val = external hidden addrspace(2) global <3 x i16>, align 8 +// CHECK: @int16_t4_Val = external hidden addrspace(2) global <4 x i16>, align 8 +// CHECK: @uint16_t2_Val = external hidden addrspace(2) global <2 x i16>, align 4 +// CHECK: @uint16_t3_Val = external hidden addrspace(2) global <3 x i16>, align 8 +// CHECK: @uint16_t4_Val = external hidden addrspace(2) global <4 x i16>, align 8 +// CHECK: @int2_Val = external hidden addrspace(2) global <2 x i32>, align 8 +// CHECK: @int3_Val = external hidden addrspace(2) global <3 x i32>, align 16 +// CHECK: @int4_Val = external hidden addrspace(2) global <4 x i32>, align 16 +// CHECK: @uint2_Val = external hidden addrspace(2) global <2 x i32>, align 8 +// CHECK: @uint3_Val = external hidden addrspace(2) global <3 x i32>, align 16 +// CHECK: @uint4_Val = external hidden addrspace(2) global <4 x i32>, align 16 +// CHECK: @int64_t2_Val = external hidden addrspace(2) global <2 x i64>, align 16 +// CHECK: @int64_t3_Val = external hidden addrspace(2) global <3 x i64>, align 32 +// CHECK: @int64_t4_Val = external hidden addrspace(2) global <4 x i64>, align 32 +// CHECK: @uint64_t2_Val = external hidden addrspace(2) global <2 x i64>, align 16 +// CHECK: @uint64_t3_Val = external hidden addrspace(2) global <3 x i64>, align 32 +// CHECK: @uint64_t4_Val = external hidden addrspace(2) global <4 x i64>, align 32 +// CHECK: @half2_Val = external hidden addrspace(2) global <2 x half>, align 4 +// CHECK: @half3_Val = external hidden addrspace(2) global <3 x half>, align 8 +// CHECK: @half4_Val = external hidden addrspace(2) global <4 x half>, align 8 +// CHECK: @float2_Val = external hidden addrspace(2) global <2 x float>, align 8 +// CHECK: @float3_Val = external hidden addrspace(2) global <3 x float>, align 16 +// CHECK: @float4_Val = external hidden addrspace(2) global <4 x float>, align 16 +// CHECK: @double2_Val = external hidden addrspace(2) global <2 x double>, align 16 +// CHECK: @double3_Val = external hidden addrspace(2) global <3 x double>, align 32 +// CHECK: @double4_Val = external hidden addrspace(2) global <4 x double>, align 32 #ifdef NAMESPACED #define TYPE_DECL(T) hlsl::T T##_Val diff --git a/clang/test/CodeGenHLSL/builtins/AddUint64.hlsl b/clang/test/CodeGenHLSL/builtins/AddUint64.hlsl index e1832bdbbf33..8457ad6da293 100644 --- a/clang/test/CodeGenHLSL/builtins/AddUint64.hlsl +++ b/clang/test/CodeGenHLSL/builtins/AddUint64.hlsl @@ -4,7 +4,7 @@ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef <2 x i32> @_Z20test_AddUint64_uint2Dv2_jS_( +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z20test_AddUint64_uint2Dv2_jS_( // CHECK-SAME: <2 x i32> noundef [[A:%.*]], <2 x i32> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x i32>, align 8 @@ -31,7 +31,7 @@ uint2 test_AddUint64_uint2(uint2 a, uint2 b) { return AddUint64(a, b); } -// CHECK-LABEL: define noundef <4 x i32> @_Z20test_AddUint64_uint4Dv4_jS_( +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z20test_AddUint64_uint4Dv4_jS_( // CHECK-SAME: <4 x i32> noundef [[A:%.*]], <4 x i32> noundef [[B:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 403d473ce968..3a8d2c03e173 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -35,7 +35,7 @@ export void foo() { // CHECK-SAME: i32 noundef 1, i32 noundef 2, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]]) // Buf1 initialization part 2 - body of ByteAddressBuffer C1 constructor with explicit binding that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl17ByteAddressBufferC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK: call void @_ZN4hlsl17ByteAddressBufferC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) @@ -47,27 +47,27 @@ export void foo() { // CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0, ptr noundef @[[Buf2Str]]) // Buf2 initialization part 2 - body of RWByteAddressBuffer C1 constructor with implicit binding that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl19RWByteAddressBufferC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: call void @_ZN4hlsl19RWByteAddressBufferC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this1, // CHECK-SAME: i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) // Buf3 initialization part 1 - local variable declared in function foo() is initialized by // RasterizerOrderedByteAddressBuffer C1 default constructor -// CHECK: define void @_Z3foov() #2 { +// CHECK: define void @_Z3foov() // CHECK-NEXT: entry: // CHECK-NEXT: %Buf3 = alloca %"class.hlsl::RasterizerOrderedByteAddressBuffer", align 4 // CHECK-NEXT: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %Buf3) // Buf3 initialization part 2 - body of RasterizerOrderedByteAddressBuffer default C1 constructor that // calls the default C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}) // CHECK-NEXT: ret void // Buf1 initialization part 3 - ByteAddressBuffer C2 constructor with explicit binding that initializes // handle with @llvm.dx.resource.handlefrombinding -// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl17ByteAddressBufferC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t( // CHECK-DXIL-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -76,7 +76,7 @@ export void foo() { // Buf2 initialization part 3 - body of RWByteAddressBuffer C2 constructor with implicit binding that initializes // handle with @llvm.dx.resource.handlefromimplicitbinding -// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl19RWByteAddressBufferC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i8_1_0t // CHECK-SAME: (i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -85,7 +85,7 @@ export void foo() { // Buf3 initialization part 3 - body of RasterizerOrderedByteAddressBuffer default C2 constructor that // initializes handle to poison -// CHECK: define linkonce_odr void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK: store target("dx.RawBuffer", i8, 1, 1) poison, ptr %__handle, align 4 diff --git a/clang/test/CodeGenHLSL/builtins/GroupMemoryBarrierWithGroupSync.hlsl b/clang/test/CodeGenHLSL/builtins/GroupMemoryBarrierWithGroupSync.hlsl index 9d95d54852c0..114230d38ba5 100644 --- a/clang/test/CodeGenHLSL/builtins/GroupMemoryBarrierWithGroupSync.hlsl +++ b/clang/test/CodeGenHLSL/builtins/GroupMemoryBarrierWithGroupSync.hlsl @@ -1,14 +1,14 @@ // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ -// RUN: -DTARGET=dx -DFNATTRS=noundef -check-prefixes=CHECK,CHECK-DXIL +// RUN: -DTARGET=dx -check-prefixes=CHECK,CHECK-DXIL // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" -check-prefixes=CHECK,CHECK-SPIRV +// RUN: -DTARGET=spv -check-prefixes=CHECK,CHECK-SPIRV -// CHECK-DXIL: define void @ -// CHECK-SPIRV: define spir_func void @ +// CHECK-DXIL: define hidden void @ +// CHECK-SPIRV: define hidden spir_func void @ void test_GroupMemoryBarrierWithGroupSync() { // CHECK-DXIL: call void @llvm.[[TARGET]].group.memory.barrier.with.group.sync() // CHECK-SPIRV: call spir_func void @llvm.[[TARGET]].group.memory.barrier.with.group.sync() diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index e74a7ed270b0..114468914e2e 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -35,7 +35,7 @@ export void foo() { // CHECK-SAME: i32 noundef 5, i32 noundef 3, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]]) // Buf1 initialization part 2 - body of RWBuffer C1 constructor with explicit binding that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK: call void @_ZN4hlsl8RWBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) @@ -47,7 +47,7 @@ export void foo() { // CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0, ptr noundef @[[Buf2Str]]) // Buf2 initialization part 2 - body of RWBuffer C1 constructor with implicit binding that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: call void @_ZN4hlsl8RWBufferIdEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) @@ -59,12 +59,12 @@ export void foo() { // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %Buf3) // Buf3 initialization part 2 - body of RWBuffer default C1 constructor that calls the default C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: call void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}) // Buf1 initialization part 3 - body of RWBuffer C2 constructor with explicit binding that initializes // handle with @llvm.dx.resource.handlefrombinding -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t( // CHECK-DXIL-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -73,7 +73,7 @@ export void foo() { // Buf2 initialization part 3 - body of RWBuffer C2 constructor with implicit binding that initializes // handle with @llvm.dx.resource.handlefromimplicitbinding -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIdEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", double, 1, 0, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.TypedBuffer_f64_1_0_0t // CHECK-SAME: (i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -81,7 +81,7 @@ export void foo() { // CHECK-NEXT: store target("dx.TypedBuffer", double, 1, 0, 0) %[[HANDLE]], ptr %__handle, align 4 // Buf3 initialization part 3 - body of RWBuffer default C2 constructor that initializes handle to poison -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer.1", ptr %{{.*}}, i32 0, i32 0 // CHECK-NEXT: store target("dx.TypedBuffer", i32, 1, 0, 1) poison, ptr %__handle, align 4 diff --git a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl index 8a3958ad8fd0..7804239edcca 100644 --- a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl @@ -304,7 +304,7 @@ bool2 AccessBools() { return X.zw; } -// CHECK-LABEL: define void {{.*}}BoolSizeMismatch{{.*}} +// CHECK-LABEL: define hidden void {{.*}}BoolSizeMismatch{{.*}} // CHECK: [[B:%.*]] = alloca <4 x i32>, align 16 // CHECK-NEXT: [[Tmp:%.*]] = alloca <1 x i32>, align 4 // CHECK-NEXT: store <4 x i32> splat (i32 1), ptr [[B]], align 16 diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index fc7b6be5c900..28841732df99 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -36,7 +36,7 @@ export void foo() { // Buf1 initialization part 2 - body of StructuredBuffer C1 constructor with explicit binding // that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl16StructuredBufferIfEC1EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK: call void @_ZN4hlsl16StructuredBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) @@ -49,7 +49,7 @@ export void foo() { // CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0, ptr noundef @[[Buf2Str]]) // Buf2 initialization part 2 - body of RWStructuredBuffer C1 constructor with implicit binding that calls the C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl18RWStructuredBufferIfEC1EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: call void @_ZN4hlsl18RWStructuredBufferIfEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) @@ -63,12 +63,12 @@ export void foo() { // Buf3 initialization part 2 - body of AppendStructuredBuffer default C1 constructor that calls // the default C2 constructor -// CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: call void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}) // Buf1 initialization part 3 - body of AppendStructuredBuffer C2 constructor with explicit binding // that initializes handle with @llvm.dx.resource.handlefrombinding -// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl16StructuredBufferIfEC2EjjijPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name) // CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t( // CHECK-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -77,7 +77,7 @@ export void foo() { // Buf2 initialization part 3 - body of RWStructuredBuffer C2 constructor with implicit binding that initializes // handle with @llvm.dx.resource.handlefromimplicitbinding -// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK: define linkonce_odr hidden void @_ZN4hlsl18RWStructuredBufferIfEC2EjijjPKc(ptr noundef nonnull align 4 dereferenceable(4) %this, // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId, ptr noundef %name) // CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f32_1_0t // CHECK-SAME: (i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false, ptr %{{.*}}) @@ -86,7 +86,7 @@ export void foo() { // Buf3 initialization part 3 - body of AppendStructuredBuffer default C2 constructor that // initializes handle to poison -// CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: define linkonce_odr hidden void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::AppendStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK: store target("dx.RawBuffer", float, 1, 0) poison, ptr %__handle, align 4 diff --git a/clang/test/CodeGenHLSL/builtins/WaveActiveMax.hlsl b/clang/test/CodeGenHLSL/builtins/WaveActiveMax.hlsl index 7891cfc1989a..be05a17cc369 100644 --- a/clang/test/CodeGenHLSL/builtins/WaveActiveMax.hlsl +++ b/clang/test/CodeGenHLSL/builtins/WaveActiveMax.hlsl @@ -16,7 +16,7 @@ int test_int(int expr) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.max.i32([[TY]]) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.max.i32([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.reduce.max.i32([[TY]]) #[[#attr:]] // CHECK-LABEL: test_uint64_t uint64_t test_uint64_t(uint64_t expr) { @@ -27,7 +27,7 @@ uint64_t test_uint64_t(uint64_t expr) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.umax.i64([[TY]]) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.umax.i64([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.reduce.umax.i64([[TY]]) #[[#attr:]] // Test basic lowering to runtime function call with array and float value. @@ -40,7 +40,7 @@ float4 test_floatv4(float4 expr) { } // CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] -// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] +// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.reduce.max.v4f32([[TY1]]) #[[#attr]] // CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} diff --git a/clang/test/CodeGenHLSL/builtins/WaveActiveSum.hlsl b/clang/test/CodeGenHLSL/builtins/WaveActiveSum.hlsl index 4bf423ccc1b8..1fc93c62c8db 100644 --- a/clang/test/CodeGenHLSL/builtins/WaveActiveSum.hlsl +++ b/clang/test/CodeGenHLSL/builtins/WaveActiveSum.hlsl @@ -16,7 +16,7 @@ int test_int(int expr) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.sum.i32([[TY]]) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.sum.i32([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.reduce.sum.i32([[TY]]) #[[#attr:]] // CHECK-LABEL: test_uint64_t uint64_t test_uint64_t(uint64_t expr) { @@ -27,7 +27,7 @@ uint64_t test_uint64_t(uint64_t expr) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.reduce.usum.i64([[TY]]) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.reduce.sum.i64([[TY]]) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.reduce.sum.i64([[TY]]) #[[#attr:]] // Test basic lowering to runtime function call with array and float value. @@ -40,6 +40,6 @@ float4 test_floatv4(float4 expr) { } // CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.reduce.sum.v4f32([[TY1]]) #[[#attr]] -// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.reduce.sum.v4f32([[TY1]]) #[[#attr]] +// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.reduce.sum.v4f32([[TY1]]) #[[#attr]] // CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} diff --git a/clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl b/clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl index c94ef8a67735..8c787a42618a 100644 --- a/clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl @@ -17,7 +17,7 @@ int test_int(int expr, uint idx) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i32([[TY]], i32) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]] // CHECK-LABEL: test_uint uint test_uint(uint expr, uint idx) { @@ -38,7 +38,7 @@ int64_t test_int64_t(int64_t expr, uint idx) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i64([[TY]], i32) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i64([[TY]], i32) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i64([[TY]], i32) #[[#attr:]] // CHECK-LABEL: test_uint64_t uint64_t test_uint64_t(uint64_t expr, uint idx) { @@ -60,7 +60,7 @@ int16_t test_int16(int16_t expr, uint idx) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i16([[TY]], i32) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]] // CHECK-LABEL: test_uint16 uint16_t test_uint16(uint16_t expr, uint idx) { @@ -84,7 +84,7 @@ half test_half(half expr, uint idx) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f16([[TY]], i32) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]] // CHECK-LABEL: test_double double test_double(double expr, uint idx) { @@ -96,7 +96,7 @@ double test_double(double expr, uint idx) { } // CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f64([[TY]], i32) #[[#attr:]] -// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]] +// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]] // CHECK-LABEL: test_floatv4 float4 test_floatv4(float4 expr, uint idx) { @@ -108,6 +108,6 @@ float4 test_floatv4(float4 expr, uint idx) { } // CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.readlane.v4f32([[TY1]], i32) #[[#attr]] -// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]] +// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]] // CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} diff --git a/clang/test/CodeGenHLSL/builtins/abs.hlsl b/clang/test/CodeGenHLSL/builtins/abs.hlsl index e8a6ee044957..6abe2f816c84 100644 --- a/clang/test/CodeGenHLSL/builtins/abs.hlsl +++ b/clang/test/CodeGenHLSL/builtins/abs.hlsl @@ -8,16 +8,16 @@ using hlsl::abs; #ifdef __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef i16 @_Z16test_abs_int16_t +// NATIVE_HALF-LABEL: define hidden noundef i16 @_Z16test_abs_int16_t // NATIVE_HALF: call i16 @llvm.abs.i16( int16_t test_abs_int16_t(int16_t p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef <2 x i16> @_Z17test_abs_int16_t2 +// NATIVE_HALF-LABEL: define hidden noundef <2 x i16> @_Z17test_abs_int16_t2 // NATIVE_HALF: call <2 x i16> @llvm.abs.v2i16( int16_t2 test_abs_int16_t2(int16_t2 p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef <3 x i16> @_Z17test_abs_int16_t3 +// NATIVE_HALF-LABEL: define hidden noundef <3 x i16> @_Z17test_abs_int16_t3 // NATIVE_HALF: call <3 x i16> @llvm.abs.v3i16( int16_t3 test_abs_int16_t3(int16_t3 p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> @_Z17test_abs_int16_t4 +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> @_Z17test_abs_int16_t4 // NATIVE_HALF: call <4 x i16> @llvm.abs.v4i16( int16_t4 test_abs_int16_t4(int16_t4 p0) { return abs(p0); } @@ -50,76 +50,76 @@ uint16_t3 test_abs_uint64_t3(uint16_t3 p0) { return abs(p0); } uint16_t4 test_abs_uint64_t4(uint16_t4 p0) { return abs(p0); } #endif // __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_abs_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_abs_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.fabs.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_abs_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_abs_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.fabs.f32(float %0) half test_abs_half(half p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_abs_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_abs_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.fabs.v2f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_abs_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_abs_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.fabs.v2f32( half2 test_abs_half2(half2 p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_abs_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_abs_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.fabs.v3f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_abs_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_abs_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.fabs.v3f32( half3 test_abs_half3(half3 p0) { return abs(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_abs_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_abs_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.fabs.v4f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_abs_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_abs_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.fabs.v4f32( half4 test_abs_half4(half4 p0) { return abs(p0); } -// CHECK-LABEL: define noundef i32 @_Z12test_abs_int +// CHECK-LABEL: define hidden noundef i32 @_Z12test_abs_int // CHECK: call i32 @llvm.abs.i32( int test_abs_int(int p0) { return abs(p0); } -// CHECK-LABEL: define noundef <2 x i32> @_Z13test_abs_int2 +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z13test_abs_int2 // CHECK: call <2 x i32> @llvm.abs.v2i32( int2 test_abs_int2(int2 p0) { return abs(p0); } -// CHECK-LABEL: define noundef <3 x i32> @_Z13test_abs_int3 +// CHECK-LABEL: define hidden noundef <3 x i32> @_Z13test_abs_int3 // CHECK: call <3 x i32> @llvm.abs.v3i32( int3 test_abs_int3(int3 p0) { return abs(p0); } -// CHECK-LABEL: define noundef <4 x i32> @_Z13test_abs_int4 +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z13test_abs_int4 // CHECK: call <4 x i32> @llvm.abs.v4i32( int4 test_abs_int4(int4 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_abs_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_abs_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.fabs.f32( float test_abs_float(float p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_abs_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_abs_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.fabs.v2f32( float2 test_abs_float2(float2 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_abs_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_abs_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.fabs.v3f32( float3 test_abs_float3(float3 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_abs_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_abs_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.fabs.v4f32( float4 test_abs_float4(float4 p0) { return abs(p0); } -// CHECK-LABEL: define noundef i64 @_Z16test_abs_int64_t +// CHECK-LABEL: define hidden noundef i64 @_Z16test_abs_int64_t // CHECK: call i64 @llvm.abs.i64( int64_t test_abs_int64_t(int64_t p0) { return abs(p0); } -// CHECK-LABEL: define noundef <2 x i64> @_Z17test_abs_int64_t2 +// CHECK-LABEL: define hidden noundef <2 x i64> @_Z17test_abs_int64_t2 // CHECK: call <2 x i64> @llvm.abs.v2i64( int64_t2 test_abs_int64_t2(int64_t2 p0) { return abs(p0); } -// CHECK-LABEL: define noundef <3 x i64> @_Z17test_abs_int64_t3 +// CHECK-LABEL: define hidden noundef <3 x i64> @_Z17test_abs_int64_t3 // CHECK: call <3 x i64> @llvm.abs.v3i64( int64_t3 test_abs_int64_t3(int64_t3 p0) { return abs(p0); } -// CHECK-LABEL: define noundef <4 x i64> @_Z17test_abs_int64_t4 +// CHECK-LABEL: define hidden noundef <4 x i64> @_Z17test_abs_int64_t4 // CHECK: call <4 x i64> @llvm.abs.v4i64( int64_t4 test_abs_int64_t4(int64_t4 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) double @_Z15test_abs_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) double @_Z15test_abs_double // CHECK: call reassoc nnan ninf nsz arcp afn double @llvm.fabs.f64( double test_abs_double(double p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x double> @_Z16test_abs_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x double> @_Z16test_abs_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x double> @llvm.fabs.v2f64( double2 test_abs_double2(double2 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x double> @_Z16test_abs_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x double> @_Z16test_abs_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x double> @llvm.fabs.v3f64( double3 test_abs_double3(double3 p0) { return abs(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> @_Z16test_abs_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> @_Z16test_abs_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x double> @llvm.fabs.v4f64( double4 test_abs_double4(double4 p0) { return abs(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/all.hlsl b/clang/test/CodeGenHLSL/builtins/all.hlsl index 39f364c5953d..391fad0ef33f 100644 --- a/clang/test/CodeGenHLSL/builtins/all.hlsl +++ b/clang/test/CodeGenHLSL/builtins/all.hlsl @@ -2,20 +2,20 @@ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS=noundef -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS=noundef -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef" -DTARGET=dx #ifdef __HLSL_ENABLE_16_BIT // NATIVE_HALF: define [[FNATTRS]] i1 @ diff --git a/clang/test/CodeGenHLSL/builtins/and.hlsl b/clang/test/CodeGenHLSL/builtins/and.hlsl index b77889cd9ae7..d2ca7cf4163e 100644 --- a/clang/test/CodeGenHLSL/builtins/and.hlsl +++ b/clang/test/CodeGenHLSL/builtins/and.hlsl @@ -3,7 +3,7 @@ // RUN: dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -O1 -o - | FileCheck %s -// CHECK-LABEL: define noundef i1 @_Z15test_and_scalarbb( +// CHECK-LABEL: define hidden noundef i1 @_Z15test_and_scalarbb( // CHECK-SAME: i1 noundef [[X:%.*]], i1 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_AND:%.*]] = and i1 [[X]], [[Y]] @@ -13,7 +13,7 @@ bool test_and_scalar(bool x, bool y) { return and(x, y); } -// CHECK-LABEL: define noundef <2 x i1> @_Z14test_and_bool2Dv2_bS_( +// CHECK-LABEL: define hidden noundef <2 x i1> @_Z14test_and_bool2Dv2_bS_( // CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_AND:%.*]] = and <2 x i1> [[X]], [[Y]] @@ -23,7 +23,7 @@ bool2 test_and_bool2(bool2 x, bool2 y) { return and(x, y); } -// CHECK-LABEL: define noundef <3 x i1> @_Z14test_and_bool3Dv3_bS_( +// CHECK-LABEL: define hidden noundef <3 x i1> @_Z14test_and_bool3Dv3_bS_( // CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_AND:%.*]] = and <3 x i1> [[X]], [[Y]] @@ -33,7 +33,7 @@ bool3 test_and_bool3(bool3 x, bool3 y) { return and(x, y); } -// CHECK-LABEL: define noundef <4 x i1> @_Z14test_and_bool4Dv4_bS_( +// CHECK-LABEL: define hidden noundef <4 x i1> @_Z14test_and_bool4Dv4_bS_( // CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_AND:%.*]] = and <4 x i1> [[X]], [[Y]] @@ -43,7 +43,7 @@ bool4 test_and_bool4(bool4 x, bool4 y) { return and(x, y); } -// CHECK-LABEL: define noundef <4 x i1> @_Z13test_and_int4Dv4_iS_( +// CHECK-LABEL: define hidden noundef <4 x i1> @_Z13test_and_int4Dv4_iS_( // CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne <4 x i32> [[X]], zeroinitializer @@ -55,7 +55,7 @@ bool4 test_and_int4(int4 x, int4 y) { return and(x, y); } -// CHECK-LABEL: define noundef <4 x i1> @_Z15test_and_float4Dv4_fS_( +// CHECK-LABEL: define hidden noundef <4 x i1> @_Z15test_and_float4Dv4_fS_( // CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TOBOOL:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[X]], zeroinitializer diff --git a/clang/test/CodeGenHLSL/builtins/any.hlsl b/clang/test/CodeGenHLSL/builtins/any.hlsl index 3d9d8e9e689e..e4837876e269 100644 --- a/clang/test/CodeGenHLSL/builtins/any.hlsl +++ b/clang/test/CodeGenHLSL/builtins/any.hlsl @@ -2,20 +2,20 @@ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS=noundef -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS=noundef -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef" -DTARGET=dx #ifdef __HLSL_ENABLE_16_BIT // NATIVE_HALF: define [[FNATTRS]] i1 @ diff --git a/clang/test/CodeGenHLSL/builtins/ceil-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/ceil-overloads.hlsl index b313c99e89a5..bdefe46b802e 100644 --- a/clang/test/CodeGenHLSL/builtins/ceil-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ceil-overloads.hlsl @@ -4,67 +4,67 @@ using hlsl::ceil; -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_ceil_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_ceil_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_double(double p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_double2(double2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_double3(double3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_double4(double4 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_ceil_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_ceil_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_int(int p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_int2(int2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_int3(int3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_int4(int4 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_ceil_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_ceil_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_uint(uint p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_uint2(uint2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_uint3(uint3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_uint4(uint4 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_ceil_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_ceil_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_int64_t(int64_t p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_int64_t2(int64_t2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_int64_t3(int64_t3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_int64_t4(int64_t4 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_ceil_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_ceil_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_uint64_t(uint64_t p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_ceil_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_uint64_t2(uint64_t2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_ceil_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_uint64_t3(uint64_t3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_ceil_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_uint64_t4(uint64_t4 p0) { return ceil(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/ceil.hlsl b/clang/test/CodeGenHLSL/builtins/ceil.hlsl index fe0b8f898383..1a9c630b60e5 100644 --- a/clang/test/CodeGenHLSL/builtins/ceil.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ceil.hlsl @@ -7,36 +7,36 @@ using hlsl::ceil; -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z14test_ceil_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z14test_ceil_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.ceil.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z14test_ceil_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_ceil_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32(float %0) half test_ceil_half(half p0) { return ceil(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z15test_ceil_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z15test_ceil_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.ceil.v2f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_ceil_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_ceil_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( half2 test_ceil_half2(half2 p0) { return ceil(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z15test_ceil_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z15test_ceil_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.ceil.v3f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_ceil_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_ceil_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( half3 test_ceil_half3(half3 p0) { return ceil(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z15test_ceil_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z15test_ceil_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.ceil.v4f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_ceil_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_ceil_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( half4 test_ceil_half4(half4 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z15test_ceil_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_ceil_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.ceil.f32( float test_ceil_float(float p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_ceil_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_ceil_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.ceil.v2f32( float2 test_ceil_float2(float2 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_ceil_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_ceil_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.ceil.v3f32( float3 test_ceil_float3(float3 p0) { return ceil(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_ceil_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_ceil_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.ceil.v4f32( float4 test_ceil_float4(float4 p0) { return ceil(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/clamp-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/clamp-overloads.hlsl index c0e1e914831a..eaedfb419c19 100644 --- a/clang/test/CodeGenHLSL/builtins/clamp-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/clamp-overloads.hlsl @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ // RUN: -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple spirv-unknown-vulkan-compute %s \ // RUN: -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple spirv-unknown-vulkan-compute %s \ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" #ifdef __HLSL_ENABLE_16_BIT // NATIVE_HALF: define [[FNATTRS]] <4 x i16> {{.*}}test_clamp_short4_mismatch diff --git a/clang/test/CodeGenHLSL/builtins/clamp.hlsl b/clang/test/CodeGenHLSL/builtins/clamp.hlsl index d01c2a45c43c..58db4423799b 100644 --- a/clang/test/CodeGenHLSL/builtins/clamp.hlsl +++ b/clang/test/CodeGenHLSL/builtins/clamp.hlsl @@ -1,19 +1,19 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ // RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute %s \ // RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" -DFFNATTRS="nofpclass(nan inf)" #ifdef __HLSL_ENABLE_16_BIT // NATIVE_HALF: define [[FNATTRS]] i16 @_Z16test_clamp_short diff --git a/clang/test/CodeGenHLSL/builtins/clip-builtin.hlsl b/clang/test/CodeGenHLSL/builtins/clip-builtin.hlsl index c864f93af472..aaeb2f026449 100644 --- a/clang/test/CodeGenHLSL/builtins/clip-builtin.hlsl +++ b/clang/test/CodeGenHLSL/builtins/clip-builtin.hlsl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK: define void @{{.*}}builtin_clip_float{{.*}}(float {{.*}} [[P0:%.*]]) +// CHECK: define hidden void @{{.*}}builtin_clip_float{{.*}}(float {{.*}} [[P0:%.*]]) // CHECK: [[LOAD:%.*]] = load float, ptr [[P0]].addr, align 4 // CHECK-NEXT: [[FCMP:%.*]] = fcmp reassoc nnan ninf nsz arcp afn olt float [[LOAD]], 0.000000e+00 // CHECK-NO: call i1 @llvm.dx.any diff --git a/clang/test/CodeGenHLSL/builtins/clip.hlsl b/clang/test/CodeGenHLSL/builtins/clip.hlsl index 5a1753766a8a..e067828c38bf 100644 --- a/clang/test/CodeGenHLSL/builtins/clip.hlsl +++ b/clang/test/CodeGenHLSL/builtins/clip.hlsl @@ -3,13 +3,13 @@ void test_scalar(float Buf) { - // CHECK: define void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]]) + // CHECK: define hidden void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]]) // CHECK: [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4 // CHECK-NEXT: [[FCMP:%.*]] = fcmp reassoc nnan ninf nsz arcp afn olt float [[LOAD]], 0.000000e+00 // CHECK-NO: call i1 @llvm.dx.any // CHECK-NEXT: call void @llvm.dx.discard(i1 [[FCMP]]) // - // SPIRV: define spir_func void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]]) + // SPIRV: define hidden spir_func void @{{.*}}test_scalar{{.*}}(float {{.*}} [[VALP:%.*]]) // SPIRV: [[LOAD:%.*]] = load float, ptr [[VALP]].addr, align 4 // SPIRV-NEXT: [[FCMP:%.*]] = fcmp reassoc nnan ninf nsz arcp afn olt float [[LOAD]], 0.000000e+00 // SPIRV-NO: call i1 @llvm.spv.any @@ -21,13 +21,13 @@ void test_scalar(float Buf) { } void test_vector4(float4 Buf) { - // CHECK: define void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]]) + // CHECK: define hidden void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]]) // CHECK: [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16 // CHECK-NEXT: [[FCMP:%.*]] = fcmp reassoc nnan ninf nsz arcp afn olt <4 x float> [[LOAD]], zeroinitializer // CHECK-NEXT: [[ANYC:%.*]] = call i1 @llvm.dx.any.v4i1(<4 x i1> [[FCMP]]) // CHECK-NEXT: call void @llvm.dx.discard(i1 [[ANYC]]) // - // SPIRV: define spir_func void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]]) + // SPIRV: define hidden spir_func void @{{.*}}test_vector{{.*}}(<4 x float> {{.*}} [[VALP:%.*]]) // SPIRV: [[LOAD:%.*]] = load <4 x float>, ptr [[VALP]].addr, align 16 // SPIRV-NEXT: [[FCMP:%.*]] = fcmp reassoc nnan ninf nsz arcp afn olt <4 x float> [[LOAD]], zeroinitializer // SPIRV-NEXT: [[ANYC:%.*]] = call i1 @llvm.spv.any.v4i1(<4 x i1> [[FCMP]]) diff --git a/clang/test/CodeGenHLSL/builtins/cos-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/cos-overloads.hlsl index b7b11b1c3bd6..70926cc8ba74 100644 --- a/clang/test/CodeGenHLSL/builtins/cos-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/cos-overloads.hlsl @@ -2,67 +2,67 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_cos_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_cos_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_double(double p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_double2(double2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_double3(double3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_double4(double4 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_cos_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_cos_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_int(int p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_int2(int2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_int3(int3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_int4(int4 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_cos_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_cos_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_uint(uint p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_uint2(uint2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_uint3(uint3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_uint4(uint4 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_cos_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_cos_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_int64_t(int64_t p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_int64_t2(int64_t2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_int64_t3(int64_t3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_int64_t4(int64_t4 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_cos_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_cos_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_uint64_t(uint64_t p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_cos_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_uint64_t2(uint64_t2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_cos_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_uint64_t3(uint64_t3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_cos_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_uint64_t4(uint64_t4 p0) { return cos(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/cos.hlsl b/clang/test/CodeGenHLSL/builtins/cos.hlsl index 5f993d50498b..79f9e1e6fbec 100644 --- a/clang/test/CodeGenHLSL/builtins/cos.hlsl +++ b/clang/test/CodeGenHLSL/builtins/cos.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_cos_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_cos_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.cos.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_cos_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_cos_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( half test_cos_half(half p0) { return cos(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_cos_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_cos_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.cos.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_cos_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_cos_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32( half2 test_cos_half2(half2 p0) { return cos(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_cos_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_cos_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.cos.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_cos_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_cos_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32( half3 test_cos_half3(half3 p0) { return cos(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_cos_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_cos_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.cos.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_cos_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_cos_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32( half4 test_cos_half4(half4 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_cos_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_cos_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.cos.f32( float test_cos_float(float p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_cos_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_cos_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.cos.v2f32 float2 test_cos_float2(float2 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_cos_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_cos_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.cos.v3f32 float3 test_cos_float3(float3 p0) { return cos(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_cos_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_cos_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.cos.v4f32 float4 test_cos_float4(float4 p0) { return cos(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/cross.hlsl b/clang/test/CodeGenHLSL/builtins/cross.hlsl index b2a1d6316787..89ac383e2517 100644 --- a/clang/test/CodeGenHLSL/builtins/cross.hlsl +++ b/clang/test/CodeGenHLSL/builtins/cross.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] <3 x half> @ // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.[[TARGET]].cross.v3f16(<3 x half> diff --git a/clang/test/CodeGenHLSL/builtins/degrees-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/degrees-overloads.hlsl index bafd2368c996..a1abf435ea10 100644 --- a/clang/test/CodeGenHLSL/builtins/degrees-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/degrees-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @ // CHECK: %hlsl.degrees = call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].degrees.f32( diff --git a/clang/test/CodeGenHLSL/builtins/degrees.hlsl b/clang/test/CodeGenHLSL/builtins/degrees.hlsl index 64531dd2785e..f0fb12855e5f 100644 --- a/clang/test/CodeGenHLSL/builtins/degrees.hlsl +++ b/clang/test/CodeGenHLSL/builtins/degrees.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] half @ // NATIVE_HALF: %hlsl.degrees = call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].degrees.f16( diff --git a/clang/test/CodeGenHLSL/builtins/distance.hlsl b/clang/test/CodeGenHLSL/builtins/distance.hlsl index ac38cf185379..0c24fbb9f185 100644 --- a/clang/test/CodeGenHLSL/builtins/distance.hlsl +++ b/clang/test/CodeGenHLSL/builtins/distance.hlsl @@ -6,14 +6,14 @@ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z18test_distance_halfDhDh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z18test_distance_halfDhDh( // CHECK-SAME: half noundef nofpclass(nan inf) [[X:%.*]], half noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[Y]] // CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half nofpclass(nan inf) [[SUB_I]]) // CHECK-NEXT: ret half [[ELT_ABS_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z18test_distance_halfDhDh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z18test_distance_halfDhDh( // SPVCHECK-SAME: half noundef nofpclass(nan inf) [[X:%.*]], half noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[Y]] @@ -22,7 +22,7 @@ // half test_distance_half(half X, half Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_( // CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[X:%.*]], <2 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[Y]] @@ -30,7 +30,7 @@ half test_distance_half(half X, half Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_( // SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[X:%.*]], <2 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[Y]] @@ -39,7 +39,7 @@ half test_distance_half(half X, half Y) { return distance(X, Y); } // half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_( // CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[X:%.*]], <3 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[Y]] @@ -47,7 +47,7 @@ half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_( // SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[X:%.*]], <3 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[Y]] @@ -56,7 +56,7 @@ half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); } // half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_( // CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[X:%.*]], <4 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[Y]] @@ -64,7 +64,7 @@ half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_( // SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[X:%.*]], <4 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[Y]] @@ -73,14 +73,14 @@ half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); } // half test_distance_half4(half4 X, half4 Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z19test_distance_floatff( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z19test_distance_floatff( // CHECK-SAME: float noundef nofpclass(nan inf) [[X:%.*]], float noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[Y]] // CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float nofpclass(nan inf) [[SUB_I]]) // CHECK-NEXT: ret float [[ELT_ABS_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z19test_distance_floatff( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z19test_distance_floatff( // SPVCHECK-SAME: float noundef nofpclass(nan inf) [[X:%.*]], float noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[Y]] @@ -89,7 +89,7 @@ half test_distance_half4(half4 X, half4 Y) { return distance(X, Y); } // float test_distance_float(float X, float Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_( // CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[X:%.*]], <2 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[Y]] @@ -97,7 +97,7 @@ float test_distance_float(float X, float Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_( // SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[X:%.*]], <2 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[Y]] @@ -106,7 +106,7 @@ float test_distance_float(float X, float Y) { return distance(X, Y); } // float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_( // CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[X:%.*]], <3 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[Y]] @@ -114,7 +114,7 @@ float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_( // SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[X:%.*]], <3 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[Y]] @@ -123,7 +123,7 @@ float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); } // float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_( // CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[X]], [[Y]] @@ -131,7 +131,7 @@ float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); } // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_( // SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[X]], [[Y]] diff --git a/clang/test/CodeGenHLSL/builtins/exp-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/exp-overloads.hlsl index 858a1210169d..df34beeba7a8 100644 --- a/clang/test/CodeGenHLSL/builtins/exp-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/exp-overloads.hlsl @@ -2,87 +2,87 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp_double // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_double(double p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_double2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_double2(double2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_double3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_double3(double3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_double4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_double4(double4 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp_int // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_int(int p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_int2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_int2(int2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_int3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_int3(int3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_int4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_int4(int4 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp_uint // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_uint(uint p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_uint2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_uint2(uint2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_uint3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_uint3(uint3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_uint4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_uint4(uint4 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp_int64_t // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_int64_t(int64_t p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_int64_t2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_int64_t2(int64_t2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_int64_t3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_int64_t3(int64_t3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_int64_t4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_int64_t4(int64_t4 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp_uint64_t // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_uint64_t(uint64_t p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp_uint64_t2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_uint64_t2(uint64_t2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp_uint64_t3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_uint64_t3(uint64_t3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp_uint64_t4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_uint64_t4(uint64_t4 p0) { return exp(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/exp.hlsl b/clang/test/CodeGenHLSL/builtins/exp.hlsl index 6ed40ed8f433..5a8f60528a84 100644 --- a/clang/test/CodeGenHLSL/builtins/exp.hlsl +++ b/clang/test/CodeGenHLSL/builtins/exp.hlsl @@ -5,48 +5,48 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_exp_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_exp_half // NATIVE_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn half @llvm.exp.f16( // NATIVE_HALF: ret half %elt.exp -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_exp_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_exp_half // NO_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // NO_HALF: ret float %elt.exp half test_exp_half(half p0) { return exp(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_exp_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_exp_half2 // NATIVE_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.exp.v2f16 // NATIVE_HALF: ret <2 x half> %elt.exp -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_exp_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_exp_half2 // NO_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32( // NO_HALF: ret <2 x float> %elt.exp half2 test_exp_half2(half2 p0) { return exp(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_exp_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_exp_half3 // NATIVE_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.exp.v3f16 // NATIVE_HALF: ret <3 x half> %elt.exp -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_exp_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_exp_half3 // NO_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32( // NO_HALF: ret <3 x float> %elt.exp half3 test_exp_half3(half3 p0) { return exp(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_exp_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_exp_half4 // NATIVE_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.exp.v4f16 // NATIVE_HALF: ret <4 x half> %elt.exp -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_exp_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_exp_half4 // NO_HALF: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32( // NO_HALF: ret <4 x float> %elt.exp half4 test_exp_half4(half4 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_exp_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_exp_float // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn float @llvm.exp.f32( // CHECK: ret float %elt.exp float test_exp_float(float p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_exp_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_exp_float2 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp.v2f32 // CHECK: ret <2 x float> %elt.exp float2 test_exp_float2(float2 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_exp_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_exp_float3 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp.v3f32 // CHECK: ret <3 x float> %elt.exp float3 test_exp_float3(float3 p0) { return exp(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_exp_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_exp_float4 // CHECK: %elt.exp = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp.v4f32 // CHECK: ret <4 x float> %elt.exp float4 test_exp_float4(float4 p0) { return exp(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/exp2-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/exp2-overloads.hlsl index ef522afc244a..20482777a18d 100644 --- a/clang/test/CodeGenHLSL/builtins/exp2-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/exp2-overloads.hlsl @@ -2,87 +2,87 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp2_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp2_double // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_double(double p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_double2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_double2(double2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_double3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_double3(double3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_double4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_double4(double4 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp2_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp2_int // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_int(int p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_int2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_int2(int2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_int3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_int3(int3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_int4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_int4(int4 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp2_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp2_uint // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_uint(uint p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_uint2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_uint2(uint2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_uint3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_uint3(uint3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_uint4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_uint4(uint4 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp2_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp2_int64_t // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_int64_t(int64_t p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_int64_t2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_int64_t2(int64_t2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_int64_t3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_int64_t3(int64_t3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_int64_t4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_int64_t4(int64_t4 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_exp2_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_exp2_uint64_t // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_uint64_t(uint64_t p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_exp2_uint64_t2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_uint64_t2(uint64_t2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_exp2_uint64_t3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_uint64_t3(uint64_t3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_exp2_uint64_t4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_uint64_t4(uint64_t4 p0) { return exp2(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/exp2.hlsl b/clang/test/CodeGenHLSL/builtins/exp2.hlsl index b067427e4636..a9bbcb0d9bff 100644 --- a/clang/test/CodeGenHLSL/builtins/exp2.hlsl +++ b/clang/test/CodeGenHLSL/builtins/exp2.hlsl @@ -5,48 +5,48 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z14test_exp2_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z14test_exp2_half // NATIVE_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn half @llvm.exp2.f16( // NATIVE_HALF: ret half %elt.exp2 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z14test_exp2_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_exp2_half // NO_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // NO_HALF: ret float %elt.exp2 half test_exp2_half(half p0) { return exp2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z15test_exp2_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z15test_exp2_half2 // NATIVE_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.exp2.v2f16 // NATIVE_HALF: ret <2 x half> %elt.exp2 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_exp2_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_exp2_half2 // NO_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32( // NO_HALF: ret <2 x float> %elt.exp2 half2 test_exp2_half2(half2 p0) { return exp2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z15test_exp2_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z15test_exp2_half3 // NATIVE_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.exp2.v3f16 // NATIVE_HALF: ret <3 x half> %elt.exp2 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_exp2_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_exp2_half3 // NO_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32( // NO_HALF: ret <3 x float> %elt.exp2 half3 test_exp2_half3(half3 p0) { return exp2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z15test_exp2_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z15test_exp2_half4 // NATIVE_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.exp2.v4f16 // NATIVE_HALF: ret <4 x half> %elt.exp2 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_exp2_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_exp2_half4 // NO_HALF: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32( // NO_HALF: ret <4 x float> %elt.exp2 half4 test_exp2_half4(half4 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z15test_exp2_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_exp2_float // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32( // CHECK: ret float %elt.exp2 float test_exp2_float(float p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_exp2_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_exp2_float2 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32 // CHECK: ret <2 x float> %elt.exp2 float2 test_exp2_float2(float2 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_exp2_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_exp2_float3 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32 // CHECK: ret <3 x float> %elt.exp2 float3 test_exp2_float3(float3 p0) { return exp2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_exp2_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_exp2_float4 // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32 // CHECK: ret <4 x float> %elt.exp2 float4 test_exp2_float4(float4 p0) { return exp2(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/firstbithigh.hlsl b/clang/test/CodeGenHLSL/builtins/firstbithigh.hlsl index debf6b6d3e3f..a71b1878f8b5 100644 --- a/clang/test/CodeGenHLSL/builtins/firstbithigh.hlsl +++ b/clang/test/CodeGenHLSL/builtins/firstbithigh.hlsl @@ -151,3 +151,11 @@ uint3 test_firstbithigh_long3(int64_t3 p0) { uint4 test_firstbithigh_long4(int64_t4 p0) { return firstbithigh(p0); } + +// CHECK-LABEL: test_firstbithigh_upcast +// CHECK: [[FBH:%.*]] = call <4 x i32> @llvm.[[TARGET]].firstbituhigh.v4i32(<4 x i32> %{{.*}}) +// CHECK: [[CONV:%.*]] = zext <4 x i32> [[FBH]] to <4 x i64> +// CHECK: ret <4 x i64> [[CONV]] +uint64_t4 test_firstbithigh_upcast(uint4 p0) { + return firstbithigh(p0); +} diff --git a/clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl b/clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl index 5d490fabc5bc..007db0c9c2ad 100644 --- a/clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl +++ b/clang/test/CodeGenHLSL/builtins/firstbitlow.hlsl @@ -151,3 +151,11 @@ uint3 test_firstbitlow_long3(int64_t3 p0) { uint4 test_firstbitlow_long4(int64_t4 p0) { return firstbitlow(p0); } + +// CHECK-LABEL: test_firstbitlow_upcast +// CHECK: [[FBL:%.*]] = call <4 x i32> @llvm.[[TARGET]].firstbitlow.v4i32(<4 x i32> %{{.*}}) +// CHECK: [[CONV:%.*]] = zext <4 x i32> [[FBL]] to <4 x i64> +// CHECK: ret <4 x i64> [[CONV]] +uint64_t4 test_firstbitlow_upcast(uint4 p0) { + return firstbitlow(p0); +} diff --git a/clang/test/CodeGenHLSL/builtins/floor-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/floor-overloads.hlsl index 26d83443ea48..1e413e53f333 100644 --- a/clang/test/CodeGenHLSL/builtins/floor-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/floor-overloads.hlsl @@ -4,67 +4,67 @@ using hlsl::floor; -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_floor_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_floor_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_double(double p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_double2(double2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_double3(double3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_double4(double4 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_floor_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_floor_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_int(int p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_int2(int2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_int3(int3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_int4(int4 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_floor_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_floor_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_uint(uint p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_uint2(uint2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_uint3(uint3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_uint4(uint4 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_floor_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_floor_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_int64_t(int64_t p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_int64_t2(int64_t2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_int64_t3(int64_t3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_int64_t4(int64_t4 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_floor_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_floor_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_uint64_t(uint64_t p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_floor_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_uint64_t2(uint64_t2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_floor_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_uint64_t3(uint64_t3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_floor_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_uint64_t4(uint64_t4 p0) { return floor(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/floor.hlsl b/clang/test/CodeGenHLSL/builtins/floor.hlsl index f610baeeefd4..b3ff58317981 100644 --- a/clang/test/CodeGenHLSL/builtins/floor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/floor.hlsl @@ -7,36 +7,36 @@ using hlsl::floor; -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z15test_floor_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z15test_floor_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.floor.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z15test_floor_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_floor_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32(float %0) half test_floor_half(half p0) { return floor(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z16test_floor_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z16test_floor_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.floor.v2f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_floor_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_floor_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( half2 test_floor_half2(half2 p0) { return floor(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z16test_floor_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z16test_floor_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.floor.v3f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_floor_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_floor_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( half3 test_floor_half3(half3 p0) { return floor(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z16test_floor_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z16test_floor_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.floor.v4f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_floor_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_floor_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( half4 test_floor_half4(half4 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z16test_floor_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z16test_floor_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.floor.f32( float test_floor_float(float p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z17test_floor_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z17test_floor_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.floor.v2f32( float2 test_floor_float2(float2 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z17test_floor_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z17test_floor_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.floor.v3f32( float3 test_floor_float3(float3 p0) { return floor(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z17test_floor_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z17test_floor_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.floor.v4f32( float4 test_floor_float4(float4 p0) { return floor(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/fmod.hlsl b/clang/test/CodeGenHLSL/builtins/fmod.hlsl index 7ecc5854b398..cc91c0b67f6c 100644 --- a/clang/test/CodeGenHLSL/builtins/fmod.hlsl +++ b/clang/test/CodeGenHLSL/builtins/fmod.hlsl @@ -4,7 +4,7 @@ // // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ -// RUN: -emit-llvm -o - | FileCheck %s -DFNATTRS="noundef nofpclass(nan inf)" \ +// RUN: -emit-llvm -o - | FileCheck %s -DFNATTRS="hidden noundef nofpclass(nan inf)" \ // RUN: -DTYPE=half -DINT_TYPE=f16 --check-prefixes=DXCHECK // @@ -12,7 +12,7 @@ // // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm \ -// RUN: -o - | FileCheck %s -DFNATTRS="noundef nofpclass(nan inf)" \ +// RUN: -o - | FileCheck %s -DFNATTRS="hidden noundef nofpclass(nan inf)" \ // RUN: -DTYPE=float -DINT_TYPE=f32 --check-prefixes=DXCHECK @@ -23,7 +23,7 @@ // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -o - | FileCheck %s \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTYPE=half +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTYPE=half // // ---------- No Native Half support test ----------- @@ -31,7 +31,7 @@ // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm \ // RUN: -o - | FileCheck %s \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTYPE=float +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTYPE=float diff --git a/clang/test/CodeGenHLSL/builtins/frac-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/frac-overloads.hlsl index b0e844bd8a8d..7a3f7b006948 100644 --- a/clang/test/CodeGenHLSL/builtins/frac-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/frac-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @ // CHECK: %hlsl.frac = call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].frac.f32( diff --git a/clang/test/CodeGenHLSL/builtins/frac.hlsl b/clang/test/CodeGenHLSL/builtins/frac.hlsl index 7b105ce84359..d8397407cd01 100644 --- a/clang/test/CodeGenHLSL/builtins/frac.hlsl +++ b/clang/test/CodeGenHLSL/builtins/frac.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] half @ // NATIVE_HALF: %hlsl.frac = call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].frac.f16( diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl index 6d2ae6535ecb..24114b11c760 100644 --- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl +++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl @@ -6,9 +6,9 @@ using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::c // CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct, 0, 0) // CHECK: %struct.MyStruct = type <{ <4 x float>, <2 x i32> }> -// CHECK: define void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) +// CHECK: define hidden void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) // CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0) -// CHECK: declare void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0)) +// CHECK: declare hidden void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0)) void foo1(handle_float_t res); @@ -16,14 +16,14 @@ void fa(handle_float_t a) { foo1(a); } -// CHECK: define void @_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) +// CHECK: define hidden void @_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) void fb(handle_float_t a) { handle_float_t b = a; } -// CHECK: define void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %a) +// CHECK: define hidden void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %a) // CHECK: call void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %agg.tmp) -// CHECK: declare void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4) +// CHECK: declare hidden void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 4) void foo2(RWBuffer buf); void fc(RWBuffer a) { @@ -39,9 +39,9 @@ struct MyStruct { int2 i; }; -// CHECK: define void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 4 %a) +// CHECK: define hidden void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 4 %a) // CHECK: call void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 4 %agg.tmp) -// CHECK: declare void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 4) +// CHECK: declare hidden void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 4) void foo3(StructuredBuffer buf); void fe(StructuredBuffer a) { diff --git a/clang/test/CodeGenHLSL/builtins/isinf-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/isinf-overloads.hlsl index ace209003ce4..f39cba9ace6e 100644 --- a/clang/test/CodeGenHLSL/builtins/isinf-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/isinf-overloads.hlsl @@ -2,19 +2,19 @@ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s -// CHECK: define noundef i1 @ +// CHECK: define hidden noundef i1 @ // CHECK: %dx.isinf = call i1 @llvm.dx.isinf.f32( // CHECK: ret i1 %dx.isinf bool test_isinf_double(double p0) { return isinf(p0); } -// CHECK: define noundef <2 x i1> @ +// CHECK: define hidden noundef <2 x i1> @ // CHECK: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f32 // CHECK: ret <2 x i1> %dx.isinf bool2 test_isinf_double2(double2 p0) { return isinf(p0); } -// CHECK: define noundef <3 x i1> @ +// CHECK: define hidden noundef <3 x i1> @ // CHECK: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f32 // CHECK: ret <3 x i1> %dx.isinf bool3 test_isinf_double3(double3 p0) { return isinf(p0); } -// CHECK: define noundef <4 x i1> @ +// CHECK: define hidden noundef <4 x i1> @ // CHECK: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f32 // CHECK: ret <4 x i1> %dx.isinf bool4 test_isinf_double4(double4 p0) { return isinf(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/isinf.hlsl b/clang/test/CodeGenHLSL/builtins/isinf.hlsl index df44fc4a91df..4d53daaafb69 100644 --- a/clang/test/CodeGenHLSL/builtins/isinf.hlsl +++ b/clang/test/CodeGenHLSL/builtins/isinf.hlsl @@ -6,40 +6,40 @@ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF -// CHECK: define noundef i1 @ +// CHECK: define hidden noundef i1 @ // NATIVE_HALF: %dx.isinf = call i1 @llvm.dx.isinf.f16( // NO_HALF: %dx.isinf = call i1 @llvm.dx.isinf.f32( // CHECK: ret i1 %dx.isinf bool test_isinf_half(half p0) { return isinf(p0); } -// CHECK: define noundef <2 x i1> @ +// CHECK: define hidden noundef <2 x i1> @ // NATIVE_HALF: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f16 // NO_HALF: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f32( // CHECK: ret <2 x i1> %dx.isinf bool2 test_isinf_half2(half2 p0) { return isinf(p0); } -// NATIVE_HALF: define noundef <3 x i1> @ +// NATIVE_HALF: define hidden noundef <3 x i1> @ // NATIVE_HALF: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f16 // NO_HALF: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f32( // CHECK: ret <3 x i1> %dx.isinf bool3 test_isinf_half3(half3 p0) { return isinf(p0); } -// NATIVE_HALF: define noundef <4 x i1> @ +// NATIVE_HALF: define hidden noundef <4 x i1> @ // NATIVE_HALF: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f16 // NO_HALF: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f32( // CHECK: ret <4 x i1> %dx.isinf bool4 test_isinf_half4(half4 p0) { return isinf(p0); } -// CHECK: define noundef i1 @ +// CHECK: define hidden noundef i1 @ // CHECK: %dx.isinf = call i1 @llvm.dx.isinf.f32( // CHECK: ret i1 %dx.isinf bool test_isinf_float(float p0) { return isinf(p0); } -// CHECK: define noundef <2 x i1> @ +// CHECK: define hidden noundef <2 x i1> @ // CHECK: %dx.isinf = call <2 x i1> @llvm.dx.isinf.v2f32 // CHECK: ret <2 x i1> %dx.isinf bool2 test_isinf_float2(float2 p0) { return isinf(p0); } -// CHECK: define noundef <3 x i1> @ +// CHECK: define hidden noundef <3 x i1> @ // CHECK: %dx.isinf = call <3 x i1> @llvm.dx.isinf.v3f32 // CHECK: ret <3 x i1> %dx.isinf bool3 test_isinf_float3(float3 p0) { return isinf(p0); } -// CHECK: define noundef <4 x i1> @ +// CHECK: define hidden noundef <4 x i1> @ // CHECK: %dx.isinf = call <4 x i1> @llvm.dx.isinf.v4f32 // CHECK: ret <4 x i1> %dx.isinf bool4 test_isinf_float4(float4 p0) { return isinf(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/ldexp.hlsl b/clang/test/CodeGenHLSL/builtins/ldexp.hlsl index ea0d1348c6e4..f8fa06c39f2a 100644 --- a/clang/test/CodeGenHLSL/builtins/ldexp.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ldexp.hlsl @@ -1,48 +1,48 @@ // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) half @_ZN4hlsl8__detail10ldexp_implIDhEET_S2_S2_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) half @_ZN4hlsl8__detail10ldexp_implIDhEET_S2_S2_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn half @llvm.exp2.f16(half %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn half %elt.exp2, %{{.*}} // CHECK: ret half %mul half test_ldexp_half(half X, half Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <2 x half> @_ZN4hlsl8__detail10ldexp_implIDv2_DhEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <2 x half> @_ZN4hlsl8__detail10ldexp_implIDv2_DhEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.exp2.v2f16(<2 x half> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <2 x half> %elt.exp2, %{{.*}} // CHECK: ret <2 x half> %mul half2 test_ldexp_half2(half2 X, half2 Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <3 x half> @_ZN4hlsl8__detail10ldexp_implIDv3_DhEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <3 x half> @_ZN4hlsl8__detail10ldexp_implIDv3_DhEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.exp2.v3f16(<3 x half> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <3 x half> %elt.exp2, %{{.*}} // CHECK: ret <3 x half> %mul half3 test_ldexp_half3(half3 X, half3 Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <4 x half> @_ZN4hlsl8__detail10ldexp_implIDv4_DhEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x half> @_ZN4hlsl8__detail10ldexp_implIDv4_DhEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.exp2.v4f16(<4 x half> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <4 x half> %elt.exp2, %{{.*}} // CHECK: ret <4 x half> %mul half4 test_ldexp_half4(half4 X, half4 Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) float @_ZN4hlsl8__detail10ldexp_implIfEET_S2_S2_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) float @_ZN4hlsl8__detail10ldexp_implIfEET_S2_S2_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn float @llvm.exp2.f32(float %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn float %elt.exp2, %{{.*}} // CHECK: ret float %mul float test_ldexp_float(float X, float Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <2 x float> @_ZN4hlsl8__detail10ldexp_implIDv2_fEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <2 x float> @_ZN4hlsl8__detail10ldexp_implIDv2_fEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.exp2.v2f32(<2 x float> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <2 x float> %elt.exp2, %{{.*}} // CHECK: ret <2 x float> %mul float2 test_ldexp_float2(float2 X, float2 Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <3 x float> @_ZN4hlsl8__detail10ldexp_implIDv3_fEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <3 x float> @_ZN4hlsl8__detail10ldexp_implIDv3_fEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.exp2.v3f32(<3 x float> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <3 x float> %elt.exp2, %{{.*}} // CHECK: ret <3 x float> %mul float3 test_ldexp_float3(float3 X, float3 Exp) { return ldexp(X, Exp); } -// CHECK-LABEL: define linkonce_odr noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl8__detail10ldexp_implIDv4_fEET_S3_S3_ +// CHECK-LABEL: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl8__detail10ldexp_implIDv4_fEET_S3_S3_ // CHECK: %elt.exp2 = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.exp2.v4f32(<4 x float> %{{.*}}) // CHECK: %mul = fmul reassoc nnan ninf nsz arcp afn <4 x float> %elt.exp2, %{{.*}} // CHECK: ret <4 x float> %mul diff --git a/clang/test/CodeGenHLSL/builtins/length.hlsl b/clang/test/CodeGenHLSL/builtins/length.hlsl index 0b17d03d7097..9297c35abfd1 100644 --- a/clang/test/CodeGenHLSL/builtins/length.hlsl +++ b/clang/test/CodeGenHLSL/builtins/length.hlsl @@ -8,16 +8,13 @@ // RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK -// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z16test_length_halfDh( -// - -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z16test_length_halfDh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z16test_length_halfDh( // CHECK-SAME: half noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half nofpclass(nan inf) [[P0]]) // CHECK-NEXT: ret half [[ELT_ABS_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z16test_length_halfDh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z16test_length_halfDh( // SPVCHECK-SAME: half noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half nofpclass(nan inf) [[P0]]) @@ -28,18 +25,14 @@ half test_length_half(half p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh( -// - - -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh( // CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> nofpclass(nan inf) [[P0]], <2 x half> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh( // SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v2f16(<2 x half> nofpclass(nan inf) [[P0]]) @@ -50,15 +43,14 @@ half test_length_half2(half2 p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh( -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh( // CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> nofpclass(nan inf) [[P0]], <3 x half> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh( // SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v3f16(<3 x half> nofpclass(nan inf) [[P0]]) @@ -69,15 +61,14 @@ half test_length_half3(half3 p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh( -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh( // CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> nofpclass(nan inf) [[P0]], <4 x half> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]]) // CHECK-NEXT: ret half [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh( // SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v4f16(<4 x half> nofpclass(nan inf) [[P0]]) @@ -88,14 +79,13 @@ half test_length_half4(half4 p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z17test_length_floatf( -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z17test_length_floatf( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z17test_length_floatf( // CHECK-SAME: float noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float nofpclass(nan inf) [[P0]]) // CHECK-NEXT: ret float [[ELT_ABS_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z17test_length_floatf( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z17test_length_floatf( // SPVCHECK-SAME: float noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float nofpclass(nan inf) [[P0]]) @@ -106,15 +96,14 @@ float test_length_float(float p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f( -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f( // CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> nofpclass(nan inf) [[P0]], <2 x float> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f( // SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v2f32(<2 x float> nofpclass(nan inf) [[P0]]) @@ -125,15 +114,14 @@ float test_length_float2(float2 p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f( -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f( // CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> nofpclass(nan inf) [[P0]], <3 x float> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f( // SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v3f32(<3 x float> nofpclass(nan inf) [[P0]]) @@ -144,15 +132,14 @@ float test_length_float3(float3 p0) return length(p0); } -// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f( -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f( // CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> nofpclass(nan inf) [[P0]], <4 x float> nofpclass(nan inf) [[P0]]) // CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]]) // CHECK-NEXT: ret float [[TMP0]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f( // SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v4f32(<4 x float> nofpclass(nan inf) [[P0]]) diff --git a/clang/test/CodeGenHLSL/builtins/lerp-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/lerp-overloads.hlsl index 3cb14f8555ca..3b13e43873c7 100644 --- a/clang/test/CodeGenHLSL/builtins/lerp-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/lerp-overloads.hlsl @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx -// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx -// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-compute %s -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv -// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-compute %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-compute %s -fnative-half-type -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-compute %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @_Z16test_lerp_doubled( // CHECK: [[CONV0:%.*]] = fptrunc {{.*}} double %{{.*}} to float diff --git a/clang/test/CodeGenHLSL/builtins/log-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/log-overloads.hlsl index 5c63d630c3f3..d7aacdc486ac 100644 --- a/clang/test/CodeGenHLSL/builtins/log-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log-overloads.hlsl @@ -2,67 +2,67 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_double(double p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_double2(double2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_double3(double3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_double4(double4 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_int(int p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_int2(int2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_int3(int3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_int4(int4 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_uint(uint p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_uint2(uint2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_uint3(uint3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_uint4(uint4 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_int64_t(int64_t p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_int64_t2(int64_t2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_int64_t3(int64_t3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_int64_t4(int64_t4 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_uint64_t(uint64_t p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_uint64_t2(uint64_t2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_uint64_t3(uint64_t3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_uint64_t4(uint64_t4 p0) { return log(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/log.hlsl b/clang/test/CodeGenHLSL/builtins/log.hlsl index e489939594a5..0136c1a052ed 100644 --- a/clang/test/CodeGenHLSL/builtins/log.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_log_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_log_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.log.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_log_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_log_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( half test_log_half(half p0) { return log(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_log_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_log_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.log.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_log_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_log_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32( half2 test_log_half2(half2 p0) { return log(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_log_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_log_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.log.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_log_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_log_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32( half3 test_log_half3(half3 p0) { return log(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_log_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_log_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.log.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_log_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_log_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32( half4 test_log_half4(half4 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_log_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_log_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log.f32( float test_log_float(float p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_log_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_log_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log.v2f32 float2 test_log_float2(float2 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_log_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_log_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log.v3f32 float3 test_log_float3(float3 p0) { return log(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_log_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_log_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log.v4f32 float4 test_log_float4(float4 p0) { return log(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/log10-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/log10-overloads.hlsl index 1a0539c3517d..e408f4a5d45c 100644 --- a/clang/test/CodeGenHLSL/builtins/log10-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log10-overloads.hlsl @@ -2,67 +2,67 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log10_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log10_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_double(double p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_double2(double2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_double3(double3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_double4(double4 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log10_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log10_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_int(int p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_int2(int2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_int3(int3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_int4(int4 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log10_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log10_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_uint(uint p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_uint2(uint2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_uint3(uint3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_uint4(uint4 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log10_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log10_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_int64_t(int64_t p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_int64_t2(int64_t2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_int64_t3(int64_t3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_int64_t4(int64_t4 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log10_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log10_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_uint64_t(uint64_t p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log10_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_uint64_t2(uint64_t2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log10_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_uint64_t3(uint64_t3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log10_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_uint64_t4(uint64_t4 p0) { return log10(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/log10.hlsl b/clang/test/CodeGenHLSL/builtins/log10.hlsl index 37c8e837c45a..6a75444143b1 100644 --- a/clang/test/CodeGenHLSL/builtins/log10.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log10.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z15test_log10_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z15test_log10_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.log10.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z15test_log10_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_log10_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( half test_log10_half(half p0) { return log10(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z16test_log10_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z16test_log10_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.log10.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_log10_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_log10_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32( half2 test_log10_half2(half2 p0) { return log10(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z16test_log10_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z16test_log10_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.log10.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_log10_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_log10_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32( half3 test_log10_half3(half3 p0) { return log10(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z16test_log10_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z16test_log10_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.log10.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_log10_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_log10_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32( half4 test_log10_half4(half4 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z16test_log10_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z16test_log10_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log10.f32( float test_log10_float(float p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z17test_log10_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z17test_log10_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log10.v2f32 float2 test_log10_float2(float2 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z17test_log10_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z17test_log10_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log10.v3f32 float3 test_log10_float3(float3 p0) { return log10(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z17test_log10_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z17test_log10_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log10.v4f32 float4 test_log10_float4(float4 p0) { return log10(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/log2-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/log2-overloads.hlsl index c35b50d8e490..f88d5ab84921 100644 --- a/clang/test/CodeGenHLSL/builtins/log2-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log2-overloads.hlsl @@ -2,67 +2,67 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log2_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log2_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_double(double p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_double2(double2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_double3(double3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_double4(double4 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log2_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log2_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_int(int p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_int2(int2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_int3(int3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_int4(int4 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log2_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log2_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_uint(uint p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_uint2(uint2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_uint3(uint3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_uint4(uint4 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log2_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log2_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_int64_t(int64_t p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_int64_t2(int64_t2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_int64_t3(int64_t3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_int64_t4(int64_t4 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_log2_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_log2_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_uint64_t(uint64_t p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_log2_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_uint64_t2(uint64_t2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_log2_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_uint64_t3(uint64_t3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_log2_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_uint64_t4(uint64_t4 p0) { return log2(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/log2.hlsl b/clang/test/CodeGenHLSL/builtins/log2.hlsl index 5159d5bb0fa4..84d73c181089 100644 --- a/clang/test/CodeGenHLSL/builtins/log2.hlsl +++ b/clang/test/CodeGenHLSL/builtins/log2.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z14test_log2_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z14test_log2_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.log2.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z14test_log2_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_log2_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( half test_log2_half(half p0) { return log2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z15test_log2_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z15test_log2_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.log2.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_log2_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_log2_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32( half2 test_log2_half2(half2 p0) { return log2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z15test_log2_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z15test_log2_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.log2.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_log2_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_log2_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32( half3 test_log2_half3(half3 p0) { return log2(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z15test_log2_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z15test_log2_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.log2.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_log2_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_log2_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32( half4 test_log2_half4(half4 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z15test_log2_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_log2_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.log2.f32( float test_log2_float(float p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_log2_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_log2_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.log2.v2f32 float2 test_log2_float2(float2 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_log2_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_log2_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.log2.v3f32 float3 test_log2_float3(float3 p0) { return log2(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_log2_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_log2_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.log2.v4f32 float4 test_log2_float4(float4 p0) { return log2(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/max-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/max-overloads.hlsl index d952398a6a59..cd7013ba7582 100644 --- a/clang/test/CodeGenHLSL/builtins/max-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/max-overloads.hlsl @@ -4,14 +4,14 @@ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF #ifdef __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef <4 x i16> {{.*}}test_max_short4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> {{.*}}test_max_short4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x i16> poison, i16 %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x i16> [[CONV0]], <4 x i16> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MAX:%.*]] = call noundef <4 x i16> @llvm.smax.v4i16(<4 x i16> %{{.*}}, <4 x i16> [[CONV1]]) // NATIVE_HALF: ret <4 x i16> [[MAX]] int16_t4 test_max_short4_mismatch(int16_t4 p0, int16_t p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> {{.*}}test_max_ushort4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> {{.*}}test_max_ushort4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x i16> poison, i16 %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x i16> [[CONV0]], <4 x i16> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MAX:%.*]] = call noundef <4 x i16> @llvm.umax.v4i16(<4 x i16> %{{.*}}, <4 x i16> [[CONV1]]) @@ -19,61 +19,61 @@ int16_t4 test_max_short4_mismatch(int16_t4 p0, int16_t p1) { return max(p0, p1); uint16_t4 test_max_ushort4_mismatch(uint16_t4 p0, uint16_t p1) { return max(p0, p1); } #endif -// CHECK-LABEL: define noundef <4 x i32> {{.*}}test_max_int4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i32> {{.*}}test_max_int4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i32> poison, i32 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i32> [[CONV0]], <4 x i32> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call noundef <4 x i32> @llvm.smax.v4i32(<4 x i32> %{{.*}}, <4 x i32> [[CONV1]]) // CHECK: ret <4 x i32> [[MAX]] int4 test_max_int4_mismatch(int4 p0, int p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> {{.*}}test_max_uint4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i32> {{.*}}test_max_uint4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i32> poison, i32 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i32> [[CONV0]], <4 x i32> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call noundef <4 x i32> @llvm.umax.v4i32(<4 x i32> %{{.*}}, <4 x i32> [[CONV1]]) // CHECK: ret <4 x i32> [[MAX]] uint4 test_max_uint4_mismatch(uint4 p0, uint p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> {{.*}}test_max_long4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i64> {{.*}}test_max_long4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i64> poison, i64 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i64> [[CONV0]], <4 x i64> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call noundef <4 x i64> @llvm.smax.v4i64(<4 x i64> %{{.*}}, <4 x i64> [[CONV1]]) // CHECK: ret <4 x i64> [[MAX]] int64_t4 test_max_long4_mismatch(int64_t4 p0, int64_t p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> {{.*}}test_max_ulong4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i64> {{.*}}test_max_ulong4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i64> poison, i64 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i64> [[CONV0]], <4 x i64> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call noundef <4 x i64> @llvm.umax.v4i64(<4 x i64> %{{.*}}, <4 x i64> [[CONV1]]) // CHECK: ret <4 x i64> [[MAX]] uint64_t4 test_max_ulong4_mismatch(uint64_t4 p0, uint64_t p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> {{.*}}test_max_half4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> {{.*}}test_max_half4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x half> poison, half %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x half> [[CONV0]], <4 x half> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MAX:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.maxnum.v4f16(<4 x half> %{{.*}}, <4 x half> [[CONV1]]) // NATIVE_HALF: ret <4 x half> [[MAX]] -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_max_half4_mismatch +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_max_half4_mismatch // NO_HALF: [[CONV0:%.*]] = insertelement <4 x float> poison, float %{{.*}}, i64 0 // NO_HALF: [[CONV1:%.*]] = shufflevector <4 x float> [[CONV0]], <4 x float> poison, <4 x i32> zeroinitializer // NO_HALF: [[MAX:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.maxnum.v4f32(<4 x float> %{{.*}}, <4 x float> [[CONV1]]) // NO_HALF: ret <4 x float> [[MAX]] half4 test_max_half4_mismatch(half4 p0, half p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_max_float4_mismatch +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_max_float4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x float> poison, float %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x float> [[CONV0]], <4 x float> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.maxnum.v4f32(<4 x float> %{{.*}}, <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[MAX]] float4 test_max_float4_mismatch(float4 p0, float p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> {{.*}}test_max_double4_mismatch +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> {{.*}}test_max_double4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x double> poison, double %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x double> [[CONV0]], <4 x double> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x double> @llvm.maxnum.v4f64(<4 x double> %{{.*}}, <4 x double> [[CONV1]]) // CHECK: ret <4 x double> [[MAX]] double4 test_max_double4_mismatch(double4 p0, double p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> {{.*}}test_max_double4_mismatch2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> {{.*}}test_max_double4_mismatch2 // CHECK: [[CONV0:%.*]] = insertelement <4 x double> poison, double %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x double> [[CONV0]], <4 x double> poison, <4 x i32> zeroinitializer // CHECK: [[MAX:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x double> @llvm.maxnum.v4f64(<4 x double> [[CONV1]], <4 x double> %{{.*}}) diff --git a/clang/test/CodeGenHLSL/builtins/max.hlsl b/clang/test/CodeGenHLSL/builtins/max.hlsl index 0b767335556e..fab53a160c85 100644 --- a/clang/test/CodeGenHLSL/builtins/max.hlsl +++ b/clang/test/CodeGenHLSL/builtins/max.hlsl @@ -6,128 +6,128 @@ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF #ifdef __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef i16 @_Z14test_max_short +// NATIVE_HALF-LABEL: define hidden noundef i16 @_Z14test_max_short // NATIVE_HALF: call i16 @llvm.smax.i16( int16_t test_max_short(int16_t p0, int16_t p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <2 x i16> @_Z15test_max_short2 +// NATIVE_HALF-LABEL: define hidden noundef <2 x i16> @_Z15test_max_short2 // NATIVE_HALF: call <2 x i16> @llvm.smax.v2i16( int16_t2 test_max_short2(int16_t2 p0, int16_t2 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <3 x i16> @_Z15test_max_short3 +// NATIVE_HALF-LABEL: define hidden noundef <3 x i16> @_Z15test_max_short3 // NATIVE_HALF: call <3 x i16> @llvm.smax.v3i16 int16_t3 test_max_short3(int16_t3 p0, int16_t3 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> @_Z15test_max_short4 +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> @_Z15test_max_short4 // NATIVE_HALF: call <4 x i16> @llvm.smax.v4i16 int16_t4 test_max_short4(int16_t4 p0, int16_t4 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef i16 @_Z15test_max_ushort +// NATIVE_HALF-LABEL: define hidden noundef i16 @_Z15test_max_ushort // NATIVE_HALF: call i16 @llvm.umax.i16( uint16_t test_max_ushort(uint16_t p0, uint16_t p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <2 x i16> @_Z16test_max_ushort2 +// NATIVE_HALF-LABEL: define hidden noundef <2 x i16> @_Z16test_max_ushort2 // NATIVE_HALF: call <2 x i16> @llvm.umax.v2i16 uint16_t2 test_max_ushort2(uint16_t2 p0, uint16_t2 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <3 x i16> @_Z16test_max_ushort3 +// NATIVE_HALF-LABEL: define hidden noundef <3 x i16> @_Z16test_max_ushort3 // NATIVE_HALF: call <3 x i16> @llvm.umax.v3i16 uint16_t3 test_max_ushort3(uint16_t3 p0, uint16_t3 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> @_Z16test_max_ushort4 +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> @_Z16test_max_ushort4 // NATIVE_HALF: call <4 x i16> @llvm.umax.v4i16 uint16_t4 test_max_ushort4(uint16_t4 p0, uint16_t4 p1) { return max(p0, p1); } #endif -// CHECK-LABEL: define noundef i32 @_Z12test_max_int +// CHECK-LABEL: define hidden noundef i32 @_Z12test_max_int // CHECK: call i32 @llvm.smax.i32( int test_max_int(int p0, int p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <2 x i32> @_Z13test_max_int2 +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z13test_max_int2 // CHECK: call <2 x i32> @llvm.smax.v2i32 int2 test_max_int2(int2 p0, int2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <3 x i32> @_Z13test_max_int3 +// CHECK-LABEL: define hidden noundef <3 x i32> @_Z13test_max_int3 // CHECK: call <3 x i32> @llvm.smax.v3i32 int3 test_max_int3(int3 p0, int3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> @_Z13test_max_int4 +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z13test_max_int4 // CHECK: call <4 x i32> @llvm.smax.v4i32 int4 test_max_int4(int4 p0, int4 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef i32 @_Z13test_max_uint +// CHECK-LABEL: define hidden noundef i32 @_Z13test_max_uint // CHECK: call i32 @llvm.umax.i32( int test_max_uint(uint p0, uint p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <2 x i32> @_Z14test_max_uint2 +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z14test_max_uint2 // CHECK: call <2 x i32> @llvm.umax.v2i32 uint2 test_max_uint2(uint2 p0, uint2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <3 x i32> @_Z14test_max_uint3 +// CHECK-LABEL: define hidden noundef <3 x i32> @_Z14test_max_uint3 // CHECK: call <3 x i32> @llvm.umax.v3i32 uint3 test_max_uint3(uint3 p0, uint3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> @_Z14test_max_uint4 +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z14test_max_uint4 // CHECK: call <4 x i32> @llvm.umax.v4i32 uint4 test_max_uint4(uint4 p0, uint4 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef i64 @_Z13test_max_long +// CHECK-LABEL: define hidden noundef i64 @_Z13test_max_long // CHECK: call i64 @llvm.smax.i64( int64_t test_max_long(int64_t p0, int64_t p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <2 x i64> @_Z14test_max_long2 +// CHECK-LABEL: define hidden noundef <2 x i64> @_Z14test_max_long2 // CHECK: call <2 x i64> @llvm.smax.v2i64 int64_t2 test_max_long2(int64_t2 p0, int64_t2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <3 x i64> @_Z14test_max_long3 +// CHECK-LABEL: define hidden noundef <3 x i64> @_Z14test_max_long3 // CHECK: call <3 x i64> @llvm.smax.v3i64 int64_t3 test_max_long3(int64_t3 p0, int64_t3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> @_Z14test_max_long4 +// CHECK-LABEL: define hidden noundef <4 x i64> @_Z14test_max_long4 // CHECK: call <4 x i64> @llvm.smax.v4i64 int64_t4 test_max_long4(int64_t4 p0, int64_t4 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef i64 @_Z14test_max_ulong +// CHECK-LABEL: define hidden noundef i64 @_Z14test_max_ulong // CHECK: call i64 @llvm.umax.i64( uint64_t test_max_ulong(uint64_t p0, uint64_t p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <2 x i64> @_Z15test_max_ulong2 +// CHECK-LABEL: define hidden noundef <2 x i64> @_Z15test_max_ulong2 // CHECK: call <2 x i64> @llvm.umax.v2i64 uint64_t2 test_max_ulong2(uint64_t2 p0, uint64_t2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <3 x i64> @_Z15test_max_ulong3 +// CHECK-LABEL: define hidden noundef <3 x i64> @_Z15test_max_ulong3 // CHECK: call <3 x i64> @llvm.umax.v3i64 uint64_t3 test_max_ulong3(uint64_t3 p0, uint64_t3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> @_Z15test_max_ulong4 +// CHECK-LABEL: define hidden noundef <4 x i64> @_Z15test_max_ulong4 // CHECK: call <4 x i64> @llvm.umax.v4i64 uint64_t4 test_max_ulong4(uint64_t4 p0, uint64_t4 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_max_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_max_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.maxnum.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_max_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_max_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.maxnum.f32( half test_max_half(half p0, half p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_max_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_max_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.maxnum.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_max_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_max_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.maxnum.v2f32( half2 test_max_half2(half2 p0, half2 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_max_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_max_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.maxnum.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_max_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_max_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.maxnum.v3f32( half3 test_max_half3(half3 p0, half3 p1) { return max(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_max_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_max_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.maxnum.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_max_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_max_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.maxnum.v4f32( half4 test_max_half4(half4 p0, half4 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_max_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_max_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.maxnum.f32( float test_max_float(float p0, float p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_max_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_max_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.maxnum.v2f32 float2 test_max_float2(float2 p0, float2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_max_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_max_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.maxnum.v3f32 float3 test_max_float3(float3 p0, float3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_max_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_max_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.maxnum.v4f32 float4 test_max_float4(float4 p0, float4 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) double @_Z15test_max_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) double @_Z15test_max_double // CHECK: call reassoc nnan ninf nsz arcp afn double @llvm.maxnum.f64( double test_max_double(double p0, double p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x double> @_Z16test_max_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x double> @_Z16test_max_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x double> @llvm.maxnum.v2f64 double2 test_max_double2(double2 p0, double2 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x double> @_Z16test_max_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x double> @_Z16test_max_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x double> @llvm.maxnum.v3f64 double3 test_max_double3(double3 p0, double3 p1) { return max(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> @_Z16test_max_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> @_Z16test_max_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x double> @llvm.maxnum.v4f64 double4 test_max_double4(double4 p0, double4 p1) { return max(p0, p1); } diff --git a/clang/test/CodeGenHLSL/builtins/min-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/min-overloads.hlsl index 5c200f488c24..f81fa128ce9c 100644 --- a/clang/test/CodeGenHLSL/builtins/min-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/min-overloads.hlsl @@ -4,14 +4,14 @@ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF #ifdef __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef <4 x i16> {{.*}}test_min_short4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> {{.*}}test_min_short4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x i16> poison, i16 %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x i16> [[CONV0]], <4 x i16> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MIN:%.*]] = call noundef <4 x i16> @llvm.smin.v4i16(<4 x i16> %{{.*}}, <4 x i16> [[CONV1]]) // NATIVE_HALF: ret <4 x i16> [[MIN]] int16_t4 test_min_short4_mismatch(int16_t4 p0, int16_t p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> {{.*}}test_min_ushort4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> {{.*}}test_min_ushort4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x i16> poison, i16 %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x i16> [[CONV0]], <4 x i16> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MIN:%.*]] = call noundef <4 x i16> @llvm.umin.v4i16(<4 x i16> %{{.*}}, <4 x i16> [[CONV1]]) @@ -19,61 +19,61 @@ int16_t4 test_min_short4_mismatch(int16_t4 p0, int16_t p1) { return min(p0, p1); uint16_t4 test_min_ushort4_mismatch(uint16_t4 p0, uint16_t p1) { return min(p0, p1); } #endif -// CHECK-LABEL: define noundef <4 x i32> {{.*}}test_min_int4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i32> {{.*}}test_min_int4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i32> poison, i32 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i32> [[CONV0]], <4 x i32> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call noundef <4 x i32> @llvm.smin.v4i32(<4 x i32> %{{.*}}, <4 x i32> [[CONV1]]) // CHECK: ret <4 x i32> [[MIN]] int4 test_min_int4_mismatch(int4 p0, int p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> {{.*}}test_min_uint4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i32> {{.*}}test_min_uint4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i32> poison, i32 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i32> [[CONV0]], <4 x i32> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call noundef <4 x i32> @llvm.umin.v4i32(<4 x i32> %{{.*}}, <4 x i32> [[CONV1]]) // CHECK: ret <4 x i32> [[MIN]] uint4 test_min_uint4_mismatch(uint4 p0, uint p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> {{.*}}test_min_long4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i64> {{.*}}test_min_long4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i64> poison, i64 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i64> [[CONV0]], <4 x i64> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call noundef <4 x i64> @llvm.smin.v4i64(<4 x i64> %{{.*}}, <4 x i64> [[CONV1]]) // CHECK: ret <4 x i64> [[MIN]] int64_t4 test_min_long4_mismatch(int64_t4 p0, int64_t p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> {{.*}}test_min_ulong4_mismatch +// CHECK-LABEL: define hidden noundef <4 x i64> {{.*}}test_min_ulong4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x i64> poison, i64 %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x i64> [[CONV0]], <4 x i64> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call noundef <4 x i64> @llvm.umin.v4i64(<4 x i64> %{{.*}}, <4 x i64> [[CONV1]]) // CHECK: ret <4 x i64> [[MIN]] uint64_t4 test_min_ulong4_mismatch(uint64_t4 p0, uint64_t p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> {{.*}}test_min_half4_mismatch +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> {{.*}}test_min_half4_mismatch // NATIVE_HALF: [[CONV0:%.*]] = insertelement <4 x half> poison, half %{{.*}}, i64 0 // NATIVE_HALF: [[CONV1:%.*]] = shufflevector <4 x half> [[CONV0]], <4 x half> poison, <4 x i32> zeroinitializer // NATIVE_HALF: [[MIN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.minnum.v4f16(<4 x half> %{{.*}}, <4 x half> [[CONV1]]) // NATIVE_HALF: ret <4 x half> [[MIN]] -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_min_half4_mismatch +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_min_half4_mismatch // NO_HALF: [[CONV0:%.*]] = insertelement <4 x float> poison, float %{{.*}}, i64 0 // NO_HALF: [[CONV1:%.*]] = shufflevector <4 x float> [[CONV0]], <4 x float> poison, <4 x i32> zeroinitializer // NO_HALF: [[MIN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.minnum.v4f32(<4 x float> %{{.*}}, <4 x float> [[CONV1]]) // NO_HALF: ret <4 x float> [[MIN]] half4 test_min_half4_mismatch(half4 p0, half p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_min_float4_mismatch +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_min_float4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x float> poison, float %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x float> [[CONV0]], <4 x float> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.minnum.v4f32(<4 x float> %{{.*}}, <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[MIN]] float4 test_min_float4_mismatch(float4 p0, float p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch // CHECK: [[CONV0:%.*]] = insertelement <4 x double> poison, double %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x double> [[CONV0]], <4 x double> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x double> @llvm.minnum.v4f64(<4 x double> %{{.*}}, <4 x double> [[CONV1]]) // CHECK: ret <4 x double> [[MIN]] double4 test_min_double4_mismatch(double4 p0, double p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch2 // CHECK: [[CONV0:%.*]] = insertelement <4 x double> poison, double %{{.*}}, i64 0 // CHECK: [[CONV1:%.*]] = shufflevector <4 x double> [[CONV0]], <4 x double> poison, <4 x i32> zeroinitializer // CHECK: [[MIN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef <4 x double> @llvm.minnum.v4f64(<4 x double> [[CONV1]], <4 x double> %{{.*}}) diff --git a/clang/test/CodeGenHLSL/builtins/min.hlsl b/clang/test/CodeGenHLSL/builtins/min.hlsl index 508d8b68ea45..b3e8fedff9b1 100644 --- a/clang/test/CodeGenHLSL/builtins/min.hlsl +++ b/clang/test/CodeGenHLSL/builtins/min.hlsl @@ -6,131 +6,131 @@ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF #ifdef __HLSL_ENABLE_16_BIT -// NATIVE_HALF-LABEL: define noundef i16 @_Z14test_min_short +// NATIVE_HALF-LABEL: define hidden noundef i16 @_Z14test_min_short // NATIVE_HALF: call i16 @llvm.smin.i16( int16_t test_min_short(int16_t p0, int16_t p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <2 x i16> @_Z15test_min_short2 +// NATIVE_HALF-LABEL: define hidden noundef <2 x i16> @_Z15test_min_short2 // NATIVE_HALF: call <2 x i16> @llvm.smin.v2i16( int16_t2 test_min_short2(int16_t2 p0, int16_t2 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <3 x i16> @_Z15test_min_short3 +// NATIVE_HALF-LABEL: define hidden noundef <3 x i16> @_Z15test_min_short3 // NATIVE_HALF: call <3 x i16> @llvm.smin.v3i16 int16_t3 test_min_short3(int16_t3 p0, int16_t3 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> @_Z15test_min_short4 +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> @_Z15test_min_short4 // NATIVE_HALF: call <4 x i16> @llvm.smin.v4i16 int16_t4 test_min_short4(int16_t4 p0, int16_t4 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef i16 @_Z15test_min_ushort +// NATIVE_HALF-LABEL: define hidden noundef i16 @_Z15test_min_ushort // NATIVE_HALF: call i16 @llvm.umin.i16( uint16_t test_min_ushort(uint16_t p0, uint16_t p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <2 x i16> @_Z16test_min_ushort2 +// NATIVE_HALF-LABEL: define hidden noundef <2 x i16> @_Z16test_min_ushort2 // NATIVE_HALF: call <2 x i16> @llvm.umin.v2i16 uint16_t2 test_min_ushort2(uint16_t2 p0, uint16_t2 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <3 x i16> @_Z16test_min_ushort3 +// NATIVE_HALF-LABEL: define hidden noundef <3 x i16> @_Z16test_min_ushort3 // NATIVE_HALF: call <3 x i16> @llvm.umin.v3i16 uint16_t3 test_min_ushort3(uint16_t3 p0, uint16_t3 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef <4 x i16> @_Z16test_min_ushort4 +// NATIVE_HALF-LABEL: define hidden noundef <4 x i16> @_Z16test_min_ushort4 // NATIVE_HALF: call <4 x i16> @llvm.umin.v4i16 uint16_t4 test_min_ushort4(uint16_t4 p0, uint16_t4 p1) { return min(p0, p1); } #endif -// CHECK-LABEL: define noundef i32 @_Z12test_min_int +// CHECK-LABEL: define hidden noundef i32 @_Z12test_min_int // CHECK: call i32 @llvm.smin.i32( int test_min_int(int p0, int p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <2 x i32> @_Z13test_min_int2 +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z13test_min_int2 // CHECK: call <2 x i32> @llvm.smin.v2i32 int2 test_min_int2(int2 p0, int2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <3 x i32> @_Z13test_min_int3 +// CHECK-LABEL: define hidden noundef <3 x i32> @_Z13test_min_int3 // CHECK: call <3 x i32> @llvm.smin.v3i32 int3 test_min_int3(int3 p0, int3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> @_Z13test_min_int4 +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z13test_min_int4 // CHECK: call <4 x i32> @llvm.smin.v4i32 int4 test_min_int4(int4 p0, int4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef i32 @_Z13test_min_uint +// CHECK-LABEL: define hidden noundef i32 @_Z13test_min_uint // CHECK: call i32 @llvm.umin.i32( int test_min_uint(uint p0, uint p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <2 x i32> @_Z14test_min_uint2 +// CHECK-LABEL: define hidden noundef <2 x i32> @_Z14test_min_uint2 // CHECK: call <2 x i32> @llvm.umin.v2i32 uint2 test_min_uint2(uint2 p0, uint2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <3 x i32> @_Z14test_min_uint3 +// CHECK-LABEL: define hidden noundef <3 x i32> @_Z14test_min_uint3 // CHECK: call <3 x i32> @llvm.umin.v3i32 uint3 test_min_uint3(uint3 p0, uint3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i32> @_Z14test_min_uint4 +// CHECK-LABEL: define hidden noundef <4 x i32> @_Z14test_min_uint4 // CHECK: call <4 x i32> @llvm.umin.v4i32 uint4 test_min_uint4(uint4 p0, uint4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef i64 @_Z13test_min_long +// CHECK-LABEL: define hidden noundef i64 @_Z13test_min_long // CHECK: call i64 @llvm.smin.i64( int64_t test_min_long(int64_t p0, int64_t p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <2 x i64> @_Z14test_min_long2 +// CHECK-LABEL: define hidden noundef <2 x i64> @_Z14test_min_long2 // CHECK: call <2 x i64> @llvm.smin.v2i64 int64_t2 test_min_long2(int64_t2 p0, int64_t2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <3 x i64> @_Z14test_min_long3 +// CHECK-LABEL: define hidden noundef <3 x i64> @_Z14test_min_long3 // CHECK: call <3 x i64> @llvm.smin.v3i64 int64_t3 test_min_long3(int64_t3 p0, int64_t3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> @_Z14test_min_long4 +// CHECK-LABEL: define hidden noundef <4 x i64> @_Z14test_min_long4 // CHECK: call <4 x i64> @llvm.smin.v4i64 int64_t4 test_min_long4(int64_t4 p0, int64_t4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef i64 @_Z14test_min_ulong +// CHECK-LABEL: define hidden noundef i64 @_Z14test_min_ulong // CHECK: call i64 @llvm.umin.i64( uint64_t test_min_ulong(uint64_t p0, uint64_t p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <2 x i64> @_Z15test_min_ulong2 +// CHECK-LABEL: define hidden noundef <2 x i64> @_Z15test_min_ulong2 // CHECK: call <2 x i64> @llvm.umin.v2i64 uint64_t2 test_min_ulong2(uint64_t2 p0, uint64_t2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <3 x i64> @_Z15test_min_ulong3 +// CHECK-LABEL: define hidden noundef <3 x i64> @_Z15test_min_ulong3 // CHECK: call <3 x i64> @llvm.umin.v3i64 uint64_t3 test_min_ulong3(uint64_t3 p0, uint64_t3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef <4 x i64> @_Z15test_min_ulong4 +// CHECK-LABEL: define hidden noundef <4 x i64> @_Z15test_min_ulong4 // CHECK: call <4 x i64> @llvm.umin.v4i64 uint64_t4 test_min_ulong4(uint64_t4 p0, uint64_t4 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_min_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_min_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.minnum.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_min_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_min_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.minnum.f32( half test_min_half(half p0, half p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_min_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_min_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.minnum.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_min_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_min_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.minnum.v2f32( half2 test_min_half2(half2 p0, half2 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_min_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_min_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.minnum.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_min_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_min_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.minnum.v3f32( half3 test_min_half3(half3 p0, half3 p1) { return min(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_min_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_min_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.minnum.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_min_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_min_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.minnum.v4f32( half4 test_min_half4(half4 p0, half4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_min_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_min_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.minnum.f32( float test_min_float(float p0, float p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_min_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_min_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.minnum.v2f32 float2 test_min_float2(float2 p0, float2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_min_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_min_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.minnum.v3f32 float3 test_min_float3(float3 p0, float3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_min_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_min_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.minnum.v4f32 float4 test_min_float4(float4 p0, float4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) double @_Z15test_min_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) double @_Z15test_min_double // CHECK: call reassoc nnan ninf nsz arcp afn double @llvm.minnum.f64( double test_min_double(double p0, double p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x double> @_Z16test_min_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x double> @_Z16test_min_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x double> @llvm.minnum.v2f64 double2 test_min_double2(double2 p0, double2 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x double> @_Z16test_min_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x double> @_Z16test_min_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x double> @llvm.minnum.v3f64 double3 test_min_double3(double3 p0, double3 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> @_Z16test_min_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> @_Z16test_min_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x double> @llvm.minnum.v4f64 double4 test_min_double4(double4 p0, double4 p1) { return min(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x double> {{.*}}test_min_double4_mismatch // CHECK: call reassoc nnan ninf nsz arcp afn <4 x double> @llvm.minnum.v4f64 double4 test_min_double4_mismatch(double4 p0, double p1) { return min(p0, p1); } diff --git a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl index e9baa25fc640..52ff7da94c4f 100644 --- a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @ // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].normalize.f32(float diff --git a/clang/test/CodeGenHLSL/builtins/normalize.hlsl b/clang/test/CodeGenHLSL/builtins/normalize.hlsl index 830fc26b7acf..cc2378756a50 100644 --- a/clang/test/CodeGenHLSL/builtins/normalize.hlsl +++ b/clang/test/CodeGenHLSL/builtins/normalize.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] half @ // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].normalize.f16(half diff --git a/clang/test/CodeGenHLSL/builtins/or.hlsl b/clang/test/CodeGenHLSL/builtins/or.hlsl index 69c57c5455f7..66cc5572a75b 100644 --- a/clang/test/CodeGenHLSL/builtins/or.hlsl +++ b/clang/test/CodeGenHLSL/builtins/or.hlsl @@ -2,7 +2,7 @@ // RUN: dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s -//CHECK-LABEL: define noundef i1 @_Z14test_or_scalarbb( +//CHECK-LABEL: define hidden noundef i1 @_Z14test_or_scalarbb( //CHECK-SAME: i1 noundef [[X:%.*]], i1 noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] { //CHECK-NEXT: entry: //CHECK: [[HLSL_OR:%.*]] = or i1 [[A:%.*]], [[B:%.*]] @@ -12,7 +12,7 @@ bool test_or_scalar(bool x, bool y) return or(x, y); } -//CHECK-LABEL: define noundef <2 x i1> @_Z13test_or_bool2Dv2_bS_( +//CHECK-LABEL: define hidden noundef <2 x i1> @_Z13test_or_bool2Dv2_bS_( //CHECK-SAME: <2 x i1> noundef [[X:%.*]], <2 x i1> noundef [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[HLSL_OR:%.*]] = or <2 x i1> [[A:%.*]], [[B:%.*]] @@ -22,7 +22,7 @@ bool2 test_or_bool2(bool2 x, bool2 y) return or(x, y); } -//CHECK-LABEL: define noundef <3 x i1> @_Z13test_or_bool3Dv3_bS_( +//CHECK-LABEL: define hidden noundef <3 x i1> @_Z13test_or_bool3Dv3_bS_( //CHECK-SAME: <3 x i1> noundef [[X:%.*]], <3 x i1> noundef [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[HLSL_OR:%.*]] = or <3 x i1> [[A:%.*]], [[B:%.*]] @@ -32,7 +32,7 @@ bool3 test_or_bool3(bool3 x, bool3 y) return or(x, y); } -//CHECK-LABEL: define noundef <4 x i1> @_Z13test_or_bool4Dv4_bS_( +//CHECK-LABEL: define hidden noundef <4 x i1> @_Z13test_or_bool4Dv4_bS_( //CHECK-SAME: <4 x i1> noundef [[X:%.*]], <4 x i1> noundef [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[HLSL_OR:%.*]] = or <4 x i1> [[A:%.*]], [[B:%.*]] @@ -42,7 +42,7 @@ bool4 test_or_bool4(bool4 x, bool4 y) return or(x, y); } -//CHECK-LABEL: define noundef i1 @_Z11test_or_intii( +//CHECK-LABEL: define hidden noundef i1 @_Z11test_or_intii( //CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[TOBBOL:%.*]] = icmp ne i32 [[A:%.*]], 0 @@ -54,7 +54,7 @@ bool test_or_int(int x, int y) return or(x, y); } -//CHECK-LABEL: define noundef <4 x i1> @_Z12test_or_int4Dv4_iS_( +//CHECK-LABEL: define hidden noundef <4 x i1> @_Z12test_or_int4Dv4_iS_( //CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> noundef [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[TOBOOL:%.*]] = icmp ne <4 x i32> [[A:%.*]], zeroinitializer @@ -66,7 +66,7 @@ bool4 test_or_int4(int4 x, int4 y) return or(x, y); } -//CHECK-LABEL: define noundef <4 x i1> @_Z14test_or_float4Dv4_fS_( +//CHECK-LABEL: define hidden noundef <4 x i1> @_Z14test_or_float4Dv4_fS_( //CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) #[[ATTR0]] { //CHECK-NEXT: entry: //CHECK: [[TOBOOL:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> [[A:%.*]], zeroinitializer diff --git a/clang/test/CodeGenHLSL/builtins/pow-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/pow-overloads.hlsl index 39003aef7b7b..0d1f3d3546a3 100644 --- a/clang/test/CodeGenHLSL/builtins/pow-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/pow-overloads.hlsl @@ -2,125 +2,125 @@ // RUN: -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK \ // RUN: -DFLOATATTRS="reassoc nnan ninf nsz arcp afn" -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_pow_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_pow_double // CHECK: [[CONV0:%.*]] = fptrunc [[FLOATATTRS]] double %{{.*}} to float // CHECK: [[CONV1:%.*]] = fptrunc [[FLOATATTRS]] double %{{.*}} to float // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef float @llvm.pow.f32(float [[CONV0]], float [[CONV1]]) // CHECK: ret float [[POW]] float test_pow_double(double p0, double p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_double2 // CHECK: [[CONV0:%.*]] = fptrunc [[FLOATATTRS]] <2 x double> %{{.*}} to <2 x float> // CHECK: [[CONV1:%.*]] = fptrunc [[FLOATATTRS]] <2 x double> %{{.*}} to <2 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <2 x float> @llvm.pow.v2f32(<2 x float> [[CONV0]], <2 x float> [[CONV1]]) // CHECK: ret <2 x float> [[POW]] float2 test_pow_double2(double2 p0, double2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_double3 // CHECK: [[CONV0:%.*]] = fptrunc [[FLOATATTRS]] <3 x double> %{{.*}} to <3 x float> // CHECK: [[CONV1:%.*]] = fptrunc [[FLOATATTRS]] <3 x double> %{{.*}} to <3 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <3 x float> @llvm.pow.v3f32(<3 x float> [[CONV0]], <3 x float> [[CONV1]]) // CHECK: ret <3 x float> [[POW]] float3 test_pow_double3(double3 p0, double3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_double4 // CHECK: [[CONV0:%.*]] = fptrunc [[FLOATATTRS]] <4 x double> %{{.*}} to <4 x float> // CHECK: [[CONV1:%.*]] = fptrunc [[FLOATATTRS]] <4 x double> %{{.*}} to <4 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <4 x float> @llvm.pow.v4f32(<4 x float> [[CONV0]], <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[POW]] float4 test_pow_double4(double4 p0, double4 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_pow_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_pow_int // CHECK: [[CONV0:%.*]] = sitofp i32 %{{.*}} to float // CHECK: [[CONV1:%.*]] = sitofp i32 %{{.*}} to float // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef float @llvm.pow.f32(float [[CONV0]], float [[CONV1]]) // CHECK: ret float [[POW]] float test_pow_int(int p0, int p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_int2 // CHECK: [[CONV0:%.*]] = sitofp <2 x i32> %{{.*}} to <2 x float> // CHECK: [[CONV1:%.*]] = sitofp <2 x i32> %{{.*}} to <2 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <2 x float> @llvm.pow.v2f32(<2 x float> [[CONV0]], <2 x float> [[CONV1]]) // CHECK: ret <2 x float> [[POW]] float2 test_pow_int2(int2 p0, int2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_int3 // CHECK: [[CONV0:%.*]] = sitofp <3 x i32> %{{.*}} to <3 x float> // CHECK: [[CONV1:%.*]] = sitofp <3 x i32> %{{.*}} to <3 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <3 x float> @llvm.pow.v3f32(<3 x float> [[CONV0]], <3 x float> [[CONV1]]) // CHECK: ret <3 x float> [[POW]] float3 test_pow_int3(int3 p0, int3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_int4 // CHECK: [[CONV0:%.*]] = sitofp <4 x i32> %{{.*}} to <4 x float> // CHECK: [[CONV1:%.*]] = sitofp <4 x i32> %{{.*}} to <4 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <4 x float> @llvm.pow.v4f32(<4 x float> [[CONV0]], <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[POW]] float4 test_pow_int4(int4 p0, int4 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_pow_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_pow_uint // CHECK: [[CONV0:%.*]] = uitofp i32 %{{.*}} to float // CHECK: [[CONV1:%.*]] = uitofp i32 %{{.*}} to float // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef float @llvm.pow.f32(float [[CONV0]], float [[CONV1]]) // CHECK: ret float [[POW]] float test_pow_uint(uint p0, uint p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_uint2 // CHECK: [[CONV0:%.*]] = uitofp <2 x i32> %{{.*}} to <2 x float> // CHECK: [[CONV1:%.*]] = uitofp <2 x i32> %{{.*}} to <2 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <2 x float> @llvm.pow.v2f32(<2 x float> [[CONV0]], <2 x float> [[CONV1]]) // CHECK: ret <2 x float> [[POW]] float2 test_pow_uint2(uint2 p0, uint2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_uint3 // CHECK: [[CONV0:%.*]] = uitofp <3 x i32> %{{.*}} to <3 x float> // CHECK: [[CONV1:%.*]] = uitofp <3 x i32> %{{.*}} to <3 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <3 x float> @llvm.pow.v3f32(<3 x float> [[CONV0]], <3 x float> [[CONV1]]) // CHECK: ret <3 x float> [[POW]] float3 test_pow_uint3(uint3 p0, uint3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_uint4 // CHECK: [[CONV0:%.*]] = uitofp <4 x i32> %{{.*}} to <4 x float> // CHECK: [[CONV1:%.*]] = uitofp <4 x i32> %{{.*}} to <4 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <4 x float> @llvm.pow.v4f32(<4 x float> [[CONV0]], <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[POW]] float4 test_pow_uint4(uint4 p0, uint4 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_pow_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_pow_int64_t // CHECK: [[CONV0:%.*]] = sitofp i64 %{{.*}} to float // CHECK: [[CONV1:%.*]] = sitofp i64 %{{.*}} to float // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef float @llvm.pow.f32(float [[CONV0]], float [[CONV1]]) // CHECK: ret float [[POW]] float test_pow_int64_t(int64_t p0, int64_t p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_int64_t2 // CHECK: [[CONV0:%.*]] = sitofp <2 x i64> %{{.*}} to <2 x float> // CHECK: [[CONV1:%.*]] = sitofp <2 x i64> %{{.*}} to <2 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <2 x float> @llvm.pow.v2f32(<2 x float> [[CONV0]], <2 x float> [[CONV1]]) // CHECK: ret <2 x float> [[POW]] float2 test_pow_int64_t2(int64_t2 p0, int64_t2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_int64_t3 // CHECK: [[CONV0:%.*]] = sitofp <3 x i64> %{{.*}} to <3 x float> // CHECK: [[CONV1:%.*]] = sitofp <3 x i64> %{{.*}} to <3 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <3 x float> @llvm.pow.v3f32(<3 x float> [[CONV0]], <3 x float> [[CONV1]]) // CHECK: ret <3 x float> [[POW]] float3 test_pow_int64_t3(int64_t3 p0, int64_t3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_int64_t4 // CHECK: [[CONV0:%.*]] = sitofp <4 x i64> %{{.*}} to <4 x float> // CHECK: [[CONV1:%.*]] = sitofp <4 x i64> %{{.*}} to <4 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <4 x float> @llvm.pow.v4f32(<4 x float> [[CONV0]], <4 x float> [[CONV1]]) // CHECK: ret <4 x float> [[POW]] float4 test_pow_int64_t4(int64_t4 p0, int64_t4 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_pow_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_pow_uint64_t // CHECK: [[CONV0:%.*]] = uitofp i64 %{{.*}} to float // CHECK: [[CONV1:%.*]] = uitofp i64 %{{.*}} to float // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef float @llvm.pow.f32(float [[CONV0]], float [[CONV1]]) // CHECK: ret float [[POW]] float test_pow_uint64_t(uint64_t p0, uint64_t p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_pow_uint64_t2 // CHECK: [[CONV0:%.*]] = uitofp <2 x i64> %{{.*}} to <2 x float> // CHECK: [[CONV1:%.*]] = uitofp <2 x i64> %{{.*}} to <2 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <2 x float> @llvm.pow.v2f32(<2 x float> [[CONV0]], <2 x float> [[CONV1]]) // CHECK: ret <2 x float> [[POW]] float2 test_pow_uint64_t2(uint64_t2 p0, uint64_t2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_pow_uint64_t3 // CHECK: [[CONV0:%.*]] = uitofp <3 x i64> %{{.*}} to <3 x float> // CHECK: [[CONV1:%.*]] = uitofp <3 x i64> %{{.*}} to <3 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <3 x float> @llvm.pow.v3f32(<3 x float> [[CONV0]], <3 x float> [[CONV1]]) // CHECK: ret <3 x float> [[POW]] float3 test_pow_uint64_t3(uint64_t3 p0, uint64_t3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_pow_uint64_t4 // CHECK: [[CONV0:%.*]] = uitofp <4 x i64> %{{.*}} to <4 x float> // CHECK: [[CONV1:%.*]] = uitofp <4 x i64> %{{.*}} to <4 x float> // CHECK: [[POW:%.*]] = call [[FLOATATTRS]] noundef <4 x float> @llvm.pow.v4f32(<4 x float> [[CONV0]], <4 x float> [[CONV1]]) diff --git a/clang/test/CodeGenHLSL/builtins/pow.hlsl b/clang/test/CodeGenHLSL/builtins/pow.hlsl index fd21f1b94c57..fcde755e15fc 100644 --- a/clang/test/CodeGenHLSL/builtins/pow.hlsl +++ b/clang/test/CodeGenHLSL/builtins/pow.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_pow_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_pow_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.pow.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_pow_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_pow_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.pow.f32( half test_pow_half(half p0, half p1) { return pow(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_pow_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_pow_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.pow.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_pow_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_pow_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32( half2 test_pow_half2(half2 p0, half2 p1) { return pow(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_pow_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_pow_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.pow.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_pow_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_pow_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32( half3 test_pow_half3(half3 p0, half3 p1) { return pow(p0, p1); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_pow_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_pow_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.pow.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_pow_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_pow_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32( half4 test_pow_half4(half4 p0, half4 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_pow_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_pow_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.pow.f32( float test_pow_float(float p0, float p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_pow_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_pow_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32 float2 test_pow_float2(float2 p0, float2 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_pow_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_pow_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32 float3 test_pow_float3(float3 p0, float3 p1) { return pow(p0, p1); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_pow_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_pow_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32 float4 test_pow_float4(float4 p0, float4 p1) { return pow(p0, p1); } diff --git a/clang/test/CodeGenHLSL/builtins/radians-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/radians-overloads.hlsl index d0cfc7b60265..4b12f590edcd 100644 --- a/clang/test/CodeGenHLSL/builtins/radians-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/radians-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DTARGET=dx -DFNATTRS="noundef nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef nofpclass(nan inf)" // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" // CHECK: define [[FNATTRS]] float @ // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].radians.f32( diff --git a/clang/test/CodeGenHLSL/builtins/radians.hlsl b/clang/test/CodeGenHLSL/builtins/radians.hlsl index efdeb9f6e142..f281747fbf29 100644 --- a/clang/test/CodeGenHLSL/builtins/radians.hlsl +++ b/clang/test/CodeGenHLSL/builtins/radians.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=dx -DFNATTRS="noundef nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=dx -DFNATTRS="noundef nofpclass(nan inf)" +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef nofpclass(nan inf)" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" // NATIVE_HALF: define [[FNATTRS]] half @ diff --git a/clang/test/CodeGenHLSL/builtins/rcp.hlsl b/clang/test/CodeGenHLSL/builtins/rcp.hlsl index 8f07f3a03153..cdfaa3c5f1ee 100644 --- a/clang/test/CodeGenHLSL/builtins/rcp.hlsl +++ b/clang/test/CodeGenHLSL/builtins/rcp.hlsl @@ -13,90 +13,90 @@ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF,SPIR_NO_HALF,SPIR_CHECK -// DXIL_NATIVE_HALF: define noundef nofpclass(nan inf) half @ -// SPIR_NATIVE_HALF: define spir_func noundef nofpclass(nan inf) half @ +// DXIL_NATIVE_HALF: define hidden noundef nofpclass(nan inf) half @ +// SPIR_NATIVE_HALF: define hidden spir_func noundef nofpclass(nan inf) half @ // NATIVE_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn half 0xH3C00, %{{.*}} // NATIVE_HALF: ret half %hlsl.rcp -// DXIL_NO_HALF: define noundef nofpclass(nan inf) float @ -// SPIR_NO_HALF: define spir_func noundef nofpclass(nan inf) float @ +// DXIL_NO_HALF: define hidden noundef nofpclass(nan inf) float @ +// SPIR_NO_HALF: define hidden spir_func noundef nofpclass(nan inf) float @ // NO_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn float 1.000000e+00, %{{.*}} // NO_HALF: ret float %hlsl.rcp half test_rcp_half(half p0) { return rcp(p0); } -// DXIL_NATIVE_HALF: define noundef nofpclass(nan inf) <2 x half> @ -// SPIR_NATIVE_HALF: define spir_func noundef nofpclass(nan inf) <2 x half> @ +// DXIL_NATIVE_HALF: define hidden noundef nofpclass(nan inf) <2 x half> @ +// SPIR_NATIVE_HALF: define hidden spir_func noundef nofpclass(nan inf) <2 x half> @ // NATIVE_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <2 x half> splat (half 0xH3C00), %{{.*}} // NATIVE_HALF: ret <2 x half> %hlsl.rcp -// DXIL_NO_HALF: define noundef nofpclass(nan inf) <2 x float> @ -// SPIR_NO_HALF: define spir_func noundef nofpclass(nan inf) <2 x float> @ +// DXIL_NO_HALF: define hidden noundef nofpclass(nan inf) <2 x float> @ +// SPIR_NO_HALF: define hidden spir_func noundef nofpclass(nan inf) <2 x float> @ // NO_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <2 x float> splat (float 1.000000e+00), %{{.*}} // NO_HALF: ret <2 x float> %hlsl.rcp half2 test_rcp_half2(half2 p0) { return rcp(p0); } -// DXIL_NATIVE_HALF: define noundef nofpclass(nan inf) <3 x half> @ -// SPIR_NATIVE_HALF: define spir_func noundef nofpclass(nan inf) <3 x half> @ +// DXIL_NATIVE_HALF: define hidden noundef nofpclass(nan inf) <3 x half> @ +// SPIR_NATIVE_HALF: define hidden spir_func noundef nofpclass(nan inf) <3 x half> @ // NATIVE_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <3 x half> splat (half 0xH3C00), %{{.*}} // NATIVE_HALF: ret <3 x half> %hlsl.rcp -// DXIL_NO_HALF: define noundef nofpclass(nan inf) <3 x float> @ -// SPIR_NO_HALF: define spir_func noundef nofpclass(nan inf) <3 x float> @ +// DXIL_NO_HALF: define hidden noundef nofpclass(nan inf) <3 x float> @ +// SPIR_NO_HALF: define hidden spir_func noundef nofpclass(nan inf) <3 x float> @ // NO_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <3 x float> splat (float 1.000000e+00), %{{.*}} // NO_HALF: ret <3 x float> %hlsl.rcp half3 test_rcp_half3(half3 p0) { return rcp(p0); } -// DXIL_NATIVE_HALF: define noundef nofpclass(nan inf) <4 x half> @ -// SPIR_NATIVE_HALF: define spir_func noundef nofpclass(nan inf) <4 x half> @ +// DXIL_NATIVE_HALF: define hidden noundef nofpclass(nan inf) <4 x half> @ +// SPIR_NATIVE_HALF: define hidden spir_func noundef nofpclass(nan inf) <4 x half> @ // NATIVE_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <4 x half> splat (half 0xH3C00), %{{.*}} // NATIVE_HALF: ret <4 x half> %hlsl.rcp -// DXIL_NO_HALF: define noundef nofpclass(nan inf) <4 x float> @ -// SPIR_NO_HALF: define spir_func noundef nofpclass(nan inf) <4 x float> @ +// DXIL_NO_HALF: define hidden noundef nofpclass(nan inf) <4 x float> @ +// SPIR_NO_HALF: define hidden spir_func noundef nofpclass(nan inf) <4 x float> @ // NO_HALF: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <4 x float> splat (float 1.000000e+00), %{{.*}} // NO_HALF: ret <4 x float> %hlsl.rcp half4 test_rcp_half4(half4 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) float @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) float @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) float @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) float @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn float 1.000000e+00, %{{.*}} // CHECK: ret float %hlsl.rcp float test_rcp_float(float p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <2 x float> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <2 x float> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <2 x float> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <2 x float> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <2 x float> splat (float 1.000000e+00), %{{.*}} // CHECK: ret <2 x float> %hlsl.rcp float2 test_rcp_float2(float2 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <3 x float> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <3 x float> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <3 x float> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <3 x float> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <3 x float> splat (float 1.000000e+00), %{{.*}} // CHECK: ret <3 x float> %hlsl.rcp float3 test_rcp_float3(float3 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <4 x float> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <4 x float> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <4 x float> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <4 x float> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <4 x float> splat (float 1.000000e+00), %{{.*}} // CHECK: ret <4 x float> %hlsl.rcp float4 test_rcp_float4(float4 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) double @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) double @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) double @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) double @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn double 1.000000e+00, %{{.*}} // CHECK: ret double %hlsl.rcp double test_rcp_double(double p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <2 x double> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <2 x double> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <2 x double> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <2 x double> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <2 x double> splat (double 1.000000e+00), %{{.*}} // CHECK: ret <2 x double> %hlsl.rcp double2 test_rcp_double2(double2 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <3 x double> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <3 x double> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <3 x double> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <3 x double> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <3 x double> splat (double 1.000000e+00), %{{.*}} // CHECK: ret <3 x double> %hlsl.rcp double3 test_rcp_double3(double3 p0) { return rcp(p0); } -// DXIL_CHECK: define noundef nofpclass(nan inf) <4 x double> @ -// SPIR_CHECK: define spir_func noundef nofpclass(nan inf) <4 x double> @ +// DXIL_CHECK: define hidden noundef nofpclass(nan inf) <4 x double> @ +// SPIR_CHECK: define hidden spir_func noundef nofpclass(nan inf) <4 x double> @ // CHECK: %hlsl.rcp = fdiv reassoc nnan ninf nsz arcp afn <4 x double> splat (double 1.000000e+00), %{{.*}} // CHECK: ret <4 x double> %hlsl.rcp double4 test_rcp_double4(double4 p0) { return rcp(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/reflect.hlsl b/clang/test/CodeGenHLSL/builtins/reflect.hlsl index c082e63ac1da..65fefd801ffe 100644 --- a/clang/test/CodeGenHLSL/builtins/reflect.hlsl +++ b/clang/test/CodeGenHLSL/builtins/reflect.hlsl @@ -6,7 +6,7 @@ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh( // CHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000 @@ -15,7 +15,7 @@ // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[I]], [[MUL2_I]] // CHECK-NEXT: ret half [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z17test_reflect_halfDhDh( // SPVCHECK-SAME: half noundef nofpclass(nan inf) [[I:%.*]], half noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[I]], 0xH4000 @@ -28,7 +28,7 @@ half test_reflect_half(half I, half N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_( // CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> nofpclass(nan inf) [[I]], <2 x half> nofpclass(nan inf) [[N]]) @@ -39,7 +39,7 @@ half test_reflect_half(half I, half N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <2 x half> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <2 x half> @_Z18test_reflect_half2Dv2_DhS_( // SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[I:%.*]], <2 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.reflect.v2f16(<2 x half> nofpclass(nan inf) [[I]], <2 x half> nofpclass(nan inf) [[N]]) @@ -49,7 +49,7 @@ half2 test_reflect_half2(half2 I, half2 N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_( // CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> nofpclass(nan inf) [[I]], <3 x half> nofpclass(nan inf) [[N]]) @@ -60,7 +60,7 @@ half2 test_reflect_half2(half2 I, half2 N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <3 x half> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <3 x half> @_Z18test_reflect_half3Dv3_DhS_( // SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[I:%.*]], <3 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.reflect.v3f16(<3 x half> nofpclass(nan inf) [[I]], <3 x half> nofpclass(nan inf) [[N]]) @@ -70,7 +70,7 @@ half3 test_reflect_half3(half3 I, half3 N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_( // CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> nofpclass(nan inf) [[I]], <4 x half> nofpclass(nan inf) [[N]]) @@ -81,7 +81,7 @@ half3 test_reflect_half3(half3 I, half3 N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <4 x half> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <4 x half> @_Z18test_reflect_half4Dv4_DhS_( // SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[I:%.*]], <4 x half> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.reflect.v4f16(<4 x half> nofpclass(nan inf) [[I]], <4 x half> nofpclass(nan inf) [[N]]) @@ -91,7 +91,7 @@ half4 test_reflect_half4(half4 I, half4 N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_reflect_floatff( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z18test_reflect_floatff( // CHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00 @@ -100,7 +100,7 @@ half4 test_reflect_half4(half4 I, half4 N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[I]], [[MUL2_I]] // CHECK-NEXT: ret float [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_reflect_floatff( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z18test_reflect_floatff( // SPVCHECK-SAME: float noundef nofpclass(nan inf) [[I:%.*]], float noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[MUL_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[I]], 2.000000e+00 @@ -113,7 +113,7 @@ float test_reflect_float(float I, float N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_( // CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> nofpclass(nan inf) [[I]], <2 x float> nofpclass(nan inf) [[N]]) @@ -124,7 +124,7 @@ float test_reflect_float(float I, float N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <2 x float> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <2 x float> @_Z19test_reflect_float2Dv2_fS_( // SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[I:%.*]], <2 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.reflect.v2f32(<2 x float> nofpclass(nan inf) [[I]], <2 x float> nofpclass(nan inf) [[N]]) @@ -134,7 +134,7 @@ float2 test_reflect_float2(float2 I, float2 N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_( // CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> nofpclass(nan inf) [[I]], <3 x float> nofpclass(nan inf) [[N]]) @@ -145,7 +145,7 @@ float2 test_reflect_float2(float2 I, float2 N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <3 x float> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <3 x float> @_Z19test_reflect_float3Dv3_fS_( // SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[I:%.*]], <3 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.reflect.v3f32(<3 x float> nofpclass(nan inf) [[I]], <3 x float> nofpclass(nan inf) [[N]]) @@ -155,7 +155,7 @@ float3 test_reflect_float3(float3 I, float3 N) { return reflect(I, N); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_( // CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> nofpclass(nan inf) [[I]], <4 x float> nofpclass(nan inf) [[N]]) @@ -166,7 +166,7 @@ float3 test_reflect_float3(float3 I, float3 N) { // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[I]], [[MUL1_I]] // CHECK-NEXT: ret <4 x float> [[SUB_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <4 x float> @_Z19test_reflect_float4Dv4_fS_( // SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[I:%.*]], <4 x float> noundef nofpclass(nan inf) [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_REFLECT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.reflect.v4f32(<4 x float> nofpclass(nan inf) [[I]], <4 x float> nofpclass(nan inf) [[N]]) diff --git a/clang/test/CodeGenHLSL/builtins/reversebits.hlsl b/clang/test/CodeGenHLSL/builtins/reversebits.hlsl index fe137b9cae4e..91375c8f4eb8 100644 --- a/clang/test/CodeGenHLSL/builtins/reversebits.hlsl +++ b/clang/test/CodeGenHLSL/builtins/reversebits.hlsl @@ -3,25 +3,25 @@ // RUN: -emit-llvm -disable-llvm-passes -O3 -o - | FileCheck %s #ifdef __HLSL_ENABLE_16_BIT -// CHECK: define noundef i16 @ +// CHECK: define hidden noundef i16 @ // CHECK: call i16 @llvm.bitreverse.i16( uint16_t test_bitreverse_ushort(uint16_t p0) { return reversebits(p0); } -// CHECK: define noundef <2 x i16> @ +// CHECK: define hidden noundef <2 x i16> @ // CHECK: call <2 x i16> @llvm.bitreverse.v2i16 uint16_t2 test_bitreverse_ushort2(uint16_t2 p0) { return reversebits(p0); } -// CHECK: define noundef <3 x i16> @ +// CHECK: define hidden noundef <3 x i16> @ // CHECK: call <3 x i16> @llvm.bitreverse.v3i16 uint16_t3 test_bitreverse_ushort3(uint16_t3 p0) { return reversebits(p0); } -// CHECK: define noundef <4 x i16> @ +// CHECK: define hidden noundef <4 x i16> @ // CHECK: call <4 x i16> @llvm.bitreverse.v4i16 uint16_t4 test_bitreverse_ushort4(uint16_t4 p0) { @@ -29,50 +29,50 @@ uint16_t4 test_bitreverse_ushort4(uint16_t4 p0) } #endif -// CHECK: define noundef i32 @ +// CHECK: define hidden noundef i32 @ // CHECK: call i32 @llvm.bitreverse.i32( int test_bitreverse_uint(uint p0) { return reversebits(p0); } -// CHECK: define noundef <2 x i32> @ +// CHECK: define hidden noundef <2 x i32> @ // CHECK: call <2 x i32> @llvm.bitreverse.v2i32 uint2 test_bitreverse_uint2(uint2 p0) { return reversebits(p0); } -// CHECK: define noundef <3 x i32> @ +// CHECK: define hidden noundef <3 x i32> @ // CHECK: call <3 x i32> @llvm.bitreverse.v3i32 uint3 test_bitreverse_uint3(uint3 p0) { return reversebits(p0); } -// CHECK: define noundef <4 x i32> @ +// CHECK: define hidden noundef <4 x i32> @ // CHECK: call <4 x i32> @llvm.bitreverse.v4i32 uint4 test_bitreverse_uint4(uint4 p0) { return reversebits(p0); } -// CHECK: define noundef i64 @ +// CHECK: define hidden noundef i64 @ // CHECK: call i64 @llvm.bitreverse.i64( uint64_t test_bitreverse_long(uint64_t p0) { return reversebits(p0); } -// CHECK: define noundef <2 x i64> @ +// CHECK: define hidden noundef <2 x i64> @ // CHECK: call <2 x i64> @llvm.bitreverse.v2i64 uint64_t2 test_bitreverse_long2(uint64_t2 p0) { return reversebits(p0); } -// CHECK: define noundef <3 x i64> @ +// CHECK: define hidden noundef <3 x i64> @ // CHECK: call <3 x i64> @llvm.bitreverse.v3i64 uint64_t3 test_bitreverse_long3(uint64_t3 p0) { return reversebits(p0); } -// CHECK: define noundef <4 x i64> @ +// CHECK: define hidden noundef <4 x i64> @ // CHECK: call <4 x i64> @llvm.bitreverse.v4i64 uint64_t4 test_bitreverse_long4(uint64_t4 p0) { diff --git a/clang/test/CodeGenHLSL/builtins/round-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/round-overloads.hlsl index 109633a64d34..3b07fcec064d 100644 --- a/clang/test/CodeGenHLSL/builtins/round-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/round-overloads.hlsl @@ -2,87 +2,87 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_round_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_round_double // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_double(double p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_double2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_double2(double2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_double3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_double3(double3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_double4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_double4(double4 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_round_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_round_int // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_int(int p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_int2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_int2(int2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_int3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_int3(int3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_int4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_int4(int4 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_round_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_round_uint // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_uint(uint p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_uint2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_uint2(uint2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_uint3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_uint3(uint3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_uint4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_uint4(uint4 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_round_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_round_int64_t // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_int64_t(int64_t p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_int64_t2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_int64_t2(int64_t2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_int64_t3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_int64_t3(int64_t3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_int64_t4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_int64_t4(int64_t4 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_round_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_round_uint64_t // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_uint64_t(uint64_t p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_round_uint64_t2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_uint64_t2(uint64_t2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_round_uint64_t3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_uint64_t3(uint64_t3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_round_uint64_t4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_uint64_t4(uint64_t4 p0) { return round(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/round.hlsl b/clang/test/CodeGenHLSL/builtins/round.hlsl index a945a9677abb..755f2e86fb11 100644 --- a/clang/test/CodeGenHLSL/builtins/round.hlsl +++ b/clang/test/CodeGenHLSL/builtins/round.hlsl @@ -5,48 +5,48 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z15test_round_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z15test_round_half // NATIVE_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn half @llvm.roundeven.f16( // NATIVE_HALF: ret half %elt.roundeven -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z15test_round_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_round_half // NO_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // NO_HALF: ret float %elt.roundeven half test_round_half(half p0) { return round(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z16test_round_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z16test_round_half2 // NATIVE_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.roundeven.v2f16 // NATIVE_HALF: ret <2 x half> %elt.roundeven -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_round_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_round_half2 // NO_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32( // NO_HALF: ret <2 x float> %elt.roundeven half2 test_round_half2(half2 p0) { return round(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z16test_round_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z16test_round_half3 // NATIVE_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.roundeven.v3f16 // NATIVE_HALF: ret <3 x half> %elt.roundeven -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_round_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_round_half3 // NO_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32( // NO_HALF: ret <3 x float> %elt.roundeven half3 test_round_half3(half3 p0) { return round(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z16test_round_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z16test_round_half4 // NATIVE_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.roundeven.v4f16 // NATIVE_HALF: ret <4 x half> %elt.roundeven -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_round_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_round_half4 // NO_HALF: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32( // NO_HALF: ret <4 x float> %elt.roundeven half4 test_round_half4(half4 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z16test_round_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z16test_round_float // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn float @llvm.roundeven.f32( // CHECK: ret float %elt.roundeven float test_round_float(float p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z17test_round_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z17test_round_float2 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.roundeven.v2f32 // CHECK: ret <2 x float> %elt.roundeven float2 test_round_float2(float2 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z17test_round_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z17test_round_float3 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.roundeven.v3f32 // CHECK: ret <3 x float> %elt.roundeven float3 test_round_float3(float3 p0) { return round(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z17test_round_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z17test_round_float4 // CHECK: %elt.roundeven = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.roundeven.v4f32 // CHECK: ret <4 x float> %elt.roundeven float4 test_round_float4(float4 p0) { return round(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/rsqrt-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/rsqrt-overloads.hlsl index 09f21f366b9d..262f306b9257 100644 --- a/clang/test/CodeGenHLSL/builtins/rsqrt-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/rsqrt-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @ // CHECK: %hlsl.rsqrt = call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].rsqrt.f32( diff --git a/clang/test/CodeGenHLSL/builtins/rsqrt.hlsl b/clang/test/CodeGenHLSL/builtins/rsqrt.hlsl index 6c9b1f643713..9c398fd6f06c 100644 --- a/clang/test/CodeGenHLSL/builtins/rsqrt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/rsqrt.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] half @ // NATIVE_HALF: %hlsl.rsqrt = call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].rsqrt.f16( diff --git a/clang/test/CodeGenHLSL/builtins/sign.hlsl b/clang/test/CodeGenHLSL/builtins/sign.hlsl index 8cc910933f46..cbdb92938893 100644 --- a/clang/test/CodeGenHLSL/builtins/sign.hlsl +++ b/clang/test/CodeGenHLSL/builtins/sign.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=dx -DFNATTRS=noundef +// RUN: -DTARGET=dx -DFNATTRS="hidden noundef" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DTARGET=spv -DFNATTRS="spir_func noundef" +// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef" // NATIVE_HALF: define [[FNATTRS]] i32 @ // NATIVE_HALF: %hlsl.sign = call i32 @llvm.[[TARGET]].sign.f16( diff --git a/clang/test/CodeGenHLSL/builtins/sin-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/sin-overloads.hlsl index a5522e4f28b7..e471cb3d42c5 100644 --- a/clang/test/CodeGenHLSL/builtins/sin-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/sin-overloads.hlsl @@ -2,67 +2,67 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sin_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sin_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_double(double p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_double2(double2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_double3(double3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_double4(double4 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sin_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sin_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_int(int p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_int2(int2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_int3(int3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_int4(int4 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sin_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sin_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_uint(uint p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_uint2(uint2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_uint3(uint3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_uint4(uint4 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sin_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sin_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_int64_t(int64_t p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_int64_t2(int64_t2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_int64_t3(int64_t3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_int64_t4(int64_t4 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sin_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sin_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_uint64_t(uint64_t p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sin_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_uint64_t2(uint64_t2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sin_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_uint64_t3(uint64_t3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sin_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_uint64_t4(uint64_t4 p0) { return sin(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/sin.hlsl b/clang/test/CodeGenHLSL/builtins/sin.hlsl index 69c657239ef9..9bbe97997aa3 100644 --- a/clang/test/CodeGenHLSL/builtins/sin.hlsl +++ b/clang/test/CodeGenHLSL/builtins/sin.hlsl @@ -5,36 +5,36 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z13test_sin_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z13test_sin_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.sin.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z13test_sin_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z13test_sin_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( half test_sin_half(half p0) { return sin(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z14test_sin_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z14test_sin_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.sin.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z14test_sin_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z14test_sin_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32( half2 test_sin_half2(half2 p0) { return sin(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z14test_sin_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z14test_sin_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.sin.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z14test_sin_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z14test_sin_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32( half3 test_sin_half3(half3 p0) { return sin(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z14test_sin_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z14test_sin_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.sin.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z14test_sin_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z14test_sin_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32( half4 test_sin_half4(half4 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z14test_sin_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_sin_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.sin.f32( float test_sin_float(float p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_sin_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_sin_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sin.v2f32 float2 test_sin_float2(float2 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_sin_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_sin_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sin.v3f32 float3 test_sin_float3(float3 p0) { return sin(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_sin_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_sin_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sin.v4f32 float4 test_sin_float4(float4 p0) { return sin(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl index d3e5c1059029..bef64ce77d47 100644 --- a/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl +++ b/clang/test/CodeGenHLSL/builtins/smoothstep.hlsl @@ -6,7 +6,7 @@ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh( // CHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn half [[X]], [[MIN]] @@ -19,7 +19,7 @@ // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn half [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret half [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) half @_Z20test_smoothstep_halfDhDhDh( // SPVCHECK-SAME: half noundef nofpclass(nan inf) [[MIN:%.*]], half noundef nofpclass(nan inf) [[MAX:%.*]], half noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.smoothstep.f16(half nofpclass(nan inf) [[MIN]], half nofpclass(nan inf) [[MAX]], half nofpclass(nan inf) [[X]]) @@ -27,7 +27,7 @@ // half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_( // CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[MIN]] @@ -40,7 +40,7 @@ half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, M // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <2 x half> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <2 x half> @_Z21test_smoothstep_half2Dv2_DhS_S_( // SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.smoothstep.v2f16(<2 x half> nofpclass(nan inf) [[MIN]], <2 x half> nofpclass(nan inf) [[MAX]], <2 x half> nofpclass(nan inf) [[X]]) @@ -48,7 +48,7 @@ half test_smoothstep_half(half Min, half Max, half X) { return smoothstep(Min, M // half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_( // CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[MIN]] @@ -61,7 +61,7 @@ half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(M // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <3 x half> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <3 x half> @_Z21test_smoothstep_half3Dv3_DhS_S_( // SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.smoothstep.v3f16(<3 x half> nofpclass(nan inf) [[MIN]], <3 x half> nofpclass(nan inf) [[MAX]], <3 x half> nofpclass(nan inf) [[X]]) @@ -69,7 +69,7 @@ half2 test_smoothstep_half2(half2 Min, half2 Max, half2 X) { return smoothstep(M // half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_( // CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[MIN]] @@ -82,7 +82,7 @@ half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(M // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <4 x half> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <4 x half> @_Z21test_smoothstep_half4Dv4_DhS_S_( // SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x half> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x half> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.smoothstep.v4f16(<4 x half> nofpclass(nan inf) [[MIN]], <4 x half> nofpclass(nan inf) [[MAX]], <4 x half> nofpclass(nan inf) [[X]]) @@ -90,7 +90,7 @@ half3 test_smoothstep_half3(half3 Min, half3 Max, half3 X) { return smoothstep(M // half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff( // CHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn float [[X]], [[MIN]] @@ -103,7 +103,7 @@ half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(M // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret float [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) float @_Z21test_smoothstep_floatfff( // SPVCHECK-SAME: float noundef nofpclass(nan inf) [[MIN:%.*]], float noundef nofpclass(nan inf) [[MAX:%.*]], float noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.smoothstep.f32(float nofpclass(nan inf) [[MIN]], float nofpclass(nan inf) [[MAX]], float nofpclass(nan inf) [[X]]) @@ -111,7 +111,7 @@ half4 test_smoothstep_half4(half4 Min, half4 Max, half4 X) { return smoothstep(M // float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_( // CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[MIN]] @@ -124,7 +124,7 @@ float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(M // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <2 x float> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <2 x float> @_Z22test_smoothstep_float2Dv2_fS_S_( // SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <2 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <2 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.smoothstep.v2f32(<2 x float> nofpclass(nan inf) [[MIN]], <2 x float> nofpclass(nan inf) [[MAX]], <2 x float> nofpclass(nan inf) [[X]]) @@ -132,7 +132,7 @@ float test_smoothstep_float(float Min, float Max, float X) { return smoothstep(M // float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_( // CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[MIN]] @@ -145,7 +145,7 @@ float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smooths // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <3 x float> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <3 x float> @_Z22test_smoothstep_float3Dv3_fS_S_( // SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <3 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <3 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.smoothstep.v3f32(<3 x float> nofpclass(nan inf) [[MIN]], <3 x float> nofpclass(nan inf) [[MAX]], <3 x float> nofpclass(nan inf) [[X]]) @@ -153,7 +153,7 @@ float2 test_smoothstep_float2(float2 Min, float2 Max, float2 X) { return smooths // float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return smoothstep(Min, Max, X); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( // CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[X]], [[MIN]] @@ -166,7 +166,7 @@ float3 test_smoothstep_float3(float3 Min, float3 Max, float3 X) { return smooths // CHECK-NEXT: [[MUL4_I:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> [[TMP0]], [[SUB2_I]] // CHECK-NEXT: ret <4 x float> [[MUL4_I]] // -// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( +// SPVCHECK-LABEL: define hidden spir_func noundef nofpclass(nan inf) <4 x float> @_Z22test_smoothstep_float4Dv4_fS_S_( // SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[MIN:%.*]], <4 x float> noundef nofpclass(nan inf) [[MAX:%.*]], <4 x float> noundef nofpclass(nan inf) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // SPVCHECK-NEXT: [[ENTRY:.*:]] // SPVCHECK-NEXT: [[SPV_SMOOTHSTEP_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.smoothstep.v4f32(<4 x float> nofpclass(nan inf) [[MIN]], <4 x float> nofpclass(nan inf) [[MAX]], <4 x float> nofpclass(nan inf) [[X]]) diff --git a/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl b/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl index a883c9d5cc35..aeb2b79e9029 100644 --- a/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl +++ b/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl @@ -8,7 +8,7 @@ // CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0 // CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1 // -// SPIRV: define spir_func {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]]) +// SPIRV: define hidden spir_func {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]]) // SPIRV-NOT: @llvm.dx.splitdouble.i32 // SPIRV: [[LOAD:%.*]] = load double, ptr [[VALD]].addr, align 8 // SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[LOAD]] to <2 x i32> @@ -26,7 +26,7 @@ uint test_scalar(double D) { // CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0 // CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1 // -// SPIRV: define spir_func {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]]) +// SPIRV: define hidden spir_func {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]]) // SPIRV-NOT: @llvm.dx.splitdouble.i32 // SPIRV: [[LOAD:%.*]] = load <1 x double>, ptr [[VALD]].addr, align 8 // SPIRV-NEXT: [[TRUNC:%.*]] = extractelement <1 x double> [[LOAD]], i64 0 @@ -44,7 +44,7 @@ uint1 test_double1(double1 D) { // CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 0 // CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 1 // -// SPIRV: define spir_func {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]]) +// SPIRV: define hidden spir_func {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]]) // SPIRV-NOT: @llvm.dx.splitdouble.i32 // SPIRV: [[LOAD:%.*]] = load <2 x double>, ptr [[VALD]].addr, align 16 // SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[LOAD]] to <4 x i32> @@ -61,7 +61,7 @@ uint2 test_vector2(double2 D) { // CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 0 // CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 1 // -// SPIRV: define spir_func {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]]) +// SPIRV: define hidden spir_func {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]]) // SPIRV-NOT: @llvm.dx.splitdouble.i32 // SPIRV: [[LOAD:%.*]] = load <3 x double>, ptr [[VALD]].addr, align 32 // SPIRV-NEXT: [[CAST1:%.*]] = bitcast <3 x double> [[LOAD]] to <6 x i32> @@ -78,7 +78,7 @@ uint3 test_vector3(double3 D) { // CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 0 // CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 1 // -// SPIRV: define spir_func {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]]) +// SPIRV: define hidden spir_func {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]]) // SPIRV-NOT: @llvm.dx.splitdouble.i32 // SPIRV: [[LOAD:%.*]] = load <4 x double>, ptr [[VALD]].addr, align 32 // SPIRV-NEXT: [[CAST1:%.*]] = bitcast <4 x double> [[LOAD]] to <8 x i32> diff --git a/clang/test/CodeGenHLSL/builtins/sqrt-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/sqrt-overloads.hlsl index 48b74c9db5c6..d4de244f38b3 100644 --- a/clang/test/CodeGenHLSL/builtins/sqrt-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/sqrt-overloads.hlsl @@ -2,87 +2,87 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sqrt_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sqrt_double // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_double(double p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_double2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_double2(double2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_double3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_double3(double3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_double4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_double4(double4 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sqrt_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sqrt_int // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_int(int p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_int2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_int2(int2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_int3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_int3(int3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_int4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_int4(int4 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sqrt_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sqrt_uint // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_uint(uint p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_uint2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_uint2(uint2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_uint3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_uint3(uint3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_uint4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_uint4(uint4 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sqrt_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sqrt_int64_t // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_int64_t(int64_t p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_int64_t2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_int64_t2(int64_t2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_int64_t3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_int64_t3(int64_t3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_int64_t4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_int64_t4(int64_t4 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_sqrt_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_sqrt_uint64_t // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_uint64_t(uint64_t p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_sqrt_uint64_t2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_uint64_t2(uint64_t2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_sqrt_uint64_t3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_uint64_t3(uint64_t3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_sqrt_uint64_t4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_uint64_t4(uint64_t4 p0) { return sqrt(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/sqrt.hlsl b/clang/test/CodeGenHLSL/builtins/sqrt.hlsl index 94d966f0bef8..31839f6bc177 100644 --- a/clang/test/CodeGenHLSL/builtins/sqrt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/sqrt.hlsl @@ -5,48 +5,48 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z14test_sqrt_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z14test_sqrt_half // NATIVE_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn half @llvm.sqrt.f16( // NATIVE_HALF: ret half %{{.*}} -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z14test_sqrt_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z14test_sqrt_half // NO_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // NO_HALF: ret float %{{.*}} half test_sqrt_half(half p0) { return sqrt(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z15test_sqrt_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z15test_sqrt_half2 // NATIVE_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.sqrt.v2f16 // NATIVE_HALF: ret <2 x half> %{{.*}} -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z15test_sqrt_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z15test_sqrt_half2 // NO_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32( // NO_HALF: ret <2 x float> %{{.*}} half2 test_sqrt_half2(half2 p0) { return sqrt(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z15test_sqrt_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z15test_sqrt_half3 // NATIVE_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.sqrt.v3f16 // NATIVE_HALF: ret <3 x half> %{{.*}} -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z15test_sqrt_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z15test_sqrt_half3 // NO_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32( // NO_HALF: ret <3 x float> %{{.*}} half3 test_sqrt_half3(half3 p0) { return sqrt(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z15test_sqrt_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z15test_sqrt_half4 // NATIVE_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.sqrt.v4f16 // NATIVE_HALF: ret <4 x half> %{{.*}} -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z15test_sqrt_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z15test_sqrt_half4 // NO_HALF: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32( // NO_HALF: ret <4 x float> %{{.*}} half4 test_sqrt_half4(half4 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z15test_sqrt_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_sqrt_float // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn float @llvm.sqrt.f32( // CHECK: ret float %{{.*}} float test_sqrt_float(float p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_sqrt_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_sqrt_float2 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.sqrt.v2f32 // CHECK: ret <2 x float> %{{.*}} float2 test_sqrt_float2(float2 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_sqrt_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_sqrt_float3 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.sqrt.v3f32 // CHECK: ret <3 x float> %{{.*}} float3 test_sqrt_float3(float3 p0) { return sqrt(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_sqrt_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_sqrt_float4 // CHECK: %{{.*}} = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.sqrt.v4f32 // CHECK: ret <4 x float> %{{.*}} float4 test_sqrt_float4(float4 p0) { return sqrt(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/step-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/step-overloads.hlsl index d3b979254391..f55a8f8aff92 100644 --- a/clang/test/CodeGenHLSL/builtins/step-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/step-overloads.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // CHECK: define [[FNATTRS]] float @ // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].step.f32(float diff --git a/clang/test/CodeGenHLSL/builtins/step.hlsl b/clang/test/CodeGenHLSL/builtins/step.hlsl index 49d09e5c6fe6..be0ffbd79464 100644 --- a/clang/test/CodeGenHLSL/builtins/step.hlsl +++ b/clang/test/CodeGenHLSL/builtins/step.hlsl @@ -2,20 +2,20 @@ // RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="noundef nofpclass(nan inf)" -DTARGET=dx +// RUN: -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,NATIVE_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ // RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \ -// RUN: -DFNATTRS="spir_func noundef nofpclass(nan inf)" -DTARGET=spv +// RUN: -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv // NATIVE_HALF: define [[FNATTRS]] half @ // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].step.f16(half diff --git a/clang/test/CodeGenHLSL/builtins/trunc-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/trunc-overloads.hlsl index d913aabfb406..51eb20c58e40 100644 --- a/clang/test/CodeGenHLSL/builtins/trunc-overloads.hlsl +++ b/clang/test/CodeGenHLSL/builtins/trunc-overloads.hlsl @@ -2,82 +2,82 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_trunc_double +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_trunc_double // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_double(double p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_double2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_double2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_double2(double2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_double3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_double3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_double3(double3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_double4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_double4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_double4(double4 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_trunc_int +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_trunc_int // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_int(int p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_int2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_int2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_int2(int2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_int3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_int3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_int3(int3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_int4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_int4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_int4(int4 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_trunc_uint +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_trunc_uint // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_uint(uint p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_uint2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_uint2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_uint2(uint2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_uint3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_uint3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_uint3(uint3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_uint4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_uint4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_uint4(uint4 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_trunc_int64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_trunc_int64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_int64_t(int64_t p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_int64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_int64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_int64_t2(int64_t2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_int64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_int64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_int64_t3(int64_t3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_int64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_int64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_int64_t4(int64_t4 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float {{.*}}test_trunc_uint64_t +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float {{.*}}test_trunc_uint64_t // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_uint64_t(uint64_t p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_uint64_t2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> {{.*}}test_trunc_uint64_t2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_uint64_t2(uint64_t2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_uint64_t3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> {{.*}}test_trunc_uint64_t3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_uint64_t3(uint64_t3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_uint64_t4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> {{.*}}test_trunc_uint64_t4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_uint64_t4(uint64_t4 p0) { return trunc(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/trunc.hlsl b/clang/test/CodeGenHLSL/builtins/trunc.hlsl index 26de5bf94c3c..c1c6ee4119f0 100644 --- a/clang/test/CodeGenHLSL/builtins/trunc.hlsl +++ b/clang/test/CodeGenHLSL/builtins/trunc.hlsl @@ -5,42 +5,42 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,NO_HALF -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) half @_Z15test_trunc_half +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) half @_Z15test_trunc_half // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.trunc.f16( -// NO_HALF-LABEL: define noundef nofpclass(nan inf) float @_Z15test_trunc_half +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) float @_Z15test_trunc_half // NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( half test_trunc_half(half p0) { return trunc(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <2 x half> @_Z16test_trunc_half2 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x half> @_Z16test_trunc_half2 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.trunc.v2f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z16test_trunc_half2 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z16test_trunc_half2 // NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32( half2 test_trunc_half2(half2 p0) { return trunc(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <3 x half> @_Z16test_trunc_half3 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x half> @_Z16test_trunc_half3 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.trunc.v3f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z16test_trunc_half3 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z16test_trunc_half3 // NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32( half3 test_trunc_half3(half3 p0) { return trunc(p0); } -// NATIVE_HALF-LABEL: define noundef nofpclass(nan inf) <4 x half> @_Z16test_trunc_half4 +// NATIVE_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x half> @_Z16test_trunc_half4 // NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.trunc.v4f16 -// NO_HALF-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z16test_trunc_half4 +// NO_HALF-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z16test_trunc_half4 // NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32( half4 test_trunc_half4(half4 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z16test_trunc_float +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z16test_trunc_float // CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.trunc.f32( float test_trunc_float(float p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <2 x float> @_Z17test_trunc_float2 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <2 x float> @_Z17test_trunc_float2 // CHECK: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.trunc.v2f32 float2 test_trunc_float2(float2 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <3 x float> @_Z17test_trunc_float3 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <3 x float> @_Z17test_trunc_float3 // CHECK: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.trunc.v3f32 float3 test_trunc_float3(float3 p0) { return trunc(p0); } -// CHECK-LABEL: define noundef nofpclass(nan inf) <4 x float> @_Z17test_trunc_float4 +// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z17test_trunc_float4 // CHECK: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.trunc.v4f32 float4 test_trunc_float4(float4 p0) { return trunc(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl index 3ab8048146ad..0df3598a3cc3 100644 --- a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ // RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK: define spir_func void @{{.*main.*}}() [[A0:#[0-9]+]] { +// CHECK: define hidden spir_func void @{{.*main.*}}() [[A0:#[0-9]+]] { void main() { // CHECK: entry: // CHECK: %[[CT_ENTRY:[0-9]+]] = call token @llvm.experimental.convergence.entry() diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl index 8e1f2d69e743..9034cae25403 100644 --- a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl @@ -6,8 +6,8 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ // RUN: --check-prefixes=CHECK,CHECK-DXIL -// CHECK-SPIRV: define spir_func noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] { -// CHECK-DXIL: define noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] { +// CHECK-SPIRV: define hidden spir_func noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] { +// CHECK-DXIL: define hidden noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] { // CHECK-SPIRV: %[[CI:[0-9]+]] = call token @llvm.experimental.convergence.entry() // CHECK-SPIRV: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ] // CHECK-DXIL: call i32 @llvm.dx.wave.getlaneindex() diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl index 12b120d0c067..a71b988417f0 100644 --- a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ // RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK: define spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] { +// CHECK: define hidden spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] { // CHECK: %[[C1:[0-9]+]] = call token @llvm.experimental.convergence.entry() // CHECK: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ] uint test_1() { @@ -10,7 +10,7 @@ uint test_1() { // CHECK-DAG: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]] -// CHECK: define spir_func noundef i32 @_Z6test_2v() [[A0]] { +// CHECK: define hidden spir_func noundef i32 @_Z6test_2v() [[A0]] { // CHECK: %[[C2:[0-9]+]] = call token @llvm.experimental.convergence.entry() // CHECK: call spir_func noundef i32 @_Z6test_1v() {{#[0-9]+}} [ "convergencectrl"(token %[[C2]]) ] uint test_2() { diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl index eebf0f682d3d..b58a49b41eb9 100644 --- a/clang/test/CodeGenHLSL/cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer.hlsl @@ -46,14 +46,14 @@ cbuffer CBScalars : register(b1, space5) { // CHECK: @CBScalars.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, // CHECK-SAME: 56, 0, 8, 16, 24, 32, 36, 40, 48)) -// CHECK: @a1 = external addrspace(2) global float, align 4 -// CHECK: @a2 = external addrspace(2) global double, align 8 -// CHECK: @a3 = external addrspace(2) global half, align 2 -// CHECK: @a4 = external addrspace(2) global i64, align 8 -// CHECK: @a5 = external addrspace(2) global i32, align 4 -// CHECK: @a6 = external addrspace(2) global i16, align 2 -// CHECK: @a7 = external addrspace(2) global i32, align 4 -// CHECK: @a8 = external addrspace(2) global i64, align 8 +// CHECK: @a1 = external hidden addrspace(2) global float, align 4 +// CHECK: @a2 = external hidden addrspace(2) global double, align 8 +// CHECK: @a3 = external hidden addrspace(2) global half, align 2 +// CHECK: @a4 = external hidden addrspace(2) global i64, align 8 +// CHECK: @a5 = external hidden addrspace(2) global i32, align 4 +// CHECK: @a6 = external hidden addrspace(2) global i16, align 2 +// CHECK: @a7 = external hidden addrspace(2) global i32, align 4 +// CHECK: @a8 = external hidden addrspace(2) global i64, align 8 // CHECK: @CBScalars.str = private unnamed_addr constant [10 x i8] c"CBScalars\00", align 1 cbuffer CBVectors { @@ -69,13 +69,13 @@ cbuffer CBVectors { // CHECK: @CBVectors.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, // CHECK-SAME: 136, 0, 16, 40, 48, 80, 96, 112)) -// CHECK: @b1 = external addrspace(2) global <3 x float>, align 16 -// CHECK: @b2 = external addrspace(2) global <3 x double>, align 32 -// CHECK: @b3 = external addrspace(2) global <2 x half>, align 4 -// CHECK: @b4 = external addrspace(2) global <3 x i64>, align 32 -// CHECK: @b5 = external addrspace(2) global <4 x i32>, align 16 -// CHECK: @b6 = external addrspace(2) global <3 x i16>, align 8 -// CHECK: @b7 = external addrspace(2) global <3 x i64>, align 32 +// CHECK: @b1 = external hidden addrspace(2) global <3 x float>, align 16 +// CHECK: @b2 = external hidden addrspace(2) global <3 x double>, align 32 +// CHECK: @b3 = external hidden addrspace(2) global <2 x half>, align 4 +// CHECK: @b4 = external hidden addrspace(2) global <3 x i64>, align 32 +// CHECK: @b5 = external hidden addrspace(2) global <4 x i32>, align 16 +// CHECK: @b6 = external hidden addrspace(2) global <3 x i16>, align 8 +// CHECK: @b7 = external hidden addrspace(2) global <3 x i64>, align 32 // CHECK: @CBVectors.str = private unnamed_addr constant [10 x i8] c"CBVectors\00", align 1 cbuffer CBArrays : register(b2) { @@ -91,14 +91,14 @@ cbuffer CBArrays : register(b2) { // CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, // CHECK-SAME: 708, 0, 48, 112, 176, 224, 608, 624, 656)) -// CHECK: @c1 = external addrspace(2) global [3 x float], align 4 -// CHECK: @c2 = external addrspace(2) global [2 x <3 x double>], align 32 -// CHECK: @c3 = external addrspace(2) global [2 x [2 x half]], align 2 -// CHECK: @c4 = external addrspace(2) global [3 x i64], align 8 -// CHECK: @c5 = external addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16 -// CHECK: @c6 = external addrspace(2) global [1 x i16], align 2 -// CHECK: @c7 = external addrspace(2) global [2 x i64], align 8 -// CHECK: @c8 = external addrspace(2) global [4 x i32], align 4 +// CHECK: @c1 = external hidden addrspace(2) global [3 x float], align 4 +// CHECK: @c2 = external hidden addrspace(2) global [2 x <3 x double>], align 32 +// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x half]], align 2 +// CHECK: @c4 = external hidden addrspace(2) global [3 x i64], align 8 +// CHECK: @c5 = external hidden addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16 +// CHECK: @c6 = external hidden addrspace(2) global [1 x i16], align 2 +// CHECK: @c7 = external hidden addrspace(2) global [2 x i64], align 8 +// CHECK: @c8 = external hidden addrspace(2) global [4 x i32], align 4 // CHECK: @CBArrays.str = private unnamed_addr constant [9 x i8] c"CBArrays\00", align 1 typedef uint32_t4 uint32_t8[2]; @@ -112,8 +112,8 @@ cbuffer CBTypedefArray : register(space2) { // CHECK: @CBTypedefArray.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, // CHECK-SAME: 128, 0, 64)) -// CHECK: @t1 = external addrspace(2) global [2 x [2 x <4 x i32>]], align 16 -// CHECK: @t2 = external addrspace(2) global [2 x [2 x <4 x i32>]], align 16 +// CHECK: @t1 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16 +// CHECK: @t2 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16 // CHECK: @CBTypedefArray.str = private unnamed_addr constant [15 x i8] c"CBTypedefArray\00", align 1 struct Empty {}; @@ -137,13 +137,13 @@ struct D { // CHECK: @CBStructs.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, // CHECK-SAME: 246, 0, 16, 32, 64, 144, 238, 240)) -// CHECK: @a = external addrspace(2) global target("dx.Layout", %A, 8, 0), align 1 -// CHECK: @b = external addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 1 -// CHECK: @c = external addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 1 -// CHECK: @array_of_A = external addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 1 -// CHECK: @d = external addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 1 -// CHECK: @e = external addrspace(2) global half, align 2 -// CHECK: @f = external addrspace(2) global <3 x i16>, align 8 +// CHECK: @a = external hidden addrspace(2) global target("dx.Layout", %A, 8, 0), align 1 +// CHECK: @b = external hidden addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 1 +// CHECK: @c = external hidden addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 1 +// CHECK: @array_of_A = external hidden addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 1 +// CHECK: @d = external hidden addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 1 +// CHECK: @e = external hidden addrspace(2) global half, align 2 +// CHECK: @f = external hidden addrspace(2) global <3 x i16>, align 8 // CHECK: @CBStructs.str = private unnamed_addr constant [10 x i8] c"CBStructs\00", align 1 cbuffer CBStructs { @@ -178,10 +178,10 @@ cbuffer CBClasses { // CHECK: @CBClasses.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, // CHECK-SAME: 260, 0, 16, 32, 112)) -// CHECK: @k = external addrspace(2) global target("dx.Layout", %K, 4, 0), align 1 -// CHECK: @l = external addrspace(2) global target("dx.Layout", %L, 8, 0, 4), align 1 -// CHECK: @m = external addrspace(2) global target("dx.Layout", %M, 68, 0), align 1 -// CHECK: @ka = external addrspace(2) global [10 x target("dx.Layout", %K, 4, 0)], align 1 +// CHECK: @k = external hidden addrspace(2) global target("dx.Layout", %K, 4, 0), align 1 +// CHECK: @l = external hidden addrspace(2) global target("dx.Layout", %L, 8, 0, 4), align 1 +// CHECK: @m = external hidden addrspace(2) global target("dx.Layout", %M, 68, 0), align 1 +// CHECK: @ka = external hidden addrspace(2) global [10 x target("dx.Layout", %K, 4, 0)], align 1 // CHECK: @CBClasses.str = private unnamed_addr constant [10 x i8] c"CBClasses\00", align 1 struct Test { @@ -190,16 +190,16 @@ struct Test { // CHECK: @CBMix.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, // CHECK-SAME: 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) -// CHECK: @test = external addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 1 -// CHECK: @f1 = external addrspace(2) global float, align 4 -// CHECK: @f2 = external addrspace(2) global [3 x [2 x <2 x float>]], align 8 -// CHECK: @f3 = external addrspace(2) global float, align 4 -// CHECK: @f4 = external addrspace(2) global target("dx.Layout", %anon, 4, 0), align 1 -// CHECK: @f5 = external addrspace(2) global double, align 8 -// CHECK: @f6 = external addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 1 -// CHECK: @f7 = external addrspace(2) global float, align 4 -// CHECK: @f8 = external addrspace(2) global <1 x double>, align 8 -// CHECK: @f9 = external addrspace(2) global i16, align 2 +// CHECK: @test = external hidden addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 1 +// CHECK: @f1 = external hidden addrspace(2) global float, align 4 +// CHECK: @f2 = external hidden addrspace(2) global [3 x [2 x <2 x float>]], align 8 +// CHECK: @f3 = external hidden addrspace(2) global float, align 4 +// CHECK: @f4 = external hidden addrspace(2) global target("dx.Layout", %anon, 4, 0), align 1 +// CHECK: @f5 = external hidden addrspace(2) global double, align 8 +// CHECK: @f6 = external hidden addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 1 +// CHECK: @f7 = external hidden addrspace(2) global float, align 4 +// CHECK: @f8 = external hidden addrspace(2) global <1 x double>, align 8 +// CHECK: @f9 = external hidden addrspace(2) global i16, align 2 // CHECK: @CBMix.str = private unnamed_addr constant [6 x i8] c"CBMix\00", align 1 cbuffer CBMix { diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl index 4a7e2597dc0f..33f480bf445e 100644 --- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl @@ -8,14 +8,14 @@ // CHECK: %"n0::Foo" = type <{ float }> // CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n1::__cblayout_A", 4, 0)) -// CHECK: @_ZN2n02n11aE = external addrspace(2) global float, align 4 +// CHECK: @_ZN2n02n11aE = external hidden addrspace(2) global float, align 4 // CHECK: @B.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::__cblayout_B", 4, 0)) -// CHECK: @_ZN2n01aE = external addrspace(2) global float, align 4 +// CHECK: @_ZN2n01aE = external hidden addrspace(2) global float, align 4 // CHECK: @C.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n2::__cblayout_C", 20, 0, 16)) -// CHECK: @_ZN2n02n21aE = external addrspace(2) global float, align 4 -// CHECK: external addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 1 +// CHECK: @_ZN2n02n21aE = external hidden addrspace(2) global float, align 4 +// CHECK: external hidden addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 1 namespace n0 { struct Foo { diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl index 0d092f0c36c2..16d22a5b1fdd 100644 --- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl @@ -6,9 +6,9 @@ // CHECK: %__cblayout_CB_1 = type <{ float, <2 x float> }> // CHECK: @CB.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88)) -// CHECK: @a = external addrspace(2) global float, align 4 -// CHECK: @b = external addrspace(2) global double, align 8 -// CHECK: @c = external addrspace(2) global <2 x i32>, align 8 +// CHECK: @a = external hidden addrspace(2) global float, align 4 +// CHECK: @b = external hidden addrspace(2) global double, align 8 +// CHECK: @c = external hidden addrspace(2) global <2 x i32>, align 8 // CHECK: @CB.str = private unnamed_addr constant [3 x i8] c"CB\00", align 1 cbuffer CB : register(b1, space3) { @@ -18,8 +18,8 @@ cbuffer CB : register(b1, space3) { } // CHECK: @CB.cb.1 = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_1, 92, 88, 80)) -// CHECK: @x = external addrspace(2) global float, align 4 -// CHECK: @y = external addrspace(2) global <2 x float>, align 8 +// CHECK: @x = external hidden addrspace(2) global float, align 4 +// CHECK: @y = external hidden addrspace(2) global <2 x float>, align 8 // Missing packoffset annotation will produce a warning. // Element x will be placed after the element y that has an explicit packoffset. diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl index a6034386ac45..cda231d8d2eb 100644 --- a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl @@ -3,7 +3,7 @@ // CHECK: %__cblayout_A = type <{ float }> // CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0)) -// CHECK: @a = external addrspace(2) global float, align 4 +// CHECK: @a = external hidden addrspace(2) global float, align 4 // CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4 // CHECK-NOT: @B.cb diff --git a/clang/test/CodeGenHLSL/convergence/do.while.hlsl b/clang/test/CodeGenHLSL/convergence/do.while.hlsl index 934fe3ea9eb7..9aabbfd54e53 100644 --- a/clang/test/CodeGenHLSL/convergence/do.while.hlsl +++ b/clang/test/CodeGenHLSL/convergence/do.while.hlsl @@ -8,7 +8,7 @@ void test1() { do { } while (cond()); } -// CHECK-LABEL: define spir_func void @_Z5test1v() +// CHECK-LABEL: define hidden spir_func void @_Z5test1v() // CHECK-SAME: [[A0:#[0-9]+]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -22,7 +22,7 @@ void test2() { foo(); } while (cond()); } -// CHECK-LABEL: define spir_func void @_Z5test2v() +// CHECK-LABEL: define hidden spir_func void @_Z5test2v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -38,7 +38,7 @@ void test3() { foo(); } while (cond()); } -// CHECK-LABEL: define spir_func void @_Z5test3v() +// CHECK-LABEL: define hidden spir_func void @_Z5test3v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -57,7 +57,7 @@ void test4() { } } while (cond()); } -// CHECK-LABEL: define spir_func void @_Z5test4v() +// CHECK-LABEL: define hidden spir_func void @_Z5test4v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -78,7 +78,7 @@ void test5() { } } while (cond()); } -// CHECK-LABEL: define spir_func void @_Z5test5v() +// CHECK-LABEL: define hidden spir_func void @_Z5test5v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() diff --git a/clang/test/CodeGenHLSL/convergence/for.hlsl b/clang/test/CodeGenHLSL/convergence/for.hlsl index 363c6a48839b..b7b11e9959ea 100644 --- a/clang/test/CodeGenHLSL/convergence/for.hlsl +++ b/clang/test/CodeGenHLSL/convergence/for.hlsl @@ -10,7 +10,7 @@ void test1() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test1v() +// CHECK-LABEL: define hidden spir_func void @_Z5test1v() // CHECK-SAME: [[A0:#[0-9]+]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -23,7 +23,7 @@ void test2() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test2v() +// CHECK-LABEL: define hidden spir_func void @_Z5test2v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -38,7 +38,7 @@ void test3() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test3v() +// CHECK-LABEL: define hidden spir_func void @_Z5test3v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -52,7 +52,7 @@ void test4() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test4v() +// CHECK-LABEL: define hidden spir_func void @_Z5test4v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -67,7 +67,7 @@ void test5() { for (cond();cond2();foo()) { } } -// CHECK-LABEL: define spir_func void @_Z5test5v() +// CHECK-LABEL: define hidden spir_func void @_Z5test5v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -86,7 +86,7 @@ void test6() { } } } -// CHECK-LABEL: define spir_func void @_Z5test6v() +// CHECK-LABEL: define hidden spir_func void @_Z5test6v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -112,7 +112,7 @@ void test7() { } } } -// CHECK-LABEL: define spir_func void @_Z5test7v() +// CHECK-LABEL: define hidden spir_func void @_Z5test7v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() diff --git a/clang/test/CodeGenHLSL/convergence/while.hlsl b/clang/test/CodeGenHLSL/convergence/while.hlsl index 570b4b133671..32579e863100 100644 --- a/clang/test/CodeGenHLSL/convergence/while.hlsl +++ b/clang/test/CodeGenHLSL/convergence/while.hlsl @@ -8,7 +8,7 @@ void test1() { while (cond()) { } } -// CHECK-LABEL: define spir_func void @_Z5test1v() +// CHECK-LABEL: define hidden spir_func void @_Z5test1v() // CHECK-SAME: [[A0:#[0-9]+]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -21,7 +21,7 @@ void test2() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test2v() +// CHECK-LABEL: define hidden spir_func void @_Z5test2v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -38,7 +38,7 @@ void test3() { foo(); } } -// CHECK-LABEL: define spir_func void @_Z5test3v() +// CHECK-LABEL: define hidden spir_func void @_Z5test3v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -59,7 +59,7 @@ void test4() { } } } -// CHECK-LABEL: define spir_func void @_Z5test4v() +// CHECK-LABEL: define hidden spir_func void @_Z5test4v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -82,7 +82,7 @@ void test5() { } } } -// CHECK-LABEL: define spir_func void @_Z5test5v() +// CHECK-LABEL: define hidden spir_func void @_Z5test5v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() @@ -107,7 +107,7 @@ void test6() { } } } -// CHECK-LABEL: define spir_func void @_Z5test6v() +// CHECK-LABEL: define hidden spir_func void @_Z5test6v() // CHECK-SAME: [[A0]] { // CHECK: entry: // CHECK: [[T0:%[0-9]+]] = call token @llvm.experimental.convergence.entry() diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl index 557913042e88..ad4d92f8afc0 100644 --- a/clang/test/CodeGenHLSL/default_cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl @@ -6,14 +6,14 @@ // CHECK: %__cblayout_S = type <{ float }> // DXIL-DAG: @"$Globals.cb" = global target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 20, 0, 4, 16)) -// DXIL-DAG: @a = external addrspace(2) global float -// DXIL-DAG: @g = external addrspace(2) global float -// DXIL-DAG: @h = external addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4 +// DXIL-DAG: @a = external hidden addrspace(2) global float +// DXIL-DAG: @g = external hidden addrspace(2) global float +// DXIL-DAG: @h = external hidden addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4 // SPIRV-DAG: @"$Globals.cb" = global target("spirv.VulkanBuffer", target("spirv.Layout", %"__cblayout_$Globals", 20, 0, 4, 16), 2, 0) -// SPIRV-DAG: @a = external addrspace(12) global float -// SPIRV-DAG: @g = external addrspace(12) global float -// SPIRV-DAG: @h = external addrspace(12) global target("spirv.Layout", %__cblayout_S, 4, 0), align 8 +// SPIRV-DAG: @a = external hidden addrspace(12) global float +// SPIRV-DAG: @g = external hidden addrspace(12) global float +// SPIRV-DAG: @h = external hidden addrspace(12) global target("spirv.Layout", %__cblayout_S, 4, 0), align 8 struct EmptyStruct { }; diff --git a/clang/test/CodeGenHLSL/default_cbuffer_with_layout.hlsl b/clang/test/CodeGenHLSL/default_cbuffer_with_layout.hlsl index 40e3196649a5..1b2cb0e99aa8 100644 --- a/clang/test/CodeGenHLSL/default_cbuffer_with_layout.hlsl +++ b/clang/test/CodeGenHLSL/default_cbuffer_with_layout.hlsl @@ -4,14 +4,14 @@ // CHECK-SAME: target("dx.Layout", %S, 8, 0) }> // CHECK: %S = type <{ <2 x float> }> -// CHECK-DAG: @b = external addrspace(2) global float, align 4 -// CHECK-DAG: @d = external addrspace(2) global <4 x i32>, align 16 +// CHECK-DAG: @b = external hidden addrspace(2) global float, align 4 +// CHECK-DAG: @d = external hidden addrspace(2) global <4 x i32>, align 16 // CHECK-DAG: @"$Globals.cb" = global target("dx.CBuffer", // CHECK-DAG-SAME: target("dx.Layout", %"__cblayout_$Globals", 144, 120, 16, 32, 64, 128, 112)) -// CHECK-DAG: @a = external addrspace(2) global i32, align 4 -// CHECK-DAG: @c = external addrspace(2) global [4 x double], align 8 -// CHECK-DAG: @e = external addrspace(2) global <4 x float>, align 16 -// CHECK-DAG: @s = external addrspace(2) global target("dx.Layout", %S, 8, 0), align 1 +// CHECK-DAG: @a = external hidden addrspace(2) global i32, align 4 +// CHECK-DAG: @c = external hidden addrspace(2) global [4 x double], align 8 +// CHECK-DAG: @e = external hidden addrspace(2) global <4 x float>, align 16 +// CHECK-DAG: @s = external hidden addrspace(2) global target("dx.Layout", %S, 8, 0), align 1 struct S { float2 v; diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl index 770618ff2e07..e72dbde5188a 100644 --- a/clang/test/CodeGenHLSL/export.hlsl +++ b/clang/test/CodeGenHLSL/export.hlsl @@ -5,17 +5,15 @@ export void f1() { } -// CHECK: define void @_ZN11MyNamespace2f2Ev() [[Attr]] +// CHECK: define void @_ZN11MyNamespace2f2Ev() namespace MyNamespace { export void f2() { } } export { -// CHECK: define void @_Z2f3v() [[Attr]] -// CHECK: define void @_Z2f4v() [[Attr]] +// CHECK: define void @_Z2f3v() +// CHECK: define void @_Z2f4v() void f3() {} void f4() {} -} - -// CHECK: attributes [[Attr]] = { {{.*}} "hlsl.export" {{.*}} } +} \ No newline at end of file diff --git a/clang/test/CodeGenHLSL/group_shared.hlsl b/clang/test/CodeGenHLSL/group_shared.hlsl index a562e75b3488..6498c53752d4 100644 --- a/clang/test/CodeGenHLSL/group_shared.hlsl +++ b/clang/test/CodeGenHLSL/group_shared.hlsl @@ -8,7 +8,7 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s // Make sure groupshared translated into address space 3. -// CHECK:@a = addrspace(3) global [10 x float] +// CHECK:@a = hidden addrspace(3) global [10 x float] groupshared float a[10]; diff --git a/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl b/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl index 12d3eeedb590..60238cbf8eff 100644 --- a/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl +++ b/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl @@ -12,7 +12,7 @@ struct Node { }; // CHECK: Function Attrs:{{.*}}norecurse -// CHECK: define noundef i32 @_Z4FindA100_4Nodej(ptr noundef byval([100 x %struct.Node]) align 1 %SortedTree, i32 noundef %key) [[IntAttr:\#[0-9]+]] +// CHECK: define hidden noundef i32 @_Z4FindA100_4Nodej(ptr noundef byval([100 x %struct.Node]) align 1 %SortedTree, i32 noundef %key) [[Attr:\#[0-9]+]] // CHECK: ret i32 // Find and return value corresponding to key in the SortedTree uint Find(Node SortedTree[MAX], uint key) { @@ -31,7 +31,7 @@ uint Find(Node SortedTree[MAX], uint key) { } // CHECK: Function Attrs:{{.*}}norecurse -// CHECK: define noundef i1 @_Z8InitTreeA100_4NodeN4hlsl8RWBufferIDv4_jEEj(ptr noundef byval([100 x %struct.Node]) align 1 %tree, ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %encodedTree, i32 noundef %maxDepth) [[ExtAttr:\#[0-9]+]] +// CHECK: define noundef i1 @_Z8InitTreeA100_4NodeN4hlsl8RWBufferIDv4_jEEj(ptr noundef byval([100 x %struct.Node]) align 1 %tree, ptr noundef byval(%"class.hlsl::RWBuffer") align 4 %encodedTree, i32 noundef %maxDepth) [[Attr:\#[0-9]+]] // CHECK: ret i1 // Initialize tree with given buffer // Imagine the inout works @@ -52,7 +52,7 @@ RWBuffer gTree; // Mangled entry points are internal // CHECK: Function Attrs:{{.*}}norecurse -// CHECK: define internal void @_Z4mainj(i32 noundef %GI) [[IntAttr]] +// CHECK: define internal void @_Z4mainj(i32 noundef %GI) [[Attr]] // CHECK: ret void // Canonical entry points are external and shader attributed @@ -71,7 +71,7 @@ void main(uint GI : SV_GroupIndex) { // Mangled entry points are internal // CHECK: Function Attrs:{{.*}}norecurse -// CHECK: define internal void @_Z11defaultMainv() [[IntAttr]] +// CHECK: define internal void @_Z11defaultMainv() [[Attr]] // CHECK: ret void // Canonical entry points are external and shader attributed @@ -88,6 +88,5 @@ void defaultMain() { needle = Find(haystack, needle); } -// CHECK: attributes [[IntAttr]] = {{.*}} norecurse -// CHECK: attributes [[ExtAttr]] = {{.*}} norecurse +// CHECK: attributes [[Attr]] = {{.*}} norecurse // CHECK: attributes [[EntryAttr]] = {{.*}} norecurse diff --git a/clang/test/CodeGenHLSL/inline-functions.hlsl b/clang/test/CodeGenHLSL/inline-functions.hlsl index 4748eeee7475..0c7467e2f972 100644 --- a/clang/test/CodeGenHLSL/inline-functions.hlsl +++ b/clang/test/CodeGenHLSL/inline-functions.hlsl @@ -15,7 +15,7 @@ float nums[MAX]; // Verify that all functions have the alwaysinline attribute // NOINLINE: Function Attrs: alwaysinline -// NOINLINE: define void @_Z4swapA100_jjj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %ix1, i32 noundef %ix2) [[IntAttr:\#[0-9]+]] +// NOINLINE: define hidden void @_Z4swapA100_jjj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %ix1, i32 noundef %ix2) [[Attr:\#[0-9]+]] // NOINLINE: ret void // Swap the values of Buf at indices ix1 and ix2 void swap(unsigned Buf[MAX], unsigned ix1, unsigned ix2) { @@ -25,7 +25,7 @@ void swap(unsigned Buf[MAX], unsigned ix1, unsigned ix2) { } // NOINLINE: Function Attrs: alwaysinline -// NOINLINE: define void @_Z10BubbleSortA100_jj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) [[IntAttr]] +// NOINLINE: define hidden void @_Z10BubbleSortA100_jj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) [[Attr]] // NOINLINE: ret void // Inefficiently sort Buf in place void BubbleSort(unsigned Buf[MAX], unsigned size) { @@ -43,7 +43,7 @@ void BubbleSort(unsigned Buf[MAX], unsigned size) { // Note ExtAttr is the inlined export set of attribs // CHECK: Function Attrs: alwaysinline -// CHECK: define noundef i32 @_Z11RemoveDupesA100_jj(ptr {{[a-z_ ]*}}noundef byval([100 x i32]) align 4 {{.*}}%Buf, i32 noundef %size) {{[a-z_ ]*}}[[ExtAttr:\#[0-9]+]] +// CHECK: define noundef i32 @_Z11RemoveDupesA100_jj(ptr {{[a-z_ ]*}}noundef byval([100 x i32]) align 4 {{.*}}%Buf, i32 noundef %size) {{[a-z_ ]*}}[[Attr:\#[0-9]+]] // CHECK: ret i32 // Sort Buf and remove any duplicate values // returns the number of values left @@ -65,9 +65,9 @@ RWBuffer Indices; // The mangled version of main only remains without inlining // because it has internal linkage from the start -// Note main functions get the norecurse attrib, which IntAttr reflects +// Note main functions get the alwaysinline attrib, which Attr reflects // NOINLINE: Function Attrs: alwaysinline -// NOINLINE: define internal void @_Z4mainj(i32 noundef %GI) [[IntAttr]] +// NOINLINE: define internal void @_Z4mainj(i32 noundef %GI) [[Attr]] // NOINLINE: ret void // The unmangled version is not inlined, EntryAttr reflects that @@ -93,9 +93,9 @@ void main(unsigned int GI : SV_GroupIndex) { // The mangled version of main only remains without inlining // because it has internal linkage from the start -// Note main functions get the norecurse attrib, which IntAttr reflects +// Note main functions get the alwaysinline attrib, which Attr reflects // NOINLINE: Function Attrs: alwaysinline -// NOINLINE: define internal void @_Z6main10v() [[IntAttr]] +// NOINLINE: define internal void @_Z6main10v() [[Attr]] // NOINLINE: ret void // The unmangled version is not inlined, EntryAttr reflects that @@ -113,6 +113,5 @@ void main10() { main(10); } -// NOINLINE: attributes [[IntAttr]] = {{.*}} alwaysinline -// CHECK: attributes [[ExtAttr]] = {{.*}} alwaysinline +// CHECK: attributes [[Attr]] = {{.*}} alwaysinline // CHECK: attributes [[EntryAttr]] = {{.*}} noinline diff --git a/clang/test/CodeGenHLSL/no_int_promotion.hlsl b/clang/test/CodeGenHLSL/no_int_promotion.hlsl index 78bff3b13810..b4ffcb477f1b 100644 --- a/clang/test/CodeGenHLSL/no_int_promotion.hlsl +++ b/clang/test/CodeGenHLSL/no_int_promotion.hlsl @@ -10,37 +10,37 @@ int16_t add(int16_t a, int16_t b) { return a + b; } -// CHECK: define noundef <2 x i16> @ +// CHECK: define hidden noundef <2 x i16> @ // CHECK: add <2 x i16> int16_t2 add(int16_t2 a, int16_t2 b) { return a + b; } -// CHECK: define noundef <3 x i16> @ +// CHECK: define hidden noundef <3 x i16> @ // CHECK: add <3 x i16> int16_t3 add(int16_t3 a, int16_t3 b) { return a + b; } -// CHECK: define noundef <4 x i16> @ +// CHECK: define hidden noundef <4 x i16> @ // CHECK: add <4 x i16> int16_t4 add(int16_t4 a, int16_t4 b) { return a + b; } -// CHECK: define noundef i16 @ +// CHECK: define hidden noundef i16 @ // CHECK: add i16 % uint16_t add(uint16_t a, uint16_t b) { return a + b; } -// CHECK: define noundef <2 x i16> @ +// CHECK: define hidden noundef <2 x i16> @ // CHECK: add <2 x i16> uint16_t2 add(uint16_t2 a, uint16_t2 b) { return a + b; } -// CHECK: define noundef <3 x i16> @ +// CHECK: define hidden noundef <3 x i16> @ // CHECK: add <3 x i16> uint16_t3 add(uint16_t3 a, uint16_t3 b) { return a + b; } -// CHECK: define noundef <4 x i16> @ +// CHECK: define hidden noundef <4 x i16> @ // CHECK: add <4 x i16> uint16_t4 add(uint16_t4 a, uint16_t4 b) { return a + b; diff --git a/clang/test/CodeGenHLSL/out-of-line-static.hlsl b/clang/test/CodeGenHLSL/out-of-line-static.hlsl index 8127a6c2ec1e..57f6c123e50e 100644 --- a/clang/test/CodeGenHLSL/out-of-line-static.hlsl +++ b/clang/test/CodeGenHLSL/out-of-line-static.hlsl @@ -6,8 +6,8 @@ struct S { }; int S::Value = 1; -// DXIL: @_ZN1S5ValueE = global i32 1, align 4 -// SPIRV: @_ZN1S5ValueE = addrspace(10) global i32 1, align 4 +// DXIL: @_ZN1S5ValueE = hidden global i32 1, align 4 +// SPIRV: @_ZN1S5ValueE = hidden addrspace(10) global i32 1, align 4 [shader("compute")] [numthreads(1,1,1)] diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl index 58b91fc9264d..bdba38e028ed 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: @sv_position = external thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 +// CHECK: @sv_position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 // CHECK: define void @main() {{.*}} { float4 main(float4 p : SV_Position) { diff --git a/clang/test/CodeGenHLSL/shift-mask.hlsl b/clang/test/CodeGenHLSL/shift-mask.hlsl index 7b3890ae560d..41e05330ed1a 100644 --- a/clang/test/CodeGenHLSL/shift-mask.hlsl +++ b/clang/test/CodeGenHLSL/shift-mask.hlsl @@ -5,7 +5,7 @@ int shl32(int V, int S) { return V << S; } -// CHECK-LABEL: define noundef i32 @_Z5shl32ii(i32 noundef %V, i32 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i32 @_Z5shl32ii(i32 noundef %V, i32 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i32 %{{.*}}, 31 // CHECK-DAG: %{{.*}} = shl i32 %{{.*}}, %[[Masked]] @@ -13,7 +13,7 @@ int shr32(int V, int S) { return V >> S; } -// CHECK-LABEL: define noundef i32 @_Z5shr32ii(i32 noundef %V, i32 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i32 @_Z5shr32ii(i32 noundef %V, i32 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i32 %{{.*}}, 31 // CHECK-DAG: %{{.*}} = ashr i32 %{{.*}}, %[[Masked]] @@ -21,7 +21,7 @@ int64_t shl64(int64_t V, int64_t S) { return V << S; } -// CHECK-LABEL: define noundef i64 @_Z5shl64ll(i64 noundef %V, i64 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i64 @_Z5shl64ll(i64 noundef %V, i64 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i64 %{{.*}}, 63 // CHECK-DAG: %{{.*}} = shl i64 %{{.*}}, %[[Masked]] @@ -29,7 +29,7 @@ int64_t shr64(int64_t V, int64_t S) { return V >> S; } -// CHECK-LABEL: define noundef i64 @_Z5shr64ll(i64 noundef %V, i64 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i64 @_Z5shr64ll(i64 noundef %V, i64 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i64 %{{.*}}, 63 // CHECK-DAG: %{{.*}} = ashr i64 %{{.*}}, %[[Masked]] @@ -37,7 +37,7 @@ uint shlu32(uint V, uint S) { return V << S; } -// CHECK-LABEL: define noundef i32 @_Z6shlu32jj(i32 noundef %V, i32 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i32 @_Z6shlu32jj(i32 noundef %V, i32 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i32 %{{.*}}, 31 // CHECK-DAG: %{{.*}} = shl i32 %{{.*}}, %[[Masked]] @@ -45,7 +45,7 @@ uint shru32(uint V, uint S) { return V >> S; } -// CHECK-LABEL: define noundef i32 @_Z6shru32jj(i32 noundef %V, i32 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i32 @_Z6shru32jj(i32 noundef %V, i32 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i32 %{{.*}}, 31 // CHECK-DAG: %{{.*}} = lshr i32 %{{.*}}, %[[Masked]] @@ -53,7 +53,7 @@ uint64_t shlu64(uint64_t V, uint64_t S) { return V << S; } -// CHECK-LABEL: define noundef i64 @_Z6shlu64mm(i64 noundef %V, i64 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i64 @_Z6shlu64mm(i64 noundef %V, i64 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i64 %{{.*}}, 63 // CHECK-DAG: %{{.*}} = shl i64 %{{.*}}, %[[Masked]] @@ -61,6 +61,6 @@ uint64_t shru64(uint64_t V, uint64_t S) { return V >> S; } -// CHECK-LABEL: define noundef i64 @_Z6shru64mm(i64 noundef %V, i64 noundef %S) #0 { +// CHECK-LABEL: define hidden noundef i64 @_Z6shru64mm(i64 noundef %V, i64 noundef %S) #0 { // CHECK-DAG: %[[Masked:.*]] = and i64 %{{.*}}, 63 // CHECK-DAG: %{{.*}} = lshr i64 %{{.*}}, %[[Masked]] diff --git a/clang/test/CodeGenHLSL/this-assignment-overload.hlsl b/clang/test/CodeGenHLSL/this-assignment-overload.hlsl index a87eb0b38f60..a2df30703877 100644 --- a/clang/test/CodeGenHLSL/this-assignment-overload.hlsl +++ b/clang/test/CodeGenHLSL/this-assignment-overload.hlsl @@ -25,7 +25,7 @@ void main() { } // This test makes a probably safe assumption that HLSL 202x includes operator overloading for assignment operators. -// CHECK: define linkonce_odr noundef i32 @_ZN4Pair8getFirstEv(ptr noundef nonnull align 1 dereferenceable(8) %this) #0 align 2 { +// CHECK: define linkonce_odr hidden noundef i32 @_ZN4Pair8getFirstEv(ptr noundef nonnull align 1 dereferenceable(8) %this) #0 align 2 { // CHECK-NEXT:entry: // CHECK-NEXT:%this.addr = alloca ptr, align 4 // CHECK-NEXT:%Another = alloca %struct.Pair, align 1 @@ -42,7 +42,7 @@ void main() { // CHECK-NEXT:%0 = load i32, ptr %First2, align 1 // CHECK-NEXT:ret i32 %0 -// CHECK: define linkonce_odr noundef i32 @_ZN4Pair9getSecondEv(ptr noundef nonnull align 1 dereferenceable(8) %this) #0 align 2 { +// CHECK: define linkonce_odr hidden noundef i32 @_ZN4Pair9getSecondEv(ptr noundef nonnull align 1 dereferenceable(8) %this) #0 align 2 { // CHECK-NEXT:entry: // CHECK-NEXT:%this.addr = alloca ptr, align 4 // CHECK-NEXT:%agg.tmp = alloca %struct.Pair, align 1 diff --git a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.alignment.hlsl b/clang/test/CodeGenHLSL/vk-features/SpirvType.alignment.hlsl similarity index 100% rename from clang/test/CodeGenHLSL/inline-spirv/SpirvType.alignment.hlsl rename to clang/test/CodeGenHLSL/vk-features/SpirvType.alignment.hlsl diff --git a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl b/clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl similarity index 87% rename from clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl rename to clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl index 5b58e436bbed..7149be0122f4 100644 --- a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl +++ b/clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl @@ -18,12 +18,12 @@ struct S { Int i; }; -// CHECK: define spir_func target("spirv.Type", target("spirv.Image", float, 5, 2, 0, 0, 2, 0), target("spirv.IntegralConstant", i64, 4), 28, 0, 0) @_Z14getArrayBufferu17spirv_type_28_0_0U5_TypeN4hlsl8RWBufferIfEEU6_ConstLm4E(target("spirv.Type", target("spirv.Image", float, 5, 2, 0, 0, 2, 0), target("spirv.IntegralConstant", i64, 4), 28, 0, 0) %v) #0 +// CHECK: define hidden spir_func target("spirv.Type", target("spirv.Image", float, 5, 2, 0, 0, 2, 0), target("spirv.IntegralConstant", i64, 4), 28, 0, 0) @_Z14getArrayBufferu17spirv_type_28_0_0U5_TypeN4hlsl8RWBufferIfEEU6_ConstLm4E(target("spirv.Type", target("spirv.Image", float, 5, 2, 0, 0, 2, 0), target("spirv.IntegralConstant", i64, 4), 28, 0, 0) %v) #0 ArrayBuffer<4> getArrayBuffer(ArrayBuffer<4> v) { return v; } -// CHECK: define spir_func target("spirv.Type", target("spirv.Literal", 32), target("spirv.Literal", 0), 21, 4, 32) @_Z6getIntu18spirv_type_21_4_32U4_LitLi32EU4_LitLi0E(target("spirv.Type", target("spirv.Literal", 32), target("spirv.Literal", 0), 21, 4, 32) %v) #0 +// CHECK: define hidden spir_func target("spirv.Type", target("spirv.Literal", 32), target("spirv.Literal", 0), 21, 4, 32) @_Z6getIntu18spirv_type_21_4_32U4_LitLi32EU4_LitLi0E(target("spirv.Type", target("spirv.Literal", 32), target("spirv.Literal", 0), 21, 4, 32) %v) #0 Int getInt(Int v) { return v; } diff --git a/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl new file mode 100644 index 000000000000..cbc1fa61eae2 --- /dev/null +++ b/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl @@ -0,0 +1,210 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5 +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \ +// RUN: -o - | FileCheck %s + +[[vk::constant_id(1)]] +const bool bool_const = true; + +[[vk::constant_id(1)]] +const short short_const = 4; + +[[vk::constant_id(3)]] +const int int_const = 5; + +[[vk::constant_id(4)]] +const long long long_const = 8; + +[[vk::constant_id(5)]] +const unsigned short ushort_const = 10; + +[[vk::constant_id(6)]] +const unsigned int uint_const = 12; + +[[vk::constant_id(7)]] +const unsigned long long ulong_const = 25; + +[[vk::constant_id(8)]] +const half half_const = 40.4; + +[[vk::constant_id(8)]] +const float float_const = 50.5; + +[[vk::constant_id(9)]] +const double double_const = 100.2; + +enum E { + e0 = 10, + e1 = 20, + e2 = 30 +}; + +[[vk::constant_id(10)]] +const E enum_const = e2; + +[numthreads(1,1,1)] +void main() { + bool b = bool_const; + short s = short_const; + int i = int_const; + long long l = long_const; + unsigned short us = ushort_const; + unsigned int ui = uint_const; + unsigned long long ul = ulong_const; + half h = half_const; + float f = float_const; + double d = double_const; + E e = enum_const; +} +//. +// CHECK: @_ZL10bool_const = internal addrspace(10) global i32 0, align 4 +// CHECK: @_ZL11short_const = internal addrspace(10) global i16 0, align 2 +// CHECK: @_ZL9int_const = internal addrspace(10) global i32 0, align 4 +// CHECK: @_ZL10long_const = internal addrspace(10) global i64 0, align 8 +// CHECK: @_ZL12ushort_const = internal addrspace(10) global i16 0, align 2 +// CHECK: @_ZL10uint_const = internal addrspace(10) global i32 0, align 4 +// CHECK: @_ZL11ulong_const = internal addrspace(10) global i64 0, align 8 +// CHECK: @_ZL10half_const = internal addrspace(10) global float 0.000000e+00, align 4 +// CHECK: @_ZL11float_const = internal addrspace(10) global float 0.000000e+00, align 4 +// CHECK: @_ZL12double_const = internal addrspace(10) global double 0.000000e+00, align 8 +// CHECK: @_ZL10enum_const = internal addrspace(10) global i32 0, align 4 +//. +// CHECK-LABEL: define internal spir_func void @_Z4mainv( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[S:%.*]] = alloca i16, align 2 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[L:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[US:%.*]] = alloca i16, align 2 +// CHECK-NEXT: [[UI:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[UL:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[H:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[F:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[D:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[E:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(10) @_ZL10bool_const, align 4 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i32 [[TMP1]] to i1 +// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[LOADEDV]] to i32 +// CHECK-NEXT: store i32 [[STOREDV]], ptr [[B]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr addrspace(10) @_ZL11short_const, align 2 +// CHECK-NEXT: store i16 [[TMP2]], ptr [[S]], align 2 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(10) @_ZL9int_const, align 4 +// CHECK-NEXT: store i32 [[TMP3]], ptr [[I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr addrspace(10) @_ZL10long_const, align 8 +// CHECK-NEXT: store i64 [[TMP4]], ptr [[L]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr addrspace(10) @_ZL12ushort_const, align 2 +// CHECK-NEXT: store i16 [[TMP5]], ptr [[US]], align 2 +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(10) @_ZL10uint_const, align 4 +// CHECK-NEXT: store i32 [[TMP6]], ptr [[UI]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load i64, ptr addrspace(10) @_ZL11ulong_const, align 8 +// CHECK-NEXT: store i64 [[TMP7]], ptr [[UL]], align 8 +// CHECK-NEXT: [[TMP8:%.*]] = load float, ptr addrspace(10) @_ZL10half_const, align 4 +// CHECK-NEXT: store float [[TMP8]], ptr [[H]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = load float, ptr addrspace(10) @_ZL11float_const, align 4 +// CHECK-NEXT: store float [[TMP9]], ptr [[F]], align 4 +// CHECK-NEXT: [[TMP10:%.*]] = load double, ptr addrspace(10) @_ZL12double_const, align 8 +// CHECK-NEXT: store double [[TMP10]], ptr [[D]], align 8 +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr addrspace(10) @_ZL10enum_const, align 4 +// CHECK-NEXT: store i32 [[TMP11]], ptr [[E]], align 4 +// CHECK-NEXT: ret void +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init( +// CHECK-SAME: ) #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i1 @_Z20__spirv_SpecConstantib(i32 1, i1 true) +// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[TMP1]] to i32 +// CHECK-NEXT: store i32 [[STOREDV]], ptr addrspace(10) @_ZL10bool_const, align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.1( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i16 @_Z20__spirv_SpecConstantis(i32 1, i16 4) +// CHECK-NEXT: store i16 [[TMP1]], ptr addrspace(10) @_ZL11short_const, align 2 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.2( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantii(i32 3, i32 5) +// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL9int_const, align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.3( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i64 @_Z20__spirv_SpecConstantix(i32 4, i64 8) +// CHECK-NEXT: store i64 [[TMP1]], ptr addrspace(10) @_ZL10long_const, align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.4( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i16 @_Z20__spirv_SpecConstantit(i32 5, i16 10) +// CHECK-NEXT: store i16 [[TMP1]], ptr addrspace(10) @_ZL12ushort_const, align 2 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.5( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantij(i32 6, i32 12) +// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL10uint_const, align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.6( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i64 @_Z20__spirv_SpecConstantiy(i32 7, i64 25) +// CHECK-NEXT: store i64 [[TMP1]], ptr addrspace(10) @_ZL11ulong_const, align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.7( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn float @_Z20__spirv_SpecConstantiDh(i32 8, float 0x4044333340000000) +// CHECK-NEXT: store float [[TMP1]], ptr addrspace(10) @_ZL10half_const, align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.8( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn float @_Z20__spirv_SpecConstantif(i32 8, float 5.050000e+01) +// CHECK-NEXT: store float [[TMP1]], ptr addrspace(10) @_ZL11float_const, align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.9( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn double @_Z20__spirv_SpecConstantid(i32 9, double 0x40590CCCC0000000) +// CHECK-NEXT: store double [[TMP1]], ptr addrspace(10) @_ZL12double_const, align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.10( +// CHECK-SAME: ) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantii(i32 10, i32 30) +// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL10enum_const, align 4 +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl index 1cc7963c0e28..157a1818c82f 100644 --- a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl +++ b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl @@ -3,7 +3,7 @@ [[vk::ext_builtin_input(/* WorkgroupId */ 26)]] static const uint3 groupid; -// CHECK: @_ZL7groupid = external local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32>, align 16, !spirv.Decorations [[META0:![0-9]+]] +// CHECK: @_ZL7groupid = external hidden local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32>, align 16, !spirv.Decorations [[META0:![0-9]+]] RWStructuredBuffer output : register(u1, space0); diff --git a/clang/test/CodeGenOpenCL/amdgpu-features.cl b/clang/test/CodeGenOpenCL/amdgpu-features.cl index b94e1e76c7a2..730ed47f0b0c 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-features.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-features.cl @@ -52,6 +52,7 @@ // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1153 -emit-llvm -o - %s | FileCheck --check-prefix=GFX1153 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1200 -emit-llvm -o - %s | FileCheck --check-prefix=GFX1200 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1201 -emit-llvm -o - %s | FileCheck --check-prefix=GFX1201 %s +// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1250 -emit-llvm -o - %s | FileCheck --check-prefix=GFX1250 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1103 -target-feature +wavefrontsize64 -emit-llvm -o - %s | FileCheck --check-prefix=GFX1103-W64 %s @@ -107,6 +108,7 @@ // GFX1153: "target-features"="+16-bit-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot10-insts,+dot12-insts,+dot5-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" // GFX1200: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot10-insts,+dot11-insts,+dot12-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+fp8-conversion-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" // GFX1201: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot10-insts,+dot11-insts,+dot12-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+fp8-conversion-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" +// GFX1250: "target-features"="+16-bit-insts,+ashr-pk-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+bitop3-insts,+ci-insts,+dl-insts,+dot7-insts,+dot8-insts,+dpp,+fp8-conversion-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx1250-insts,+gfx8-insts,+gfx9-insts,+permlane16-swap,+prng-inst,+setprio-inc-wg-inst,+wavefrontsize32" // GFX1103-W64: "target-features"="+16-bit-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot10-insts,+dot12-insts,+dot5-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize64" diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl new file mode 100644 index 000000000000..3709b1ff52f3 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl @@ -0,0 +1,12 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -cl-std=CL2.0 -O0 -triple amdgcn-unknown-unknown -target-cpu gfx1250 -emit-llvm -o - %s | FileCheck %s +// REQUIRES: amdgpu-registered-target + +// CHECK-LABEL: @test_setprio_inc_wg( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @llvm.amdgcn.s.setprio.inc.wg(i16 10) +// CHECK-NEXT: ret void +// +void test_setprio_inc_wg() { + __builtin_amdgcn_s_setprio_inc_wg(10); +} diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib/aarch64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib/aarch64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib/riscv64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib/riscv64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib/x86_64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib/x86_64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib64/aarch64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib64/aarch64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib64/riscv64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib64/riscv64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/lib64/x86_64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/lib64/x86_64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/aarch64-managarm-mlibc/c++/10/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/aarch64-managarm-mlibc/c++/10/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/c++/10/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/c++/10/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/c++/v1/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/c++/v1/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/riscv64-managarm-mlibc/c++/10/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/riscv64-managarm-mlibc/c++/10/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/x86_64-managarm-mlibc/c++/10/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/include/x86_64-managarm-mlibc/c++/10/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/aarch64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/aarch64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbegin.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginS.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginS.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginT.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginT.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbegin.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginS.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginS.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginT.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginT.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbegin.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginS.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginS.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginT.o b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginT.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/riscv64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/riscv64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/x86_64-managarm-mlibc/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib/x86_64-managarm-mlibc/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib64/.keep b/clang/test/Driver/Inputs/basic_managarm_tree/usr/lib64/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/aix-shared-lib-tls-model-opt.c b/clang/test/Driver/aix-shared-lib-tls-model-opt.c index 7acf091f0a04..891caf4ed3fc 100644 --- a/clang/test/Driver/aix-shared-lib-tls-model-opt.c +++ b/clang/test/Driver/aix-shared-lib-tls-model-opt.c @@ -1,5 +1,5 @@ -// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK-AIX,CHECK-AIX-OFF %s -// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK-AIX,CHECK-AIX-OFF %s +// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX %s +// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX %s // RUN: %clang -target powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s // RUN: %clang -target powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s @@ -19,9 +19,8 @@ int test(void) { // CHECK-AIX: test() #0 { // CHECK-AIX: attributes #0 = { -// CHECK-AIX-OFF-SAME: -aix-shared-lib-tls-model-opt // CHECK-AIX-ON-SAME: +aix-shared-lib-tls-model-opt -// CHECK-LINUX-NOT: {{[-+]aix-shared-lib-tls-model-opt}} +// CHECK-LINUX-NOT: {{[+]aix-shared-lib-tls-model-opt}} // CHECK-UNSUPPORTED-TARGET: option '-maix-shared-lib-tls-model-opt' cannot be specified on this target diff --git a/clang/test/Driver/aix-small-local-exec-dynamic-tls.c b/clang/test/Driver/aix-small-local-exec-dynamic-tls.c index 1a0619b58e89..6fc2b8efb4ae 100644 --- a/clang/test/Driver/aix-small-local-exec-dynamic-tls.c +++ b/clang/test/Driver/aix-small-local-exec-dynamic-tls.c @@ -1,37 +1,37 @@ -// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX-DEFAULT %s -// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX-DEFAULT %s -// RUN: %clang -target powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s -// RUN: %clang -target powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s +// RUN: %clang --target=powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s +// RUN: %clang --target=powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s +// RUN: %clang --target=powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s +// RUN: %clang --target=powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s -// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-exec-tls -S -emit-llvm \ +// RUN: %clang --target=powerpc64-unknown-aix -maix-small-local-exec-tls -S -emit-llvm \ // RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALEXEC_TLS -// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls -S -emit-llvm \ +// RUN: %clang --target=powerpc64-unknown-aix -maix-small-local-dynamic-tls -S -emit-llvm \ // RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALDYNAMIC_TLS -// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-exec-tls \ +// RUN: not %clang --target=powerpc-unknown-aix -maix-small-local-exec-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s -// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-exec-tls \ +// RUN: not %clang --target=powerpc64le-unknown-linux-gnu -maix-small-local-exec-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s -// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \ +// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s -// RUN: not %clang -target powerpc64-unknown-aix -maix-small-local-exec-tls \ +// RUN: not %clang --target=powerpc64-unknown-aix -maix-small-local-exec-tls \ // RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s -// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \ +// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \ // RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s -// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-dynamic-tls \ +// RUN: not %clang --target=powerpc-unknown-aix -maix-small-local-dynamic-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s -// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-dynamic-tls \ +// RUN: not %clang --target=powerpc64le-unknown-linux-gnu -maix-small-local-dynamic-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s -// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \ +// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \ // RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s -// RUN: not %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls \ +// RUN: not %clang --target=powerpc64-unknown-aix -maix-small-local-dynamic-tls \ // RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s -// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \ +// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \ // RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s @@ -39,10 +39,9 @@ int test(void) { return 0; } -// CHECK-AIX-DEFAULT: test() #0 { -// CHECK-AIX-DEFAULT: attributes #0 = { -// CHECK-AIX-DEFAULT-SAME: {{-aix-small-local-exec-tls,.*-aix-small-local-dynamic-tls|-aix-small-local-dynamic-tls,.*-aix-small-local-exec-tls}} -// CHECK-LINUX-NOT: {{[-+]aix-small-local-exec-tls,.*[-+]aix-small-local-dynamic-tls|[-+]aix-small-local-dynamic-tls,.*[-+]aix-small-local-exec-tls}} +// CHECK-DEFAULT: test() #0 { +// CHECK-DEFAULT: attributes #0 = { +// CHECK-DEFAULT-NOT: {{[-+]aix-small-local-exec-tls,.*[-+]aix-small-local-dynamic-tls|[-+]aix-small-local-dynamic-tls,.*[-+]aix-small-local-exec-tls}} // CHECK-UNSUPPORTED-AIX32: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target // CHECK-UNSUPPORTED-LINUX: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target diff --git a/clang/test/Driver/amdgpu-macros.cl b/clang/test/Driver/amdgpu-macros.cl index 35dc190761ca..a60593f2ab9e 100644 --- a/clang/test/Driver/amdgpu-macros.cl +++ b/clang/test/Driver/amdgpu-macros.cl @@ -130,6 +130,7 @@ // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1153 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1153 -DFAMILY=GFX11 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1200 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1200 -DFAMILY=GFX12 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1201 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1201 -DFAMILY=GFX12 +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1250 %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=32 -DCPU=gfx1250 -DFAMILY=GFX12 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx9-generic %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx9_generic -DFAMILY=GFX9 // RUN: %clang -E -dM -target amdgcn -mcpu=gfx9-4-generic %s 2>&1 | FileCheck --check-prefixes=ARCH-GCN,FAST_FMAF %s -DWAVEFRONT_SIZE=64 -DCPU=gfx9_4_generic -DFAMILY=GFX9 @@ -177,13 +178,19 @@ // RUN: %clang -E -dM -target amdgcn -mcpu=gfx906 -mcumode \ // RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s // RUN: %clang -E -dM -target amdgcn -mcpu=gfx906 -mno-cumode \ -// RUN: %s 2>&1 | FileCheck --check-prefixes=CUMODE-ON,WARN-CUMODE %s +// RUN: %s 2>&1 | FileCheck -DMCPU=gfx906 --check-prefixes=CUMODE-ON,WARN-CUMODE %s // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 \ // RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 -mcumode \ // RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s // RUN: %clang -E -dM -target amdgcn -mcpu=gfx1030 -mno-cumode \ // RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s -// WARN-CUMODE-DAG: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored] +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1250 \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1250 -mcumode \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s +// RUN: %clang -E -dM -target amdgcn -mcpu=gfx1250 -mno-cumode \ +// RUN: %s 2>&1 | FileCheck -DMCPU=gfx1250 --check-prefixes=CUMODE-ON,WARN-CUMODE %s +// WARN-CUMODE-DAG: warning: ignoring '-mno-cumode' option as it is not currently supported for processor '[[MCPU]]' [-Woption-ignored] // CUMODE-ON-DAG: #define __AMDGCN_CUMODE__ 1 // CUMODE-OFF-DAG: #define __AMDGCN_CUMODE__ 0 diff --git a/clang/test/Driver/amdgpu-mcpu.cl b/clang/test/Driver/amdgpu-mcpu.cl index ad5fd8ebaa6a..6d302e4c59ad 100644 --- a/clang/test/Driver/amdgpu-mcpu.cl +++ b/clang/test/Driver/amdgpu-mcpu.cl @@ -115,6 +115,7 @@ // RUN: %clang -### -target amdgcn -mcpu=gfx1153 %s 2>&1 | FileCheck --check-prefix=GFX1153 %s // RUN: %clang -### -target amdgcn -mcpu=gfx1200 %s 2>&1 | FileCheck --check-prefix=GFX1200 %s // RUN: %clang -### -target amdgcn -mcpu=gfx1201 %s 2>&1 | FileCheck --check-prefix=GFX1201 %s +// RUN: %clang -### -target amdgcn -mcpu=gfx1250 %s 2>&1 | FileCheck --check-prefix=GFX1250 %s // RUN: %clang -### -target amdgcn -mcpu=gfx9-generic %s 2>&1 | FileCheck --check-prefix=GFX9_GENERIC %s // RUN: %clang -### -target amdgcn -mcpu=gfx9-4-generic %s 2>&1 | FileCheck --check-prefix=GFX9_4_GENERIC %s @@ -169,6 +170,7 @@ // GFX1153: "-target-cpu" "gfx1153" // GFX1200: "-target-cpu" "gfx1200" // GFX1201: "-target-cpu" "gfx1201" +// GFX1250: "-target-cpu" "gfx1250" // GFX9_GENERIC: "-target-cpu" "gfx9-generic" // GFX9_4_GENERIC: "-target-cpu" "gfx9-4-generic" diff --git a/clang/test/Driver/android-link.cpp b/clang/test/Driver/android-link.cpp index ab7dae540558..b103263cdd3f 100644 --- a/clang/test/Driver/android-link.cpp +++ b/clang/test/Driver/android-link.cpp @@ -16,6 +16,16 @@ // RUN: FileCheck -check-prefix=CORTEX-A57 < %t %s // RUN: %clang --target=aarch64-none-linux-android \ +// RUN: -mno-fix-cortex-a53-843419 \ +// RUN: -### -v %s 2> %t +// RUN: FileCheck -check-prefix=OVERRIDDEN < %t %s +// +// RUN: %clang -target aarch64-none-linux-android \ +// RUN: -mno-fix-cortex-a53-843419 -mfix-cortex-a53-843419 \ +// RUN: -### -v %s 2> %t +// RUN: FileCheck -check-prefix=OVERRIDDEN2 < %t %s +// +// RUN: %clang -target aarch64-none-linux-android \ // RUN: -### -v %s 2> %t // RUN: FileCheck -check-prefix=MAX-PAGE-SIZE-16KB < %t %s @@ -31,6 +41,8 @@ // GENERIC-ARM: --fix-cortex-a53-843419 // CORTEX-A53: --fix-cortex-a53-843419 // CORTEX-A57-NOT: --fix-cortex-a53-843419 +// OVERRIDDEN-NOT: --fix-cortex-a53-843419 +// OVERRIDDEN2: --fix-cortex-a53-843419 // MAX-PAGE-SIZE-4KB: "-z" "max-page-size=4096" // MAX-PAGE-SIZE-16KB: "-z" "max-page-size=16384" // NO-MAX-PAGE-SIZE-16KB-NOT: "-z" "max-page-size=16384" diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 0535285862b9..eb079895a0a8 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -821,7 +821,11 @@ // ARM64EC_OVERRIDE: warning: /arm64EC has been overridden by specified target: x86_64-pc-windows-msvc; option ignored // RUN: %clang_cl /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWIND -// EPILOGUNWIND: -fwinx64-eh-unwindv2 +// EPILOGUNWIND: -fwinx64-eh-unwindv2=best-effort + +// RUN: %clang_cl /d2epilogunwindrequirev2 /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWINDREQUIREV2 +// RUN: %clang_cl /d2epilogunwindrequirev2 /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWINDREQUIREV2 +// EPILOGUNWINDREQUIREV2: -fwinx64-eh-unwindv2=require // RUN: %clang_cl /funcoverride:override_me1 /funcoverride:override_me2 /c -### -- %s 2>&1 | FileCheck %s --check-prefix=FUNCOVERRIDE // FUNCOVERRIDE: -loader-replaceable-function=override_me1 diff --git a/clang/test/Driver/darwin-invalid-version-range.c b/clang/test/Driver/darwin-invalid-version-range.c new file mode 100644 index 000000000000..84603aec1d2f --- /dev/null +++ b/clang/test/Driver/darwin-invalid-version-range.c @@ -0,0 +1,29 @@ +/// This test validates that the various ways to assign an invalid deployment version are captured and detected. +// REQUIRES: system-darwin && native + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: env SDKROOT=%t/iPhoneOS21.0.sdk not %clang -m64 -c -### %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=SDKROOT + +// RUN: not %clang -isysroot %t/iPhoneOS21.0.sdk -m64 -c -### %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=SYSROOT + +// RUN: not %clang -target arm64-apple-ios21 -c -### %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=TARGET + +// RUN: not %clang -mtargetos=ios21 -arch arm64 -c -### %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=MTARGET + +// RUN: env IPHONEOS_DEPLOYMENT_TARGET=21.0 not %clang -arch arm64 -c -### %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=DEPLOY_VAR + +// SDKROOT: error: invalid version number '21.0' inferred from '{{.*}}.sdk' +// SYSROOT: error: invalid version number '21.0' inferred from '{{.*}}.sdk' +// TARGET: error: invalid version number in '-target arm64-apple-ios21' +// MTARGET: error: invalid version number in '-mtargetos=ios21' +// DEPLOY_VAR: error: invalid version number in 'IPHONEOS_DEPLOYMENT_TARGET=21.0' + +//--- iPhoneOS21.0.sdk/SDKSettings.json +{"Version":"21.0", "MaximumDeploymentTarget": "21.0.99"} diff --git a/clang/test/Driver/extend-variable-liveness.c b/clang/test/Driver/extend-variable-liveness.c index bbfb2ece6f29..99a5409cecce 100644 --- a/clang/test/Driver/extend-variable-liveness.c +++ b/clang/test/Driver/extend-variable-liveness.c @@ -1,7 +1,8 @@ // Tests that -fextend-variable-liveness and its aliases are correctly passed -// by the driver. +// by the driver, and are set by default at -Og. // RUN: %clang -### -c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,DEFAULT +// RUN: %clang -### -Og -c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,ALL // RUN: %clang -fextend-variable-liveness=none -### -c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,NONE // RUN: %clang -fextend-variable-liveness=this -### -c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,THIS // RUN: %clang -fextend-variable-liveness=all -### -c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,ALL diff --git a/clang/test/Driver/fveclib.c b/clang/test/Driver/fveclib.c index 5420555c36a2..c57e9aa7a3cc 100644 --- a/clang/test/Driver/fveclib.c +++ b/clang/test/Driver/fveclib.c @@ -1,6 +1,7 @@ // RUN: %clang -### -c -fveclib=none %s 2>&1 | FileCheck --check-prefix=CHECK-NOLIB %s // RUN: %clang -### -c -fveclib=Accelerate %s 2>&1 | FileCheck --check-prefix=CHECK-ACCELERATE %s // RUN: %clang -### -c --target=x86_64-unknown-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck --check-prefix=CHECK-libmvec %s +// RUN: %clang -### -c --target=aarch64-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck --check-prefix=CHECK-LIBMVEC-AARCH64 %s // RUN: %clang -### -c --target=x86_64-unknown-linux-gnu -fveclib=AMDLIBM %s 2>&1 | FileCheck --check-prefix=CHECK-AMDLIBM %s // RUN: %clang -### -c -fveclib=MASSV %s 2>&1 | FileCheck --check-prefix=CHECK-MASSV %s // RUN: %clang -### -c -fveclib=Darwin_libsystem_m %s 2>&1 | FileCheck --check-prefix=CHECK-DARWIN_LIBSYSTEM_M %s @@ -12,6 +13,7 @@ // CHECK-NOLIB: "-fveclib=none" // CHECK-ACCELERATE: "-fveclib=Accelerate" // CHECK-libmvec: "-fveclib=libmvec" +// CHECK-LIBMVEC-AARCH64: "-fveclib=libmvec" // CHECK-AMDLIBM: "-fveclib=AMDLIBM" // CHECK-MASSV: "-fveclib=MASSV" // CHECK-DARWIN_LIBSYSTEM_M: "-fveclib=Darwin_libsystem_m" @@ -23,7 +25,6 @@ // RUN: not %clang --target=x86 -c -fveclib=SLEEF %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s // RUN: not %clang --target=x86 -c -fveclib=ArmPL %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s -// RUN: not %clang --target=aarch64 -c -fveclib=libmvec %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s // RUN: not %clang --target=aarch64 -c -fveclib=SVML %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s // RUN: not %clang --target=aarch64 -c -fveclib=AMDLIBM %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s // CHECK-ERROR: unsupported option {{.*}} for target @@ -43,6 +44,9 @@ // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fveclib=libmvec -flto %s 2>&1 | FileCheck --check-prefix=CHECK-LTO-LIBMVEC %s // CHECK-LTO-LIBMVEC: "-plugin-opt=-vector-library=LIBMVEC" +// RUN: %clang -### --target=aarch64-linux-gnu -fveclib=libmvec -flto %s 2>&1 | FileCheck --check-prefix=CHECK-LTO-LIBMVEC-AARCH64 %s +// CHECK-LTO-LIBMVEC-AARCH64: "-plugin-opt=-vector-library=LIBMVEC" + // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fveclib=AMDLIBM -flto %s 2>&1 | FileCheck --check-prefix=CHECK-LTO-AMDLIBM %s // CHECK-LTO-AMDLIBM: "-plugin-opt=-vector-library=AMDLIBM" @@ -68,6 +72,10 @@ // CHECK-ERRNO-LIBMVEC: "-fveclib=libmvec" // CHECK-ERRNO-LIBMVEC-SAME: "-fmath-errno" +// RUN: %clang -### --target=aarch64-linux-gnu -fveclib=libmvec %s 2>&1 | FileCheck --check-prefix=CHECK-ERRNO-LIBMVEC-AARCH64 %s +// CHECK-ERRNO-LIBMVEC-AARCH64: "-fveclib=libmvec" +// CHECK-ERRNO-LIBMVEC-AARCH64-SAME: "-fmath-errno" + // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fveclib=AMDLIBM %s 2>&1 | FileCheck --check-prefix=CHECK-ERRNO-AMDLIBM %s // CHECK-ERRNO-AMDLIBM: "-fveclib=AMDLIBM" // CHECK-ERRNO-AMDLIBM-SAME: "-fmath-errno" diff --git a/clang/test/Driver/hip-binding.hip b/clang/test/Driver/hip-binding.hip index 57e57194ec87..d8b3f1e24201 100644 --- a/clang/test/Driver/hip-binding.hip +++ b/clang/test/Driver/hip-binding.hip @@ -93,7 +93,7 @@ // RUN: -nogpulib -nogpuinc -foffload-lto --offload-arch=gfx90a --offload-arch=gfx908 -c %s 2>&1 \ // RUN: | FileCheck -check-prefix=LTO-NO-RDC %s // LTO-NO-RDC: # "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[LTO_908:.+]]" -// LTO-NO-RDC-NEXT: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[LTO_908]]"], output: "[[OBJ_908:.+]]" // LTO-NO-RDC-NEXT: # "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]"], output: "[[LTO_90A:.+]]" -// LTO-NO-RDC-NEXT: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[LTO_90A]]"], output: "[[OBJ_90A:.+]]" -// LTO-NO-RDC-NEXT: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[OBJ_908]]", "[[OBJ_90A]]"], output: "[[HIPFB:.+]]" +// LTO-NO-RDC-NEXT: # "x86_64-unknown-linux-gnu" - "Offload::Packager", inputs: ["[[LTO_908]]", "[[LTO_90A]]"], output: "[[PKG:.+]]" +// LTO-NO-RDC-NEXT: # "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT]]", "[[PKG]]"], output: "[[OBJ:.+]]" +// LTO-NO-RDC-NEXT: # "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[OBJ]]"], output: "hip-binding.o" diff --git a/clang/test/Driver/hip-include-path.hip b/clang/test/Driver/hip-include-path.hip index 5eeee2f5ce0d..3c7384ab9835 100644 --- a/clang/test/Driver/hip-include-path.hip +++ b/clang/test/Driver/hip-include-path.hip @@ -12,6 +12,10 @@ // RUN: -std=c++11 --rocm-path=%S/Inputs/rocm -nogpuinc -nogpulib %s 2>&1 \ // RUN: | FileCheck -check-prefixes=COMMON,CLANG,NOHIP %s +// RUN: %clang -c -### --target=x86_64-unknown-linux-gnu --cuda-gpu-arch=gfx900 \ +// RUN: -std=c++11 --rocm-path=%S/Inputs/rocm --no-offload-inc -nogpulib --offload-inc %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=COMMON,CLANG,HIP %s + // COMMON-LABEL: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CLANG-SAME: "-internal-isystem" "{{[^"]*}}/lib{{[^"]*}}/clang/{{[^"]*}}/include/cuda_wrappers" // NOCLANG-NOT: "{{[^"]*}}/lib{{[^"]*}}/clang/{{[^"]*}}/include/cuda_wrappers" diff --git a/clang/test/Driver/hip-phases.hip b/clang/test/Driver/hip-phases.hip index 5fd2c0216ccc..d8a58b78d6d5 100644 --- a/clang/test/Driver/hip-phases.hip +++ b/clang/test/Driver/hip-phases.hip @@ -8,39 +8,57 @@ // // RUN: %clang -x hip --target=x86_64-unknown-linux-gnu -ccc-print-phases \ // RUN: --no-offload-new-driver --cuda-gpu-arch=gfx803 %s 2>&1 \ -// RUN: | FileCheck -check-prefixes=BIN,NRD,OLD %s +// RUN: | FileCheck -check-prefixes=BIN,OLD,OLDN %s // RUN: %clang -x hip --target=x86_64-unknown-linux-gnu -ccc-print-phases \ // RUN: --offload-new-driver --cuda-gpu-arch=gfx803 %s 2>&1 \ -// RUN: | FileCheck -check-prefixes=BIN,NRD,NEW %s +// RUN: | FileCheck -check-prefixes=BIN,NEW,NEWN %s +// RUN: %clang -x hip --target=x86_64-unknown-linux-gnu -ccc-print-phases \ +// RUN: --offload-new-driver --cuda-gpu-arch=gfx803 -flto -c %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=BIN,NEW,NEWLTO %s // // RUN: %clang -x hip --target=x86_64-unknown-linux-gnu -ccc-print-phases \ // RUN: --no-offload-new-driver --cuda-gpu-arch=gfx803 -fgpu-rdc %s 2>&1 \ -// RUN: | FileCheck -check-prefixes=BIN,RDC %s +// RUN: | FileCheck -check-prefixes=BIN,OLD,OLDR %s +// RUN: %clang -x hip --target=x86_64-unknown-linux-gnu -ccc-print-phases \ +// RUN: --offload-new-driver --cuda-gpu-arch=gfx803 -fgpu-rdc %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=BIN,NEW,NEWR %s // // BIN-DAG: [[P0:[0-9]+]]: input, "{{.*}}hip-phases.hip", [[T:hip]], (host-[[T]]) // BIN-DAG: [[P1:[0-9]+]]: preprocessor, {[[P0]]}, [[T]]-cpp-output, (host-[[T]]) // BIN-DAG: [[P2:[0-9]+]]: compiler, {[[P1]]}, ir, (host-[[T]]) -// RDC-DAG: [[P12:[0-9]+]]: backend, {[[P2]]}, assembler, (host-[[T]]) -// RDC-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) +// OLDR-DAG: [[P12:[0-9]+]]: backend, {[[P2]]}, assembler, (host-[[T]]) +// OLDR-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) // BIN-DAG: [[P3:[0-9]+]]: input, "{{.*}}hip-phases.hip", [[T]], (device-[[T]], [[ARCH:gfx803]]) // BIN-DAG: [[P4:[0-9]+]]: preprocessor, {[[P3]]}, [[T]]-cpp-output, (device-[[T]], [[ARCH]]) // BIN-DAG: [[P5:[0-9]+]]: compiler, {[[P4]]}, ir, (device-[[T]], [[ARCH]]) -// NRD-DAG: [[P6:[0-9]+]]: backend, {[[P5]]}, assembler, (device-[[T]], [[ARCH]]) -// NRD-DAG: [[P7:[0-9]+]]: assembler, {[[P6]]}, object, (device-[[T]], [[ARCH]]) -// RDC-DAG: [[P7:[0-9]+]]: backend, {[[P5]]}, ir, (device-[[T]], [[ARCH]]) -// BIN-DAG: [[P8:[0-9]+]]: linker, {[[P7]]}, image, (device-[[T]], [[ARCH]]) -// BIN-DAG: [[P9:[0-9]+]]: offload, "device-[[T]] (amdgcn-amd-amdhsa:[[ARCH]])" {[[P8]]}, image -// NRD-DAG: [[P10:[0-9]+]]: linker, {[[P9]]}, hip-fatbin, (device-[[T]]) -// RDC-DAG: [[P10:[0-9]+]]: linker, {[[P9]]}, object, (device-[[T]]) +// OLDN-DAG: [[P6:[0-9]+]]: backend, {[[P5]]}, assembler, (device-[[T]], [[ARCH]]) +// NEW-DAG: [[P6:[0-9]+]]: backend, {[[P5]]}, ir, (device-[[T]], [[ARCH]]) +// OLDN-DAG: [[P7:[0-9]+]]: assembler, {[[P6]]}, object, (device-[[T]], [[ARCH]]) +// OLDR-DAG: [[P7:[0-9]+]]: backend, {[[P5]]}, ir, (device-[[T]], [[ARCH]]) +// OLD-DAG: [[P8:[0-9]+]]: linker, {[[P7]]}, image, (device-[[T]], [[ARCH]]) +// OLD-DAG: [[P9:[0-9]+]]: offload, "device-[[T]] (amdgcn-amd-amdhsa:[[ARCH]])" {[[P8]]}, image +// NEW-DAG: [[P9:[0-9]+]]: offload, "device-[[T]] (amdgcn-amd-amdhsa:[[ARCH]])" {[[P6]]}, ir +// OLDN-DAG: [[P10:[0-9]+]]: linker, {[[P9]]}, hip-fatbin, (device-[[T]]) +// NEW-DAG: [[P10:[0-9]+]]: clang-offload-packager, {[[P9]]}, image, (device-[[T]]) +// OLDR-DAG: [[P10:[0-9]+]]: linker, {[[P9]]}, object, (device-[[T]]) -// NRD-DAG: [[P11:[0-9]+]]: offload, "host-[[T]] (x86_64-unknown-linux-gnu)" {[[P2]]}, "device-[[T]] (amdgcn-amd-amdhsa)" {[[P10]]}, ir -// RDC-DAG: [[P11:[0-9]+]]: offload, "device-[[T]] (amdgcn-amd-amdhsa)" {[[P10]]}, object -// NRD-DAG: [[P12:[0-9]+]]: backend, {[[P11]]}, assembler, (host-[[T]]) -// NRD-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) -// OLD-DAG: [[P14:[0-9]+]]: linker, {[[P13]]}, image, (host-[[T]]) -// NEW-DAG: [[P14:[0-9]+]]: clang-linker-wrapper, {[[P13]]}, image, (host-[[T]]) -// RDC-DAG: [[P14:[0-9]+]]: linker, {[[P13]], [[P11]]}, image, (host-[[T]]) +// OLDN-DAG: [[P11:[0-9]+]]: offload, "host-[[T]] (x86_64-unknown-linux-gnu)" {[[P2]]}, "device-[[T]] (amdgcn-amd-amdhsa)" {[[P10]]}, ir +// NEW-DAG: [[P11:[0-9]+]]: offload, "host-[[T]] (x86_64-unknown-linux-gnu)" {[[P2]]}, "device-[[T]] (x86_64-unknown-linux-gnu)" {[[P10]]}, ir +// OLDR-DAG: [[P11:[0-9]+]]: offload, "device-[[T]] (amdgcn-amd-amdhsa)" {[[P10]]}, object +// OLDN-DAG: [[P12:[0-9]+]]: backend, {[[P11]]}, assembler, (host-[[T]]) +// OLDN-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) +// NEWN-DAG: [[P12:[0-9]+]]: backend, {[[P11]]}, assembler, (host-[[T]]) +// NEWN-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) +// NEWLTO-DAG: [[P13:[0-9]+]]: backend, {[[P11]]}, lto-bc, (host-hip) +// NEWR-DAG: [[P12:[0-9]+]]: backend, {[[P11]]}, assembler, (host-[[T]]) +// NEWR-DAG: [[P13:[0-9]+]]: assembler, {[[P12]]}, object, (host-[[T]]) +// OLDN-DAG: [[P14:[0-9]+]]: linker, {[[P13]]}, image, (host-[[T]]) +// NEWN-DAG: [[P14:[0-9]+]]: clang-linker-wrapper, {[[P13]]}, object, (host-[[T]]) +// NEWLTO-DAG: [[P14:[0-9]+]]: clang-linker-wrapper, {[[P13]]}, object, (host-[[T]]) +// OLDR-DAG: [[P14:[0-9]+]]: linker, {[[P13]], [[P11]]}, image, (host-[[T]]) +// NEWR-DAG: [[P14:[0-9]+]]: clang-linker-wrapper, {[[P13]]}, image, (host-[[T]]) +// NEWN-DAG: [[P15:[0-9]+]]: linker, {[[P14]]}, image // // Test single gpu architecture up to the assemble phase. diff --git a/clang/test/Driver/hip-runtime-libs-linux.hip b/clang/test/Driver/hip-runtime-libs-linux.hip index a4cd2733114b..eda87d0aa4b6 100644 --- a/clang/test/Driver/hip-runtime-libs-linux.hip +++ b/clang/test/Driver/hip-runtime-libs-linux.hip @@ -20,6 +20,11 @@ // RUN: --rocm-path=%S/Inputs/rocm %t.o -frtlib-add-rpath 2>&1 \ // RUN: | FileCheck -check-prefixes=ROCM-RPATH %s +// Test that a canonical HIP runtime path is passed to the -rpath flag +// RUN: %clang -### --hip-link --target=x86_64-linux-gnu \ +// RUN: --rocm-path=%S/Inputs/rocm/./bin/../include/../ %t.o -frtlib-add-rpath 2>&1 \ +// RUN: | FileCheck -check-prefixes=ROCM-RPATH-CANONICAL %s + // Test detecting latest /opt/rocm-{release} directory. // RUN: rm -rf %t && mkdir -p %t/opt // RUN: cp -r %S/Inputs/rocm %t/opt/rocm-3.9.0-1234 @@ -55,6 +60,7 @@ // ROCM-PATH: "-L[[HIPRT:.*/Inputs/rocm/lib]]" "-lamdhip64" // ROCM-RPATH: "-L[[HIPRT:.*/Inputs/rocm/lib]]" "-rpath" "[[HIPRT]]" "-lamdhip64" +// ROCM-RPATH-CANONICAL: "-rpath" "{{.*/rocm/lib}}" "-lamdhip64" // ROCM-REL: "-L[[HIPRT:.*/opt/rocm-3.10.0/lib]]" "-lamdhip64" // NOHIPRT-NOT: "-L{{.*/Inputs/rocm/lib}}" // NOHIPRT-NOT: "-rpath" "{{.*/Inputs/rocm/lib}}" diff --git a/clang/test/Driver/hip-thinlto.hip b/clang/test/Driver/hip-thinlto.hip index 4227cd3f2e9f..bcb7d4e6cb52 100644 --- a/clang/test/Driver/hip-thinlto.hip +++ b/clang/test/Driver/hip-thinlto.hip @@ -3,6 +3,7 @@ // CHECK: -plugin-opt=thinlto // CHECK-SAME: -plugin-opt=-force-import-all // CHECK-SAME: -plugin-opt=-avail-extern-to-local +// CHECK-SAME: -plugin-opt=-avail-extern-gv-in-addrspace-to-local=3 int main(int, char *[]) { return 0; } diff --git a/clang/test/Driver/hip-toolchain-no-rdc.hip b/clang/test/Driver/hip-toolchain-no-rdc.hip index 6c69d1d51a26..ddd251b67cc5 100644 --- a/clang/test/Driver/hip-toolchain-no-rdc.hip +++ b/clang/test/Driver/hip-toolchain-no-rdc.hip @@ -7,7 +7,7 @@ // RUN: -fuse-ld=lld -B%S/Inputs/lld -nogpuinc \ // RUN: %S/Inputs/hip_multiple_inputs/a.cu \ // RUN: %S/Inputs/hip_multiple_inputs/b.hip \ -// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,LINK %s +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,LINK,OLD %s // RUN: %clang -### --target=x86_64-linux-gnu -fno-gpu-rdc \ // RUN: -x hip --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 \ @@ -17,7 +17,7 @@ // RUN: -fuse-ld=lld -B%S/Inputs/lld -nogpuinc -c \ // RUN: %S/Inputs/hip_multiple_inputs/a.cu \ // RUN: %S/Inputs/hip_multiple_inputs/b.hip \ -// RUN: 2>&1 | FileCheck -check-prefixes=CHECK %s +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,OLD %s // RUN: %clang -### --target=x86_64-linux-gnu -fno-gpu-rdc \ // RUN: -x hip --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 \ @@ -27,7 +27,7 @@ // RUN: -fuse-ld=lld -B%S/Inputs/lld -nogpuinc --offload-new-driver -c \ // RUN: %S/Inputs/hip_multiple_inputs/a.cu \ // RUN: %S/Inputs/hip_multiple_inputs/b.hip \ -// RUN: 2>&1 | FileCheck -check-prefixes=CHECK %s +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,NEW %s // RUN: touch %t/a.o %t/b.o // RUN: %clang -### --target=x86_64-linux-gnu \ @@ -47,22 +47,23 @@ // CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" -// CHECK-SAME: "-emit-obj" +// OLD-SAME: "-emit-obj" +// NEW-SAME: "-emit-llvm-bc" // CHECK-SAME: {{.*}} "-main-file-name" "a.cu" // CHECK-SAME: "-fcuda-is-device" "-fno-threadsafe-statics" "-mllvm" "-amdgpu-internalize-symbols" // CHECK-SAME: "-fcuda-allow-variadic-functions" "-fvisibility=hidden" // CHECK-SAME: "-fapply-global-visibility-to-externs" // CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" // CHECK-SAME: "-target-cpu" "gfx803" -// CHECK-SAME: {{.*}} "-o" [[OBJ_DEV_A_803:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} "-o" "[[OBJ_DEV_A_803:.*(o|bc)]]" "-x" "hip" // CHECK-SAME: {{.*}} [[A_SRC:".*a.cu"]] // CHECK-NOT: {{".*llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" -// CHECK-SAME: "-o" "[[IMG_DEV_A_803:.*out]]" [[OBJ_DEV_A_803]] +// OLD: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" +// OLD-SAME: "-o" "[[IMG_DEV_A_803:.*out]]" "[[OBJ_DEV_A_803]]" // // Compile device code in a.cu to code object for gfx900. @@ -70,62 +71,71 @@ // CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" -// CHECK-SAME: "-emit-obj" +// CHECK-SAME: "-emit-{{(obj|llvm-bc)}}" // CHECK-SAME: {{.*}} "-main-file-name" "a.cu" // CHECK-SAME: "-fcuda-is-device" "-fno-threadsafe-statics" "-mllvm" "-amdgpu-internalize-symbols" // CHECK-SAME: "-fcuda-allow-variadic-functions" "-fvisibility=hidden" // CHECK-SAME: "-fapply-global-visibility-to-externs" // CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" // CHECK-SAME: "-target-cpu" "gfx900" -// CHECK-SAME: {{.*}} "-o" [[OBJ_DEV_A_900:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} "-o" "[[OBJ_DEV_A_900:.*(o|bc)]]" "-x" "hip" // CHECK-SAME: {{.*}} [[A_SRC]] // CHECK-NOT: {{".*llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" -// CHECK-SAME: "-o" "[[IMG_DEV_A_900:.*out]]" [[OBJ_DEV_A_900]] +// OLD: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" +// OLD-SAME: "-o" "[[IMG_DEV_A_900:.*out]]" "[[OBJ_DEV_A_900]]" // // Bundle and embed device code in host object for a.cu. // -// CHECK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" -// CHECK-SAME: "-bundle-align=4096" -// CHECK-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900" -// CHECK-SAME: "-input={{.*}}" "-input=[[IMG_DEV_A_803]]" "-input=[[IMG_DEV_A_900]]" "-output=[[BUNDLE_A:.*hipfb]]" +// OLD: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" +// OLD-SAME: "-bundle-align=4096" +// OLD-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900" +// OLD-SAME: "-input={{.*}}" "-input=[[IMG_DEV_A_803]]" "-input=[[IMG_DEV_A_900]]" "-output=[[BUNDLE_A:.*hipfb]]" + +// NEW: [[PACKAGER:".*clang-offload-packager"]] "-o" "[[PACKAGE_A:.*.out]]" +// NEW-SAME: "--image=file=[[OBJ_DEV_A_803]],triple=amdgcn-amd-amdhsa,arch=gfx803,kind=hip" +// NEW-SAME: "--image=file=[[OBJ_DEV_A_900]],triple=amdgcn-amd-amdhsa,arch=gfx900,kind=hip" // CHECK: [[CLANG]] "-cc1" "-triple" "x86_64-unknown-linux-gnu" // CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-emit-obj" // CHECK-SAME: {{.*}} "-main-file-name" "a.cu" -// CHECK-SAME: {{.*}} "-fcuda-include-gpubinary" "[[BUNDLE_A]]" -// CHECK-SAME: {{.*}} "-o" [[A_OBJ_HOST:".*o"]] "-x" "hip" +// OLD-SAME: {{.*}} "-fcuda-include-gpubinary" "[[BUNDLE_A]]" +// NEW-SAME: {{.*}} "-fembed-offload-object=[[PACKAGE_A]]" +// OLD-SAME: {{.*}} "-o" [[A_OBJ_HOST:".*o"]] "-x" "hip" +// NEW-SAME: {{.*}} "-o" [[A_OBJ_HOST_TMP:".*o"]] "-x" "hip" // CHECK-SAME: {{.*}} [[A_SRC]] +// NEW: [[WRAPPER:".*clang-linker-wrapper]]" {{.*}}"--host-triple=x86_64-unknown-linux-gnu" +// NEW: "--linker-path={{.*}}" "-o" [[A_OBJ_HOST:".*o"]] [[A_OBJ_HOST_TMP]] "-r" + // // Compile device code in b.hip to code object for gfx803. // // CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" -// CHECK-SAME: "-emit-obj" +// CHECK-SAME: "-emit-{{(obj|llvm-bc)}}" // CHECK-SAME: {{.*}} "-main-file-name" "b.hip" // CHECK-SAME: "-fcuda-is-device" "-fno-threadsafe-statics" "-mllvm" "-amdgpu-internalize-symbols" // CHECK-SAME: "-fcuda-allow-variadic-functions" "-fvisibility=hidden" // CHECK-SAME: "-fapply-global-visibility-to-externs" // CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" // CHECK-SAME: "-target-cpu" "gfx803" -// CHECK-SAME: {{.*}} "-o" [[OBJ_DEV_B_803:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} "-o" "[[OBJ_DEV_B_803:.*(o|bc)]]" "-x" "hip" // CHECK-SAME: {{.*}} [[B_SRC:".*b.hip"]] // CHECK-NOT: {{".*llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" -// CHECK-SAME: "-o" "[[IMG_DEV_B_803:.*out]]" [[OBJ_DEV_B_803]] +// OLD: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" +// OLD-SAME: "-o" "[[IMG_DEV_B_803:.*out]]" "[[OBJ_DEV_B_803]]" // // Compile device code in b.hip to code object for gfx900. @@ -133,40 +143,49 @@ // CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" -// CHECK-SAME: "-emit-obj" +// CHECK-SAME: "-emit-{{(obj|llvm-bc)}}" // CHECK-SAME: {{.*}} "-main-file-name" "b.hip" // CHECK-SAME: "-fcuda-is-device" "-fno-threadsafe-statics" "-mllvm" "-amdgpu-internalize-symbols" // CHECK-SAME: "-fcuda-allow-variadic-functions" "-fvisibility=hidden" // CHECK-SAME: "-fapply-global-visibility-to-externs" // CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" // CHECK-SAME: "-target-cpu" "gfx900" -// CHECK-SAME: {{.*}} "-o" [[OBJ_DEV_B_900:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} "-o" "[[OBJ_DEV_B_900:.*(o|bc)]]" "-x" "hip" // CHECK-SAME: {{.*}} [[B_SRC]] // CHECK-NOT: {{".*llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" -// CHECK-SAME: "-o" "[[IMG_DEV_B_900:.*out]]" [[OBJ_DEV_B_900]] +// OLD: [[LLD]] "-flavor" "gnu" "-m" "elf64_amdgpu" "--no-undefined" "-shared" +// OLD-SAME: "-o" "[[IMG_DEV_B_900:.*out]]" "[[OBJ_DEV_B_900]]" // // Bundle and embed device code in host object for b.hip. // -// CHECK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" -// CHECK-SAME: "-bundle-align=4096" -// CHECK-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900" -// CHECK-SAME: "-input={{.*}}" "-input=[[IMG_DEV_B_803]]" "-input=[[IMG_DEV_B_900]]" "-output=[[BUNDLE_A:.*hipfb]]" +// OLD: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" +// OLD-SAME: "-bundle-align=4096" +// OLD-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900" +// OLD-SAME: "-input={{.*}}" "-input=[[IMG_DEV_B_803]]" "-input=[[IMG_DEV_B_900]]" "-output=[[BUNDLE_B:.*hipfb]]" + +// NEW: [[PACKAGER:".*clang-offload-packager"]] "-o" "[[PACKAGE_B:.*.out]]" +// NEW-SAME: "--image=file=[[OBJ_DEV_B_803]],triple=amdgcn-amd-amdhsa,arch=gfx803,kind=hip" +// NEW-SAME: "--image=file=[[OBJ_DEV_B_900]],triple=amdgcn-amd-amdhsa,arch=gfx900,kind=hip" // CHECK: [[CLANG]] "-cc1" "-triple" "x86_64-unknown-linux-gnu" // CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" // CHECK-SAME: "-emit-obj" // CHECK-SAME: {{.*}} "-main-file-name" "b.hip" -// CHECK-SAME: {{.*}} "-fcuda-include-gpubinary" "[[BUNDLE_A]]" -// CHECK-SAME: {{.*}} "-o" [[B_OBJ_HOST:".*o"]] "-x" "hip" +// OLD-SAME: {{.*}} "-fcuda-include-gpubinary" "[[BUNDLE_B]]" +// NEW-SAME: {{.*}} "-fembed-offload-object=[[PACKAGE_B]]" +// OLD-SAME: {{.*}} "-o" [[B_OBJ_HOST:".*o"]] "-x" "hip" +// NEW-SAME: {{.*}} "-o" [[B_OBJ_HOST_TMP:".*o"]] "-x" "hip" // CHECK-SAME: {{.*}} [[B_SRC]] +// NEW: [[WRAPPER:".*clang-linker-wrapper]]" {{.*}}"--host-triple=x86_64-unknown-linux-gnu" +// NEW: "--linker-path={{.*}}" "-o" [[B_OBJ_HOST:".*o"]] [[B_OBJ_HOST_TMP]] "-r" + // // Link host objects. // diff --git a/clang/test/Driver/ignored-pch.cpp b/clang/test/Driver/ignored-pch.cpp new file mode 100644 index 000000000000..a3597dc0fe0d --- /dev/null +++ b/clang/test/Driver/ignored-pch.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// Create PCH without -ignore-pch. +// RUN: %clang -x c++-header %S/Inputs/pchfile.h -### 2>&1 | FileCheck %s -check-prefix=CHECK-EMIT-PCH +// RUN: %clang -x c++-header %S/Inputs/pchfile.h -o %t/pchfile.h.pch +// RUN: %clang %s -include-pch %t/pchfile.h.pch -### 2>&1 | FileCheck %s -check-prefix=CHECK-INCLUDE-PCH +// RUN: %clang %s -emit-ast -include-pch %t/pchfile.h.pch -### 2>&1 | FileCheck %s -check-prefixes=CHECK-EMIT-PCH,CHECK-INCLUDE-PCH + + +// Create PCH with -ignore-pch. +// RUN: %clang -x c++-header -ignore-pch %S/Inputs/pchfile.h -### 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE-PCH +// RUN: %clang %s -ignore-pch -include-pch %t/pchfile.h.pch -### 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE-PCH +// RUN: %clang %s -ignore-pch -emit-ast -include-pch %t/pchfile.h.pch -### 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE-PCH + +// CHECK-EMIT-PCH: -emit-pch +// CHECK-INCLUDE-PCH: -include-pch +// CHECK-IGNORE-PCH-NOT: -emit-pch +// CHECK-IGNORE-PCH-NOT: -include-pch diff --git a/clang/test/Driver/linker-wrapper.c b/clang/test/Driver/linker-wrapper.c index a7e98e7351d9..80b1a5745a12 100644 --- a/clang/test/Driver/linker-wrapper.c +++ b/clang/test/Driver/linker-wrapper.c @@ -223,6 +223,7 @@ __attribute__((visibility("protected"), used)) int x; // RELOCATABLE-LINK-HIP: clang-offload-bundler{{.*}} -type=o -bundle-align=4096 -targets=host-x86_64-unknown-linux-gnu,hip-amdgcn-amd-amdhsa--gfx90a -input={{/dev/null|NUL}} -input={{.*}} -output={{.*}} // RELOCATABLE-LINK-HIP: /usr/bin/ld.lld{{.*}}-r // RELOCATABLE-LINK-HIP: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading +// RELOCATABLE-LINK-HIP: --rename-section llvm_offload_entries // RUN: clang-offload-packager -o %t.out \ // RUN: --image=file=%t.elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_89 \ diff --git a/clang/test/Driver/managarm.cpp b/clang/test/Driver/managarm.cpp new file mode 100644 index 000000000000..9c3f2d4d722a --- /dev/null +++ b/clang/test/Driver/managarm.cpp @@ -0,0 +1,267 @@ +// UNSUPPORTED: system-windows + +// RUN: %clang -### %s --target=x86_64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform 2>&1 | FileCheck --check-prefix=CHECK-X86-64 %s +// CHECK-X86-64: "-cc1" +// CHECK-X86-64-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-X86-64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-X86-64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/x86_64-managarm-mlibc/c++/10" +// CHECK-X86-64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-X86-64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-X86-64-SAME: "-internal-externc-isystem" +// CHECK-X86-64-SAME: {{^}} "[[SYSROOT]]/usr/include/x86_64-managarm-mlibc" +// CHECK-X86-64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-X86-64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-X86-64: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-X86-64-SAME: "-dynamic-linker" "/lib/x86_64-managarm/ld.so" +// CHECK-X86-64-SAME: "{{.*}}/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbegin.o" +// CHECK-X86-64-SAME: "-L +// CHECK-X86-64-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../lib64" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-X86-64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=x86_64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=libc++ --rtlib=compiler-rt --unwindlib=libunwind 2>&1 | FileCheck --check-prefix=CHECK-X86-64-LIBS %s +// CHECK-X86-64-LIBS: "-cc1" +// CHECK-X86-64-LIBS-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-X86-64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/v1" +// CHECK-X86-64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" +// CHECK-X86-64-LIBS-SAME: "-internal-externc-isystem" +// CHECK-X86-64-LIBS-SAME: {{^}} "[[SYSROOT]]/usr/include/x86_64-managarm-mlibc" +// CHECK-X86-64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-X86-64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-X86-64-LIBS: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-X86-64-LIBS-SAME: "-dynamic-linker" "/lib/x86_64-managarm/ld.so" +// CHECK-X86-64-LIBS-SAME: "{{.*}}/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbegin.o" +// CHECK-X86-64-LIBS-SAME: "-L +// CHECK-X86-64-LIBS-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../lib64" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-X86-64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=x86_64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform -static 2>&1 | FileCheck --check-prefix=CHECK-X86-64-STATIC %s +// CHECK-X86-64-STATIC: "-cc1" +// CHECK-X86-64-STATIC-SAME: "-static-define" +// CHECK-X86-64-STATIC-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/x86_64-managarm-mlibc/c++/10" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-X86-64-STATIC-SAME: "-internal-externc-isystem" +// CHECK-X86-64-STATIC-SAME: {{^}} "[[SYSROOT]]/usr/include/x86_64-managarm-mlibc" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-X86-64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-X86-64-STATIC: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-X86-64-STATIC-SAME: "-static" +// CHECK-X86-64-STATIC-SAME: "{{.*}}/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginT.o" +// CHECK-X86-64-STATIC-SAME: "-L +// CHECK-X86-64-STATIC-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../lib64" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-X86-64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=x86_64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: -shared 2>&1 | FileCheck --check-prefix=CHECK-X86-64-SHARED %s +// CHECK-X86-64-SHARED: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-X86-64-SHARED-SAME: "{{.*}}/usr/lib/gcc/x86_64-managarm-mlibc/10/crtbeginS.o" +// CHECK-X86-64-SHARED-SAME: "-L +// CHECK-X86-64-SHARED-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-managarm-mlibc/10/../../../../lib64" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-managarm-mlibc" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-X86-64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=aarch64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform 2>&1 | FileCheck --check-prefix=CHECK-AARCH64 %s +// CHECK-AARCH64: "-cc1" +// CHECK-AARCH64-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-AARCH64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/aarch64-managarm-mlibc/c++/10" +// CHECK-AARCH64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-AARCH64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-AARCH64-SAME: "-internal-externc-isystem" +// CHECK-AARCH64-SAME: {{^}} "[[SYSROOT]]/usr/include/aarch64-managarm-mlibc" +// CHECK-AARCH64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-AARCH64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-AARCH64: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-SAME: "-m" "aarch64managarm" +// CHECK-AARCH64-SAME: {{^}} "-dynamic-linker" "/lib/aarch64-managarm/ld.so" +// CHECK-AARCH64-SAME: "{{.*}}/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbegin.o" +// CHECK-AARCH64-SAME: {{^}} "-L +// CHECK-AARCH64-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../lib64" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=aarch64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=libc++ --rtlib=compiler-rt --unwindlib=libunwind 2>&1 | FileCheck --check-prefix=CHECK-AARCH64-LIBS %s +// CHECK-AARCH64-LIBS: "-cc1" +// CHECK-AARCH64-LIBS-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/v1" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" +// CHECK-AARCH64-LIBS-SAME: "-internal-externc-isystem" +// CHECK-AARCH64-LIBS-SAME: {{^}} "[[SYSROOT]]/usr/include/aarch64-managarm-mlibc" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-AARCH64-LIBS: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-LIBS-SAME: "-m" "aarch64managarm" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-dynamic-linker" "/lib/aarch64-managarm/ld.so" +// CHECK-AARCH64-LIBS-SAME: "{{.*}}/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbegin.o" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L +// CHECK-AARCH64-LIBS-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../lib64" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-AARCH64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=aarch64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform -static 2>&1 | FileCheck --check-prefix=CHECK-AARCH64-STATIC %s +// CHECK-AARCH64-STATIC: "-cc1" +// CHECK-AARCH64-STATIC-SAME: "-static-define" +// CHECK-AARCH64-STATIC-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/aarch64-managarm-mlibc/c++/10" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-AARCH64-STATIC-SAME: "-internal-externc-isystem" +// CHECK-AARCH64-STATIC-SAME: {{^}} "[[SYSROOT]]/usr/include/aarch64-managarm-mlibc" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-AARCH64-STATIC: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-STATIC-SAME: "-m" "aarch64managarm" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-static" +// CHECK-AARCH64-STATIC-SAME: "{{.*}}/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginT.o" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L +// CHECK-AARCH64-STATIC-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../lib64" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-AARCH64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=aarch64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: -shared 2>&1 | FileCheck --check-prefix=CHECK-AARCH64-SHARED %s +// CHECK-AARCH64-SHARED: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-AARCH64-SHARED-SAME: "-m" "aarch64managarm" +// CHECK-AARCH64-SHARED-SAME: {{^}} "{{.*}}/usr/lib/gcc/aarch64-managarm-mlibc/10/crtbeginS.o" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L +// CHECK-AARCH64-SHARED-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/aarch64-managarm-mlibc/10/../../../../lib64" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/aarch64-managarm-mlibc" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-AARCH64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=riscv64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform 2>&1 | FileCheck --check-prefix=CHECK-RISCV64 %s +// CHECK-RISCV64: "-cc1" +// CHECK-RISCV64-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-RISCV64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/riscv64-managarm-mlibc/c++/10" +// CHECK-RISCV64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-RISCV64-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-RISCV64-SAME: "-internal-externc-isystem" +// CHECK-RISCV64-SAME: {{^}} "[[SYSROOT]]/usr/include/riscv64-managarm-mlibc" +// CHECK-RISCV64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-RISCV64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-RISCV64: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-SAME: "{{.*}}/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbegin.o" +// CHECK-RISCV64-SAME: "-L +// CHECK-RISCV64-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../lib64" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-RISCV64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=riscv64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=libc++ --rtlib=compiler-rt --unwindlib=libunwind 2>&1 | FileCheck --check-prefix=CHECK-RISCV64-LIBS %s +// CHECK-RISCV64-LIBS: "-cc1" +// CHECK-RISCV64-LIBS-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/v1" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" +// CHECK-RISCV64-LIBS-SAME: "-internal-externc-isystem" +// CHECK-RISCV64-LIBS-SAME: {{^}} "[[SYSROOT]]/usr/include/riscv64-managarm-mlibc" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-RISCV64-LIBS: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-LIBS-SAME: "{{.*}}/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbegin.o" +// CHECK-RISCV64-LIBS-SAME: "-L +// CHECK-RISCV64-LIBS-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../lib64" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-RISCV64-LIBS-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=riscv64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: --stdlib=platform -static 2>&1 | FileCheck --check-prefix=CHECK-RISCV64-STATIC %s +// CHECK-RISCV64-STATIC: "-cc1" +// CHECK-RISCV64-STATIC-SAME: "-static-define" +// CHECK-RISCV64-STATIC-SAME: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/c++/10" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/riscv64-managarm-mlibc/c++/10" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../include/c++/10/backward" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-RISCV64-STATIC-SAME: "-internal-externc-isystem" +// CHECK-RISCV64-STATIC-SAME: {{^}} "[[SYSROOT]]/usr/include/riscv64-managarm-mlibc" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-RISCV64-STATIC: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-STATIC-SAME: "-static" +// CHECK-RISCV64-STATIC-SAME: "{{.*}}/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginT.o" +// CHECK-RISCV64-STATIC-SAME: "-L +// CHECK-RISCV64-STATIC-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../lib64" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-RISCV64-STATIC-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -### %s --target=riscv64-unknown-managarm-mlibc --sysroot=%S/Inputs/basic_managarm_tree \ +// RUN: -shared 2>&1 | FileCheck --check-prefix=CHECK-RISCV64-SHARED %s +// CHECK-RISCV64-SHARED: "{{.*}}ld" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-RISCV64-SHARED-SAME: "{{.*}}/usr/lib/gcc/riscv64-managarm-mlibc/10/crtbeginS.o" +// CHECK-RISCV64-SHARED-SAME: "-L +// CHECK-RISCV64-SHARED-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/riscv64-managarm-mlibc/10/../../../../lib64" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/riscv64-managarm-mlibc" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib64" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/lib" +// CHECK-RISCV64-SHARED-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" diff --git a/clang/test/Driver/modules.cpp b/clang/test/Driver/modules.cpp index b0d1f2280d25..088a73230f81 100644 --- a/clang/test/Driver/modules.cpp +++ b/clang/test/Driver/modules.cpp @@ -1,43 +1,48 @@ // RUN: rm -rf %t // RUN: mkdir %t +// RUN: split-file %s %t // Check compiling a module interface to a .pcm file. // -// RUN: %clang -std=c++2a -x c++-module --precompile %s -o %t/module.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE -// RUN: %clang -std=gnu++2a -x c++-module --precompile %s -o %t/module-gnu.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE +// RUN: %clang -std=c++2a -x c++-module --precompile %t/foo.cpp -o %t/foo.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE +// RUN: %clang -std=gnu++2a -x c++-module --precompile %t/foo.cpp -o %t/foo-gnu.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE // // CHECK-PRECOMPILE: -cc1 {{.*}} -emit-module-interface // CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm // CHECK-PRECOMPILE-SAME: -x c++ -// CHECK-PRECOMPILE-SAME: modules.cpp +// CHECK-PRECOMPILE-SAME: foo.cpp // Check compiling a .pcm file to a .o file. // -// RUN: %clang -std=c++2a %t/module.pcm -S -o %t/module.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-COMPILE +// RUN: %clang -std=c++2a %t/foo.pcm -S -o %t/foo.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-COMPILE // // CHECK-COMPILE: -cc1 {{.*}} {{-emit-obj|-S}} -// CHECK-COMPILE-SAME: -o {{.*}}module{{2*}}.pcm.o +// CHECK-COMPILE-SAME: -o {{.*}}foo{{2*}}.pcm.o // CHECK-COMPILE-SAME: -x pcm // CHECK-COMPILE-SAME: {{.*}}.pcm // Check use of a .pcm file in another compilation. // -// RUN: %clang -std=c++2a -fmodule-file=%t/module.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE -// RUN: %clang -std=c++20 -fmodule-file=%t/module.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE -// RUN: %clang -std=gnu++20 -fmodule-file=%t/module-gnu.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE +// RUN: %clang -std=c++2a -fmodule-file=foo=%t/foo.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE +// RUN: %clang -std=c++20 -fmodule-file=foo=%t/foo.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE +// RUN: %clang -std=gnu++20 -fmodule-file=foo=%t/foo-gnu.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE // // CHECK-USE: -cc1 {{.*}} {{-emit-obj|-S}} -// CHECK-USE-SAME: -fmodule-file={{.*}}.pcm +// CHECK-USE-SAME: -fmodule-file=foo={{.*}}.pcm // CHECK-USE-SAME: -o {{.*}}.{{o|s}}{{"?}} {{.*}}-x c++ -// CHECK-USE-SAME: modules.cpp +// CHECK-USE-SAME: foo_impl.cpp // Check combining precompile and compile steps works. // -// RUN: %clang -std=c++2a -x c++-module %s -S -o %t/module2.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE +// RUN: %clang -std=c++2a -x c++-module %t/foo.cpp -S -o %t/foo2.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE // Check that .cppm is treated as a module implicitly. // -// RUN: cp %s %t/module.cppm -// RUN: %clang -std=c++2a --precompile %t/module.cppm -o %t/module.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE +// RUN: cp %t/foo.cpp %t/foo.cppm +// RUN: %clang -std=c++2a --precompile %t/foo.cppm -o %t/foo.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE +//--- foo.cpp export module foo; + +//--- foo_impl.cpp +module foo; diff --git a/clang/test/Driver/openmp-offload-gpu.c b/clang/test/Driver/openmp-offload-gpu.c index f67c2173cb14..2af3e2da3b21 100644 --- a/clang/test/Driver/openmp-offload-gpu.c +++ b/clang/test/Driver/openmp-offload-gpu.c @@ -388,6 +388,7 @@ // THINLTO-GFX906: --device-compiler=amdgcn-amd-amdhsa=-flto=thin // THINLTO-GFX906-SAME: --device-linker=amdgcn-amd-amdhsa=-plugin-opt=-force-import-all // THINLTO-GFX906-SAME: --device-linker=amdgcn-amd-amdhsa=-plugin-opt=-avail-extern-to-local +// THINLTO-GFX906-SAME: --device-linker=amdgcn-amd-amdhsa=-plugin-opt=-avail-extern-gv-in-addrspace-to-local=3 // THINLTO-GFX906-SAME: --device-linker=amdgcn-amd-amdhsa=-plugin-opt=-amdgpu-internalize-symbols // // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp \ diff --git a/clang/test/Driver/ppc-crbits.cpp b/clang/test/Driver/ppc-crbits.cpp index 3ed56308cb52..62893d3d0e87 100644 --- a/clang/test/Driver/ppc-crbits.cpp +++ b/clang/test/Driver/ppc-crbits.cpp @@ -64,8 +64,6 @@ // RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -mno-crbits \ // RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS -// RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -emit-llvm \ -// RUN: -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS // RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -mcrbits \ // RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-CRBITS // RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -mno-crbits \ @@ -92,8 +90,6 @@ // RUN: %clang -target powerpc-ibm-aix -mcpu=pwr8 -mno-crbits \ // RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS -// RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -emit-llvm \ -// RUN: -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS // RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -mcrbits \ // RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-CRBITS // RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -mno-crbits \ diff --git a/clang/test/Driver/ppc-isa-features.cpp b/clang/test/Driver/ppc-isa-features.cpp index 92c5bc82f72b..35dbfbcdf569 100644 --- a/clang/test/Driver/ppc-isa-features.cpp +++ b/clang/test/Driver/ppc-isa-features.cpp @@ -5,20 +5,20 @@ // RUN: %clang -target powerpc64-unknown-aix -mcpu=pwr9 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-PWR9 // RUN: %clang -target powerpc-unknown-aix -mcpu=pwr10 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-PWR10 -// CHECK-PWR6: -isa-v206-instructions -// CHECK-PWR6: -isa-v207-instructions -// CHECK-PWR6: -isa-v30-instructions +// CHECK-PWR6-NOT: isa-v206-instructions +// CHECK-PWR6-NOT: isa-v207-instructions +// CHECK-PWR6-NOT: isa-v30-instructions -// CHECK-A2: +isa-v206-instructions -// CHECK-A2: -isa-v207-instructions -// CHECK-A2: -isa-v30-instructions +// CHECK-A2: +isa-v206-instructions +// CHECK-A2-NOT: isa-v207-instructions +// CHECK-A2-NOT: isa-v30-instructions -// CHECK-PWR7: +isa-v206-instructions -// CHECK-PWR7: -isa-v207-instructions -// CHECK-PWR7: -isa-v30-instructions +// CHECK-PWR7: +isa-v206-instructions +// CHECK-PWR7-NOT: isa-v207-instructions +// CHECK-PWR7-NOT: isa-v30-instructions -// CHECK-PWR8: +isa-v207-instructions -// CHECK-PWR8: -isa-v30-instructions +// CHECK-PWR8: +isa-v207-instructions +// CHECK-PWR8-NOT: isa-v30-instructions // CHECK-PWR9: +isa-v207-instructions // CHECK-PWR9: +isa-v30-instructions diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-a25.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-a25.c index d8b3848d8452..cfb4d0ed58d1 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-a25.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-a25.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -19,12 +18,8 @@ // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) // CHECK-NEXT: zcf 1.0 'Zcf' (Compressed Single-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbc 1.0 'Zbc' (Carry-Less Multiplication) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_zba1p0_zbb1p0_zbc1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-a45.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-a45.c index a0a1c3591140..3c3c554dffc5 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-a45.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-a45.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -19,11 +18,8 @@ // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) // CHECK-NEXT: zcf 1.0 'Zcf' (Compressed Single-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_zba1p0_zbb1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-ax25.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-ax25.c index 3f933ecd8ac8..70100a0a8df1 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-ax25.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-ax25.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -18,12 +17,8 @@ // CHECK-NEXT: zalrsc 1.0 'Zalrsc' (Load-Reserved/Store-Conditional) // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbc 1.0 'Zbc' (Carry-Less Multiplication) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zba1p0_zbb1p0_zbc1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-ax45.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-ax45.c index 6460d701411b..d2b1a32e321e 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-ax45.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-ax45.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -18,11 +17,8 @@ // CHECK-NEXT: zalrsc 1.0 'Zalrsc' (Load-Reserved/Store-Conditional) // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zba1p0_zbb1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-n45.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-n45.c index 4d9c514b756e..1a2c30bfc7a2 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-n45.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-n45.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -19,11 +18,8 @@ // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) // CHECK-NEXT: zcf 1.0 'Zcf' (Compressed Single-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_zba1p0_zbb1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zcf1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-enabled-extensions/riscv-andes-nx45.c b/clang/test/Driver/print-enabled-extensions/riscv-andes-nx45.c index 5eaada3f9e16..50c38da3bd03 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-andes-nx45.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-andes-nx45.c @@ -10,7 +10,6 @@ // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) // CHECK-NEXT: d 2.2 'D' (Double-Precision Floating-Point) // CHECK-NEXT: c 2.0 'C' (Compressed Instructions) -// CHECK-NEXT: b 1.0 'B' (the collection of the Zba, Zbb, Zbs extensions) // CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zmmul 1.0 'Zmmul' (Integer Multiplication) @@ -18,11 +17,8 @@ // CHECK-NEXT: zalrsc 1.0 'Zalrsc' (Load-Reserved/Store-Conditional) // CHECK-NEXT: zca 1.0 'Zca' (part of the C extension, excluding compressed floating point loads/stores) // CHECK-NEXT: zcd 1.0 'Zcd' (Compressed Double-Precision Floating-Point Instructions) -// CHECK-NEXT: zba 1.0 'Zba' (Address Generation Instructions) -// CHECK-NEXT: zbb 1.0 'Zbb' (Basic Bit-Manipulation) -// CHECK-NEXT: zbs 1.0 'Zbs' (Single-Bit Instructions) // CHECK-NEXT: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) // CHECK-EMPTY: // CHECK-NEXT: Experimental extensions // CHECK-EMPTY: -// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_b1p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_zba1p0_zbb1p0_zbs1p0_xandesperf5p0 +// CHECK-NEXT: ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0_xandesperf5p0 diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index 95464f06378e..5008c2b7f789 100644 --- a/clang/test/Driver/print-supported-extensions-riscv.c +++ b/clang/test/Driver/print-supported-extensions-riscv.c @@ -159,6 +159,7 @@ // 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: xandesperf 5.0 'XAndesPerf' (Andes Performance Extension) +// CHECK-NEXT: xandesvbfhcvt 5.0 'XAndesVBFHCvt' (Andes Vector BFLOAT16 Conversion Extension) // CHECK-NEXT: xandesvdot 5.0 'XAndesVDot' (Andes Vector Dot Product Extension) // CHECK-NEXT: xandesvpackfph 5.0 'XAndesVPackFPH' (Andes Vector Packed FP16 Extension) // CHECK-NEXT: xcvalu 1.0 'XCValu' (CORE-V ALU Operations) @@ -213,7 +214,7 @@ // CHECK-NEXT: smctr 1.0 'Smctr' (Control Transfer Records Machine Level) // 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: xqccmp 0.1 'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves) +// CHECK-NEXT: xqccmp 0.3 'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves) // CHECK-NEXT: xqcia 0.7 'Xqcia' (Qualcomm uC Arithmetic Extension) // CHECK-NEXT: xqciac 0.3 'Xqciac' (Qualcomm uC Load-Store Address Calculation Extension) // CHECK-NEXT: xqcibi 0.2 'Xqcibi' (Qualcomm uC Branch Immediate Extension) @@ -221,14 +222,14 @@ // CHECK-NEXT: xqcicli 0.3 'Xqcicli' (Qualcomm uC Conditional Load Immediate Extension) // CHECK-NEXT: xqcicm 0.2 'Xqcicm' (Qualcomm uC Conditional Move Extension) // CHECK-NEXT: xqcics 0.2 'Xqcics' (Qualcomm uC Conditional Select Extension) -// CHECK-NEXT: xqcicsr 0.3 'Xqcicsr' (Qualcomm uC CSR Extension) -// CHECK-NEXT: xqciint 0.7 'Xqciint' (Qualcomm uC Interrupts Extension) +// CHECK-NEXT: xqcicsr 0.4 'Xqcicsr' (Qualcomm uC CSR Extension) +// CHECK-NEXT: xqciint 0.10 'Xqciint' (Qualcomm uC Interrupts Extension) // CHECK-NEXT: xqciio 0.1 'Xqciio' (Qualcomm uC External Input Output Extension) // CHECK-NEXT: xqcilb 0.2 'Xqcilb' (Qualcomm uC Long Branch Extension) // CHECK-NEXT: xqcili 0.2 'Xqcili' (Qualcomm uC Load Large Immediate Extension) // CHECK-NEXT: xqcilia 0.2 'Xqcilia' (Qualcomm uC Large Immediate Arithmetic Extension) // CHECK-NEXT: xqcilo 0.3 'Xqcilo' (Qualcomm uC Large Offset Load Store Extension) -// CHECK-NEXT: xqcilsm 0.5 'Xqcilsm' (Qualcomm uC Load Store Multiple Extension) +// CHECK-NEXT: xqcilsm 0.6 'Xqcilsm' (Qualcomm uC Load Store Multiple Extension) // CHECK-NEXT: xqcisim 0.2 'Xqcisim' (Qualcomm uC Simulation Hint Extension) // CHECK-NEXT: xqcisls 0.2 'Xqcisls' (Qualcomm uC Scaled Load Store Extension) // CHECK-NEXT: xqcisync 0.3 'Xqcisync' (Qualcomm uC Sync Delay Extension) diff --git a/clang/test/Driver/range.c b/clang/test/Driver/range.c index da5748d7c723..30140f3c208e 100644 --- a/clang/test/Driver/range.c +++ b/clang/test/Driver/range.c @@ -177,14 +177,83 @@ // RUN: %clang -### -target x86_64 -ffast-math -fcomplex-arithmetic=basic -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=BASIC %s -// BASIC: -complex-range=basic -// FULL: -complex-range=full -// PRMTD: -complex-range=promoted -// BASIC-NOT: -complex-range=improved -// CHECK-NOT: -complex-range=basic -// IMPRVD: -complex-range=improved -// IMPRVD-NOT: -complex-range=basic -// CHECK-NOT: -complex-range=improved +// RUN: %clang -### --target=x86_64 -fcx-limited-range -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE,WARN21 %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-cx-limited-range -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### --target=x86_64 -fcx-fortran-rules -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE,WARN22 %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-cx-fortran-rules -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -ffast-math -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### --target=x86_64 -fcomplex-arithmetic=basic -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE,WARN23 %s + +// RUN: %clang -### --target=x86_64 -fcomplex-arithmetic=promoted -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE,WARN24 %s + +// RUN: %clang -### --target=x86_64 -fcomplex-arithmetic=improved -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE,WARN25 %s + +// RUN: %clang -### -Werror --target=x86_64 -fcomplex-arithmetic=full -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -ffp-model=aggressive -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -ffp-model=fast -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -ffp-model=precise -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -ffp-model=strict -fno-fast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=RANGE %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcx-limited-range \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=BASIC %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fno-cx-limited-range \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=FULL %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcx-fortran-rules \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=IMPRVD %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fno-cx-fortran-rules \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=FULL %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -ffast-math \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=BASIC %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcomplex-arithmetic=basic \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=BASIC %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcomplex-arithmetic=promoted \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=PRMTD %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcomplex-arithmetic=improved \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=IMPRVD %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -fcomplex-arithmetic=full \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=FULL %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -ffp-model=aggressive \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=BASIC %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -ffp-model=fast \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=PRMTD %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -ffp-model=precise \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=FULL %s + +// RUN: %clang -### -Werror --target=x86_64 -fno-fast-math -ffp-model=strict \ +// RUN: -c %s 2>&1 | FileCheck --check-prefixes=FULL %s // WARN1: warning: overriding '-fcx-limited-range' option with '-fcx-fortran-rules' [-Woverriding-option] // WARN2: warning: overriding '-fno-cx-limited-range' option with '-fcx-fortran-rules' [-Woverriding-option] @@ -196,5 +265,20 @@ // WARN14: overriding '-complex-range=promoted' option with '-fcx-limited-range' [-Woverriding-option] // WARN17: warning: overriding '-fcomplex-arithmetic=full' option with '-fcomplex-arithmetic=basic' [-Woverriding-option] // WARN20: warning: overriding '-fcx-fortran-rules' option with '-fcx-limited-range' [-Woverriding-option] +// WARN21: warning: overriding '-fcx-limited-range' option with '-fno-fast-math' [-Woverriding-option] +// WARN22: warning: overriding '-fcx-fortran-rules' option with '-fno-fast-math' [-Woverriding-option] +// WARN23: warning: overriding '-fcomplex-arithmetic=basic' option with '-fno-fast-math' [-Woverriding-option] +// WARN24: warning: overriding '-fcomplex-arithmetic=promoted' option with '-fno-fast-math' [-Woverriding-option] +// WARN25: warning: overriding '-fcomplex-arithmetic=improved' option with '-fno-fast-math' [-Woverriding-option] + +// BASIC: -complex-range=basic +// FULL: -complex-range=full +// PRMTD: -complex-range=promoted +// BASIC-NOT: -complex-range=improved +// CHECK-NOT: -complex-range=basic +// IMPRVD: -complex-range=improved +// IMPRVD-NOT: -complex-range=basic +// CHECK-NOT: -complex-range=improved +// RANGE-NOT: -complex-range= // ERR: error: unsupported argument 'foo' to option '-fcomplex-arithmetic=' diff --git a/clang/test/Driver/spirv-amd-toolchain.c b/clang/test/Driver/spirv-amd-toolchain.c new file mode 100644 index 000000000000..c9417400a937 --- /dev/null +++ b/clang/test/Driver/spirv-amd-toolchain.c @@ -0,0 +1,19 @@ +// RUN: %clang -### -ccc-print-phases --target=spirv64-amd-amdhsa %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=PHASES +// PHASES: 0: input, "[[INPUT:.+]]", c +// PHASES: 1: preprocessor, {0}, cpp-output +// PHASES: 2: compiler, {1}, ir +// PHASES: 3: backend, {2}, assembler +// PHASES: 4: assembler, {3}, object +// PHASES: 5: linker, {4}, image + +// RUN: %clang -### -ccc-print-bindings --target=spirv64-amd-amdhsa %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=BINDINGS +// BINDINGS: # "spirv64-amd-amdhsa" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[OUTPUT:.+]]" +// BINDINGS: # "spirv64-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[OUTPUT]]"], output: "a.out" + +// RUN: %clang -### --target=spirv64-amd-amdhsa %s -nogpulib -nogpuinc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=INVOCATION +// INVOCATION: "-cc1" "-triple" "spirv64-amd-amdhsa" {{.*}} "-o" "[[OUTPUT:.+]]" "-x" "c" +// INVOCATION: "{{.*}}llvm-link" "-o" "a.out" "[[OUTPUT]]" +// INVOCATION: "{{.*}}llvm-spirv" "--spirv-max-version=1.6" "--spirv-ext=+all" "--spirv-allow-unknown-intrinsics" "--spirv-lower-const-expr" "--spirv-preserve-auxdata" "--spirv-debug-info-version=nonsemantic-shader-200" "a.out" "-o" "a.out" diff --git a/clang/test/Driver/stack-alignment.c b/clang/test/Driver/stack-alignment.c new file mode 100644 index 000000000000..e1e62c05c32a --- /dev/null +++ b/clang/test/Driver/stack-alignment.c @@ -0,0 +1,11 @@ +// RUN: not %clang -### -mstack-alignment=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK_NEG_1 +// RUN: %clang -### -mstack-alignment=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK_0 +// RUN: %clang -### -mstack-alignment=1 %s 2>&1 | FileCheck %s --check-prefix=CHECK_1 +// RUN: %clang -### -mstack-alignment=4 %s 2>&1 | FileCheck %s --check-prefix=CHECK_4 +// RUN: not %clang -### -mstack-alignment=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK_5 + +// CHECK_NEG_1: error: invalid argument '-1' to -mstack-alignment= +// CHECK_0: -mstack-alignment=0 +// CHECK_1: -mstack-alignment=1 +// CHECK_4: -mstack-alignment=4 +// CHECK_5: error: alignment is not a power of 2 in '-mstack-alignment=5' diff --git a/clang/test/ExtractAPI/objc_instancetype.m b/clang/test/ExtractAPI/objc_instancetype.m index 071ebe440918..dbd47a1f746f 100644 --- a/clang/test/ExtractAPI/objc_instancetype.m +++ b/clang/test/ExtractAPI/objc_instancetype.m @@ -157,6 +157,10 @@ }, "names": { "navigator": [ + { + "kind": "text", + "spelling": "- " + }, { "kind": "identifier", "spelling": "init" @@ -228,6 +232,10 @@ }, "names": { "navigator": [ + { + "kind": "text", + "spelling": "- " + }, { "kind": "identifier", "spelling": "reset" diff --git a/clang/test/FixIt/fixit-punctuator-spelling.cpp b/clang/test/FixIt/fixit-punctuator-spelling.cpp new file mode 100644 index 000000000000..3cba0e7b6459 --- /dev/null +++ b/clang/test/FixIt/fixit-punctuator-spelling.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +void f(int x) { + switch (x) { + case 1 // expected-error {{expected ':' after 'case'}} + break; + } +} +// CHECK: fix-it:"{{.*}}":{6:11-6:11}:":" diff --git a/clang/test/FixIt/fixit-unknown-attributes.cpp b/clang/test/FixIt/fixit-unknown-attributes.cpp new file mode 100644 index 000000000000..7dff510f5ddf --- /dev/null +++ b/clang/test/FixIt/fixit-unknown-attributes.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify %s +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +[[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f1(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:17}:"gnu::deprecated" + +[[gmu::deprecated]] // expected-warning {{unknown attribute 'gmu::deprecated' ignored; did you mean 'gnu::deprecated'?}} +int f2(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:18}:"gnu::deprecated" + +[[gnu::deprected]] // expected-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f3(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:17}:"gnu::deprecated" + +[[deprected]] // expected-warning {{unknown attribute 'deprected' ignored; did you mean 'deprecated'?}} +int f4(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:12}:"deprecated" + +[[using gmu : deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f5(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" +// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:24}:"deprecated" + +[[using gmu : deprecated]] // expected-warning {{unknown attribute 'gmu::deprecated' ignored; did you mean 'gnu::deprecated'?}} +int f6(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" + +[[using gnu : deprected]] // expected-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f7(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:15-[[@LINE-4]]:24}:"deprecated" + +[[using gnu : deprecated, noretyrn]] // expected-warning {{unknown attribute 'gnu::noretyrn' ignored; did you mean 'gnu::noreturn'?}} +void f8(void) { +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:27-[[@LINE-3]]:35}:"noreturn" + +[[using gmu : deprected, noretyrn]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} \ + // expected-warning {{unknown attribute 'gmu::noretyrn' ignored; did you mean 'gnu::noreturn'?}} +void f9(void) { +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" +// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:24}:"deprecated" + +// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:12}:"gnu" +// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:26-[[@LINE-8]]:34}:"noreturn" + +__attribute__((cont, deprected)) // expected-warning {{unknown attribute 'cont' ignored; did you mean 'const'?}} \ + // expected-warning {{unknown attribute 'deprected' ignored; did you mean 'deprecated'?}} +int f10(int) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]:20}:"const" +// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:22-[[@LINE-6]]:31}:"deprecated" + +[[using gnu: noretyrn, address_spaci(0)]] // expected-warning {{unknown attribute 'gnu::noretyrn' ignored; did you mean 'gnu::noreturn'?}} \ + // expected-warning {{unknown attribute 'gnu::address_spaci' ignored}} +void f11(void) { +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:14-[[@LINE-4]]:22}:"noreturn" diff --git a/clang/test/FixIt/typo.cpp b/clang/test/FixIt/typo.cpp deleted file mode 100644 index e489fbbcaa1d..000000000000 --- a/clang/test/FixIt/typo.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: cp %s %t -// RUN: not %clang_cc1 -fixit -x c++ %t -// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t -// RUN: grep test_string %t - -namespace std { - template class basic_string { // expected-note 3{{'basic_string' declared here}} - public: - int find(const char *substr); // expected-note{{'find' declared here}} - static const int npos = -1; // expected-note{{'npos' declared here}} - }; - - typedef basic_string string; // expected-note 2{{'string' declared here}} -} - -namespace otherstd { // expected-note 2{{'otherstd' declared here}} \ - // expected-note{{namespace 'otherstd' defined here}} - using namespace std; -} - -using namespace std; - -other_std::strng str1; // expected-error{{use of undeclared identifier 'other_std'; did you mean 'otherstd'?}} \ -// expected-error{{no type named 'strng' in namespace 'otherstd'; did you mean 'string'?}} -tring str2; // expected-error{{unknown type name 'tring'; did you mean 'string'?}} - -::other_std::string str3; // expected-error{{no member named 'other_std' in the global namespace; did you mean 'otherstd'?}} - -float area(float radius, // expected-note{{'radius' declared here}} - float pi) { - return radious * pi; // expected-error{{did you mean 'radius'?}} -} - -using namespace othestd; // expected-error{{no namespace named 'othestd'; did you mean 'otherstd'?}} -namespace blargh = otherstd; // expected-note 3{{namespace 'blargh' defined here}} -using namespace ::blarg; // expected-error{{no namespace named 'blarg' in the global namespace; did you mean 'blargh'?}} - -namespace wibble = blarg; // expected-error{{no namespace named 'blarg'; did you mean 'blargh'?}} -namespace wobble = ::blarg; // expected-error{{no namespace named 'blarg' in the global namespace; did you mean 'blargh'?}} - -bool test_string(std::string s) { - basc_string b1; // expected-error{{no template named 'basc_string'; did you mean 'basic_string'?}} - std::basic_sting b2; // expected-error{{no template named 'basic_sting' in namespace 'std'; did you mean 'basic_string'?}} - (void)b1; - (void)b2; - return s.fnd("hello") // expected-error{{no member named 'fnd' in 'std::basic_string'; did you mean 'find'?}} - == std::string::pos; // expected-error{{no member named 'pos' in 'std::basic_string'; did you mean 'npos'?}} -} - -struct Base { }; -struct Derived : public Base { // expected-note{{base class 'Base' specified here}} - int member; // expected-note 3{{'member' declared here}} - - Derived() : base(), // expected-error{{initializer 'base' does not name a non-static data member or base class; did you mean the base class 'Base'?}} - ember() { } // expected-error{{initializer 'ember' does not name a non-static data member or base class; did you mean the member 'member'?}} - - int getMember() const { - return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}} - } - - int &getMember(); -}; - -int &Derived::getMember() { - return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}} -} - -typedef int Integer; // expected-note{{'Integer' declared here}} -int global_value; // expected-note{{'global_value' declared here}} - -int foo() { - integer * i = 0; // expected-error{{unknown type name 'integer'; did you mean 'Integer'?}} - unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}} - return *i + *ptr + global_val; // expected-error{{use of undeclared identifier 'global_val'; did you mean 'global_value'?}} -} - -namespace nonstd { - typedef std::basic_string yarn; // expected-note 2 {{'nonstd::yarn' declared here}} - int narf; // expected-note{{'nonstd::narf' declared here}} -} - -yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}} -wibble::yarn str5; // expected-error{{no type named 'yarn' in namespace 'otherstd'; did you mean 'nonstd::yarn'?}} - -namespace another { - template class wide_string {}; // expected-note {{'another::wide_string' declared here}} -} -int poit() { - nonstd::basic_string str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean simply 'basic_string'?}} - nonstd::wide_string str2; // expected-error{{no template named 'wide_string' in namespace 'nonstd'; did you mean 'another::wide_string'?}} - return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}} -} - -namespace check_bool { - void f() { - Bool b; // expected-error{{use of undeclared identifier 'Bool'; did you mean 'bool'?}} - } -} - -namespace outr { -} -namespace outer { - namespace inner { // expected-note{{'outer::inner' declared here}} \ - // expected-note{{namespace 'outer::inner' defined here}} \ - // expected-note{{'inner' declared here}} - int i; - } -} - -using namespace outr::inner; // expected-error{{no namespace named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}} - -void func() { - outr::inner::i = 3; // expected-error{{no member named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}} - outer::innr::i = 4; // expected-error{{no member named 'innr' in namespace 'outer'; did you mean 'inner'?}} -} - -struct base { -}; -struct derived : base { - int i; -}; - -void func2() { - derived d; - // FIXME: we should offer a fix here. We do if the 'i' is misspelled, but we don't do name qualification changes - // to replace base::i with derived::i as we would for other qualified name misspellings. - // d.base::i = 3; -} - -class A { - void bar(int); -}; -void bar(int, int); // expected-note{{'::bar' declared here}} -void A::bar(int x) { - bar(x, 5); // expected-error{{too many arguments to function call, expected 1, have 2; did you mean '::bar'?}} -} diff --git a/clang/test/Format/multiple-inputs-error.cpp b/clang/test/Format/multiple-inputs-error.cpp index 1aa9c9f3e2fa..7cb835d39f23 100644 --- a/clang/test/Format/multiple-inputs-error.cpp +++ b/clang/test/Format/multiple-inputs-error.cpp @@ -1,6 +1,6 @@ // RUN: cp %s %t-1.cpp // RUN: cp %s %t-2.cpp -// RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=0 %t-1.cpp %t-2.cpp |FileCheck %s +// RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=1 %t-1.cpp %t-2.cpp |FileCheck %s // RUN: not clang-format 2>&1 >/dev/null -lines=1:1 %t-1.cpp %t-2.cpp |FileCheck %s -check-prefix=CHECK-LINE // CHECK: error: -offset, -length and -lines can only be used for single file. // CHECK-LINE: error: -offset, -length and -lines can only be used for single file. diff --git a/clang/test/Format/ranges.cpp b/clang/test/Format/ranges.cpp index 66b984e037b3..f42492e43f84 100644 --- a/clang/test/Format/ranges.cpp +++ b/clang/test/Format/ranges.cpp @@ -1,5 +1,5 @@ // RUN: grep -Ev "// *[A-Z-]+:" %s \ -// RUN: | clang-format -style=LLVM -offset=2 -length=0 -offset=28 -length=0 \ +// RUN: | clang-format -style=LLVM -offset=2 -length=1 -offset=28 -length=1 -offset=35 -length=8 \ // RUN: | FileCheck -strict-whitespace %s // CHECK: {{^int\ \*i;$}} int*i; @@ -9,3 +9,12 @@ int * i; // CHECK: {{^int\ \*i;$}} int * i; + +// CHECK: int I; +// CHECK-NEXT: int J ; +int I ; +int J ; + +// RUN: not clang-format -length=0 %s 2>&1 \ +// RUN: | FileCheck -strict-whitespace -check-prefix=CHECK0 %s +// CHECK0: error: length should be at least 1 diff --git a/clang/test/Frontend/aarch64-print-enabled-extensions-cc1.c b/clang/test/Frontend/aarch64-print-enabled-extensions-cc1.c index 5d65fdafaa25..d761e12e8392 100644 --- a/clang/test/Frontend/aarch64-print-enabled-extensions-cc1.c +++ b/clang/test/Frontend/aarch64-print-enabled-extensions-cc1.c @@ -57,7 +57,7 @@ // RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=DISABLE_VIA_XCLANG // However, sve2 is actually enabled in clang but disabled for MC. -// RUN: %clang --target=aarch64 -march=armv8-a+sve2 -c %s \ +// RUN: %clang --target=aarch64 -march=armv8-a+sve2 -c %s -o %t \ // RUN: -Xclang -target-feature -Xclang -sve \ // RUN: -Xclang -verify -Xclang -verify-ignore-unexpected=note diff --git a/clang/test/Frontend/ast-main.c b/clang/test/Frontend/ast-main.c index cdc74219f73a..6a64497f4109 100644 --- a/clang/test/Frontend/ast-main.c +++ b/clang/test/Frontend/ast-main.c @@ -1,6 +1,6 @@ -// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t1.ll -x c - < %s +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o - -x c - < %s | grep -v DIFile > %t1.ll // RUN: env SDKROOT="/" %clang -emit-ast -o %t.ast %s -// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o - -x ast - < %t.ast | grep -v DIFile > %t2.ll // RUN: diff %t1.ll %t2.ll int main(void) { diff --git a/clang/test/Frontend/ast-main.cpp b/clang/test/Frontend/ast-main.cpp index fe47ce435f06..fc09e6437f93 100644 --- a/clang/test/Frontend/ast-main.cpp +++ b/clang/test/Frontend/ast-main.cpp @@ -1,6 +1,6 @@ -// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o %t1.ll -x c++ - < %s +// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o - -x c++ - < %s | grep -v DIFile > %t1.ll // RUN: env SDKROOT="/" %clang -Wno-error=return-type -fno-delayed-template-parsing -emit-ast -o %t.ast %s -// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o %t2.ll -x ast - < %t.ast +// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o - -x ast - < %t.ast | grep -v DIFile > %t2.ll // RUN: diff %t1.ll %t2.ll // http://llvm.org/bugs/show_bug.cgi?id=15377 diff --git a/clang/test/Index/complete-switch.c b/clang/test/Index/complete-switch.c deleted file mode 100644 index 4a7885459554..000000000000 --- a/clang/test/Index/complete-switch.c +++ /dev/null @@ -1,10 +0,0 @@ -void f() { - auto foo = bar; - switch(foo) { - case x: - break; - } -} - -// RUN: not %clang_cc1 -fsyntax-only -fno-recovery-ast -code-completion-at=%s:4:10 %s | FileCheck %s -allow-empty -// CHECK-NOT: COMPLETION: foo diff --git a/clang/test/Index/fix-its.c b/clang/test/Index/fix-its.c index 1e710c28afcc..8378fd9da9b4 100644 --- a/clang/test/Index/fix-its.c +++ b/clang/test/Index/fix-its.c @@ -1,27 +1,12 @@ -// RUN: c-index-test -test-load-source all -fspell-checking %s 2> %t +// RUN: c-index-test -test-load-source all -fspell-checking %s 2> %t // RUN: FileCheck %s < %t -struct X { - int wibble; -}; - #define MACRO(X) X -void f(struct X *x) { - // CHECK: error: no member named 'wobble' in 'struct X'; did you mean 'wibble'? - // CHECK: FIX-IT: Replace [13:12 - 13:18] with "wibble" - // CHECK: note: 'wibble' declared here - MACRO(x->wobble = 17); - // CHECK: error: no member named 'wabble' in 'struct X'; did you mean 'wibble'? - // CHECK: FIX-IT: Replace [17:6 - 17:12] with "wibble" - // CHECK: note: 'wibble' declared here - x->wabble = 17; -} - int printf(const char *restrict, ...); void f2() { unsigned long index; // CHECK: warning: format specifies type 'int' but the argument has type 'unsigned long' - // CHECK: FIX-IT: Replace [26:17 - 26:19] with "%lu" + // CHECK: FIX-IT: Replace [11:17 - 11:19] with "%lu" MACRO(printf("%d", index)); } diff --git a/clang/test/Lexer/raw-string-ext.c b/clang/test/Lexer/raw-string-ext.c index de318b616df7..8ed96e5c19f0 100644 --- a/clang/test/Lexer/raw-string-ext.c +++ b/clang/test/Lexer/raw-string-ext.c @@ -27,13 +27,13 @@ // no-warning@* {{ignoring '-fno-raw-string-literals'}} void f() { - (void) R"foo()foo"; // unsupported-error {{use of undeclared identifier 'R'}} cxx-unsupported-error {{expected ';' after expression}} - (void) LR"foo()foo"; // unsupported-error {{use of undeclared identifier 'LR'}} cxx-unsupported-error {{expected ';' after expression}} + (void) R"foo()foo"; // unsupported-error {{use of undeclared identifier 'R'}} + (void) LR"foo()foo"; // unsupported-error {{use of undeclared identifier 'LR'}} #ifdef UNICODE - (void) uR"foo()foo"; // unsupported-error {{use of undeclared identifier 'uR'}} cxx-unsupported-error {{expected ';' after expression}} - (void) u8R"foo()foo"; // unsupported-error {{use of undeclared identifier 'u8R'}} cxx-unsupported-error {{expected ';' after expression}} - (void) UR"foo()foo"; // unsupported-error {{use of undeclared identifier 'UR'}} cxx-unsupported-error {{expected ';' after expression}} + (void) uR"foo()foo"; // unsupported-error {{use of undeclared identifier 'uR'}} + (void) u8R"foo()foo"; // unsupported-error {{use of undeclared identifier 'u8R'}} + (void) UR"foo()foo"; // unsupported-error {{use of undeclared identifier 'UR'}} #endif } diff --git a/clang/test/Misc/loop-opt-setup.c b/clang/test/Misc/loop-opt-setup.c index 01643e6073b5..c1c620e52200 100644 --- a/clang/test/Misc/loop-opt-setup.c +++ b/clang/test/Misc/loop-opt-setup.c @@ -15,7 +15,7 @@ int foo(void) { // CHECK-NOT: br i1 void Helper(void) { - const int *nodes[5]; + const int *nodes[5] = {0}; int num_active = 5; while (num_active) diff --git a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c index 9ef44b2bb403..352658b6fb38 100644 --- a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c +++ b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c @@ -68,6 +68,7 @@ // CHECK-SAME: {{^}}, gfx1153 // CHECK-SAME: {{^}}, gfx1200 // CHECK-SAME: {{^}}, gfx1201 +// CHECK-SAME: {{^}}, gfx1250 // CHECK-SAME: {{^}}, gfx9-generic // CHECK-SAME: {{^}}, gfx10-1-generic // CHECK-SAME: {{^}}, gfx10-3-generic diff --git a/clang/test/Misc/target-invalid-cpu-note/avr.c b/clang/test/Misc/target-invalid-cpu-note/avr.c index 86ffbb683858..49d68bcc2edf 100644 --- a/clang/test/Misc/target-invalid-cpu-note/avr.c +++ b/clang/test/Misc/target-invalid-cpu-note/avr.c @@ -311,6 +311,9 @@ // CHECK-SAME: {{^}}, attiny1624 // CHECK-SAME: {{^}}, attiny1626 // CHECK-SAME: {{^}}, attiny1627 +// CHECK-SAME: {{^}}, attiny3224 +// CHECK-SAME: {{^}}, attiny3226 +// CHECK-SAME: {{^}}, attiny3227 // CHECK-SAME: {{^}}, atmega808 // CHECK-SAME: {{^}}, atmega809 // CHECK-SAME: {{^}}, atmega1608 @@ -319,4 +322,66 @@ // CHECK-SAME: {{^}}, atmega3209 // CHECK-SAME: {{^}}, atmega4808 // CHECK-SAME: {{^}}, atmega4809 +// CHECK-SAME: {{^}}, avr64da28 +// CHECK-SAME: {{^}}, avr64da32 +// CHECK-SAME: {{^}}, avr64da48 +// CHECK-SAME: {{^}}, avr64da64 +// CHECK-SAME: {{^}}, avr64db28 +// CHECK-SAME: {{^}}, avr64db32 +// CHECK-SAME: {{^}}, avr64db48 +// CHECK-SAME: {{^}}, avr64db64 +// CHECK-SAME: {{^}}, avr64dd14 +// CHECK-SAME: {{^}}, avr64dd20 +// CHECK-SAME: {{^}}, avr64dd28 +// CHECK-SAME: {{^}}, avr64dd32 +// CHECK-SAME: {{^}}, avr64du28 +// CHECK-SAME: {{^}}, avr64du32 +// CHECK-SAME: {{^}}, avr64ea28 +// CHECK-SAME: {{^}}, avr64ea32 +// CHECK-SAME: {{^}}, avr64ea48 +// CHECK-SAME: {{^}}, avr64sd28 +// CHECK-SAME: {{^}}, avr64sd32 +// CHECK-SAME: {{^}}, avr64sd48 +// CHECK-SAME: {{^}}, avr16dd20 +// CHECK-SAME: {{^}}, avr16dd28 +// CHECK-SAME: {{^}}, avr16dd32 +// CHECK-SAME: {{^}}, avr16du14 +// CHECK-SAME: {{^}}, avr16du20 +// CHECK-SAME: {{^}}, avr16du28 +// CHECK-SAME: {{^}}, avr16du32 +// CHECK-SAME: {{^}}, avr32da28 +// CHECK-SAME: {{^}}, avr32da32 +// CHECK-SAME: {{^}}, avr32da48 +// CHECK-SAME: {{^}}, avr32db28 +// CHECK-SAME: {{^}}, avr32db32 +// CHECK-SAME: {{^}}, avr32db48 +// CHECK-SAME: {{^}}, avr32dd14 +// CHECK-SAME: {{^}}, avr32dd20 +// CHECK-SAME: {{^}}, avr32dd28 +// CHECK-SAME: {{^}}, avr32dd32 +// CHECK-SAME: {{^}}, avr32du14 +// CHECK-SAME: {{^}}, avr32du20 +// CHECK-SAME: {{^}}, avr32du28 +// CHECK-SAME: {{^}}, avr32du32 +// CHECK-SAME: {{^}}, avr16eb14 +// CHECK-SAME: {{^}}, avr16eb20 +// CHECK-SAME: {{^}}, avr16eb28 +// CHECK-SAME: {{^}}, avr16eb32 +// CHECK-SAME: {{^}}, avr16ea28 +// CHECK-SAME: {{^}}, avr16ea32 +// CHECK-SAME: {{^}}, avr16ea48 +// CHECK-SAME: {{^}}, avr32ea28 +// CHECK-SAME: {{^}}, avr32ea32 +// CHECK-SAME: {{^}}, avr32ea48 +// CHECK-SAME: {{^}}, avr32sd20 +// CHECK-SAME: {{^}}, avr32sd28 +// CHECK-SAME: {{^}}, avr32sd32 +// CHECK-SAME: {{^}}, avr128da28 +// CHECK-SAME: {{^}}, avr128da32 +// CHECK-SAME: {{^}}, avr128da48 +// CHECK-SAME: {{^}}, avr128da64 +// CHECK-SAME: {{^}}, avr128db28 +// CHECK-SAME: {{^}}, avr128db32 +// CHECK-SAME: {{^}}, avr128db48 +// CHECK-SAME: {{^}}, avr128db64 // CHECK-SAME: {{$}} diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c b/clang/test/Misc/target-invalid-cpu-note/nvptx.c index 6675a1ecc34b..b5209ffc5f0a 100644 --- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c +++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c @@ -83,5 +83,6 @@ // CHECK-SAME: {{^}}, gfx12-generic // CHECK-SAME: {{^}}, gfx1200 // CHECK-SAME: {{^}}, gfx1201 +// CHECK-SAME: {{^}}, gfx1250 // CHECK-SAME: {{^}}, amdgcnspirv // CHECK-SAME: {{$}} diff --git a/clang/test/Modules/diagnose-missing-import.m b/clang/test/Modules/diagnose-missing-import.m index 8fb8e6b25f68..b34bc1a62b6b 100644 --- a/clang/test/Modules/diagnose-missing-import.m +++ b/clang/test/Modules/diagnose-missing-import.m @@ -7,11 +7,9 @@ void foo(void) { XYZLogEvent(xyzRiskyCloseOpenParam, xyzRiskyCloseOpenParam); // expected-error {{call to undeclared function 'XYZLogEvent'; ISO C99 and later do not support implicit function declarations}} \ expected-error {{declaration of 'XYZLogEvent' must be imported}} \ - expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}} \ expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}} } -// expected-note@Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}} // expected-note@Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}} // expected-note@Inputs/diagnose-missing-import/a.h:6 {{declaration here is not visible}} diff --git a/clang/test/Modules/include-after-imports-enums.cppm b/clang/test/Modules/include-after-imports-enums.cppm new file mode 100644 index 000000000000..00affd98e299 --- /dev/null +++ b/clang/test/Modules/include-after-imports-enums.cppm @@ -0,0 +1,25 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t -verify -fsyntax-only +// +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-reduced-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t -verify -fsyntax-only + +//--- enum.h +enum E { Value }; + +//--- M.cppm +module; +#include "enum.h" +export module M; +auto e = Value; + +//--- use.cpp +// expected-no-diagnostics +import M; +#include "enum.h" + +auto e = Value; diff --git a/clang/test/Modules/module-local-declarations-02.cppm b/clang/test/Modules/module-local-declarations-02.cppm new file mode 100644 index 000000000000..0670c4295abc --- /dev/null +++ b/clang/test/Modules/module-local-declarations-02.cppm @@ -0,0 +1,31 @@ +// 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 -fprebuilt-module-path=%t -emit-llvm -o %t/B.ll + +//--- A.cppm +export module A; + +export template +struct holder { +}; + +struct foo {}; + +export struct a { + holder m; +}; + +//--- B.cppm +// expected-no-diagnostics +export module B; + +import A; + +struct foo {}; + +struct b { + holder m; +}; \ No newline at end of file diff --git a/clang/test/Modules/module-local-declarations.cppm b/clang/test/Modules/module-local-declarations.cppm new file mode 100644 index 000000000000..4fbcf09e4d79 --- /dev/null +++ b/clang/test/Modules/module-local-declarations.cppm @@ -0,0 +1,30 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/Base.cppm -emit-module-interface -o %t/Base.pcm +// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/A.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/B.cppm -fsyntax-only -verify -fprebuilt-module-path=%t + +//--- Base.cppm +export module Base; +export template +class Base {}; + +//--- A.cppm +export module A; +import Base; +struct S {}; + +export Base a; + +//--- B.cppm +// expected-no-diagnostics +export module B; + +import A; +import Base; + +struct S {}; + +export Base b; diff --git a/clang/test/Modules/named-modules-adl-3.cppm b/clang/test/Modules/named-modules-adl-3.cppm index d70946fa068b..a3644b45a534 100644 --- a/clang/test/Modules/named-modules-adl-3.cppm +++ b/clang/test/Modules/named-modules-adl-3.cppm @@ -58,6 +58,7 @@ void b(T x) { } //--- c.cppm +module; #ifdef EXPORT_OPERATOR // expected-no-diagnostics #endif diff --git a/clang/test/Modules/pr119947.cppm b/clang/test/Modules/pr119947.cppm new file mode 100644 index 000000000000..40de2cad3c0d --- /dev/null +++ b/clang/test/Modules/pr119947.cppm @@ -0,0 +1,54 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t -emit-llvm -o - + + +//--- a.cppm +export module a; + +struct a_inner { + ~a_inner() { + } + void f(auto) { + } +}; + +export template +struct a { + a() { + struct local {}; + inner.f(local()); + } +private: + a_inner inner; +}; + + +namespace { + +struct s { +}; + +} // namespace + +void f() { + a x; +} + +//--- use.cpp +import a; + +namespace { + +struct s { +}; + +} // namespace + +void g() { + a x; +} + diff --git a/clang/test/Modules/pr131058.cppm b/clang/test/Modules/pr131058.cppm new file mode 100644 index 000000000000..c5a626103373 --- /dev/null +++ b/clang/test/Modules/pr131058.cppm @@ -0,0 +1,85 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-reduced-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M0.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t -DMODULE_LOCAL +// RUN: %clang_cc1 -std=c++20 %t/M0.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M0.cppm -emit-reduced-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t -DMODULE_LOCAL +// RUN: %clang_cc1 -std=c++20 %t/M0.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M2.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M2.cppm -emit-reduced-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +// RUN: %clang_cc1 -std=c++20 %t/M3.cppm -emit-reduced-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/use2.cpp -fsyntax-only -verify -fprebuilt-module-path=%t + +//--- enum.h +enum { SomeName, }; + +//--- M.cppm +module; +#include "enum.h" +export module M; +export auto e = SomeName; + +//--- M0.cppm +export module M; +enum { SomeName, }; +export auto e = SomeName; + +//--- M0.cpp +// expected-no-diagnostics +module M; +auto a = SomeName; + +//--- use.cpp +import M; +auto a = SomeName; // expected-error {{use of undeclared identifier 'SomeName'}} +auto b = decltype(e)::SomeName; + +//--- enum1.h +extern "C++" { +enum { SomeName, }; +} + +//--- M2.cppm +module; +#include "enum1.h" +export module M; +export auto e = SomeName; + +//--- enums.h +namespace nn { +enum E { Value }; +enum E2 { VisibleEnum }; +enum AlwaysVisibleEnums { UnconditionallyVisible }; +} + +//--- M3.cppm +module; +#include "enums.h" +export module M; +export namespace nn { + using nn::E2::VisibleEnum; + using nn::AlwaysVisibleEnums; +} +auto e1 = nn::Value; +auto e2 = nn::VisibleEnum; + +//--- use2.cpp +import M; +auto e = nn::Value1; // expected-error {{no member named 'Value1' in namespace 'nn'}} +auto e2 = nn::VisibleEnum; +auto e3 = nn::UnconditionallyVisible; diff --git a/clang/test/Modules/pr143788.cppm b/clang/test/Modules/pr143788.cppm new file mode 100644 index 000000000000..5ae36d8d0e85 --- /dev/null +++ b/clang/test/Modules/pr143788.cppm @@ -0,0 +1,28 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 %t/P.cppm -emit-module-interface -o %t/P.pcm +// RUN: %clang_cc1 -std=c++20 %t/I.cpp -fmodule-file=M:P=%t/P.pcm -fmodule-file=M=%t/M.pcm -fsyntax-only -verify + +//--- H.hpp +struct S{}; + +//--- M.cppm +export module M; + + +//--- P.cppm +module; +#include "H.hpp" +module M:P; + +using T = S; + +//--- I.cpp +// expected-no-diagnostics +module M; +import :P; + +T f() { return {}; } diff --git a/clang/test/Modules/pr144230.cppm b/clang/test/Modules/pr144230.cppm new file mode 100644 index 000000000000..7de9fc6461ab --- /dev/null +++ b/clang/test/Modules/pr144230.cppm @@ -0,0 +1,26 @@ +// 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/P.cppm -emit-module-interface -o %t/M-P.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/M.cpp -fprebuilt-module-path=%t -fsyntax-only -verify + +//--- A.cppm +export module A; +export using T = int; + +//--- P.cppm +export module M:P; +import A; + +//--- M.cppm +export module M; +export import :P; + +//--- M.cpp +// expected-no-diagnostics +module M; + +T x; diff --git a/clang/test/Modules/pr61360.cppm b/clang/test/Modules/pr61360.cppm new file mode 100644 index 000000000000..a16f65d4be2f --- /dev/null +++ b/clang/test/Modules/pr61360.cppm @@ -0,0 +1,25 @@ +// 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 -fprebuilt-module-path=%t -emit-llvm -o %t/B.ll + +//--- A.cppm +export module A; +export template +struct holder { +}; + +struct a { + holder m; +}; + +//--- B.cppm +// expected-no-diagnostics +export module B; +import A; + +struct b { + holder m; +}; diff --git a/clang/test/Modules/preferred_name_header_unit.cpp b/clang/test/Modules/preferred_name_header_unit.cpp new file mode 100644 index 000000000000..b1f1e3579f31 --- /dev/null +++ b/clang/test/Modules/preferred_name_header_unit.cpp @@ -0,0 +1,64 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -verify -w -std=c++20 -fmodule-name=h1.h -emit-header-unit -xc++-user-header h1.h -o h1.pcm +// RUN: %clang_cc1 -verify -w -std=c++20 -fmodule-map-file=module.modulemap -fmodule-file=h1.h=h1.pcm main.cpp -o main.o + +//--- module.modulemap +module "h1.h" { + header "h1.h" + export * +} + +//--- h0.h +// expected-no-diagnostics +#pragma once +namespace std { + +template class basic_string; + +namespace pmr { +using string = basic_string; +} + +template +class __attribute__((__preferred_name__(pmr::string))) basic_string; + +template class basic_string_view {}; + +template class basic_string { + typedef _CharT value_type; + typedef _Allocator allocator_type; + struct __rep; +public: + template + basic_string(_Tp) {} + basic_string operator+=(value_type); +}; + +namespace filesystem { +class path { + typedef char value_type; + value_type preferred_separator; + typedef basic_string string_type; + typedef basic_string_view __string_view; + template void append(_Source) { + __pn_ += preferred_separator; + } + void __root_directory() { append(string_type(__string_view{})); } + string_type __pn_; +}; +} // namespace filesystem +} // namespace std + +//--- h1.h +// expected-no-diagnostics +#pragma once + +#include "h0.h" + +//--- main.cpp +// expected-no-diagnostics +#include "h0.h" + +import "h1.h"; diff --git a/clang/test/Modules/reserved-names-1.cppm b/clang/test/Modules/reserved-names-1.cppm index e780f1e35b3b..35b264bcb573 100644 --- a/clang/test/Modules/reserved-names-1.cppm +++ b/clang/test/Modules/reserved-names-1.cppm @@ -88,12 +88,14 @@ export module module; // expected-error {{'module' is an invalid name for a modu export module import; // expected-error {{'import' is an invalid name for a module}} //--- _Test.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif export module _Test; // loud-warning {{'_Test' is a reserved name for a module}} //--- __test.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif @@ -101,6 +103,7 @@ export module __test; // loud-warning {{'__test' is a reserved name for a module export int a = 43; //--- te__st.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif @@ -108,6 +111,7 @@ export module te__st; // loud-warning {{'te__st' is a reserved name for a module export int a = 43; //--- std.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif @@ -116,36 +120,42 @@ export module std; // loud-warning {{'std' is a reserved name for a module}} export int a = 43; //--- std.foo.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif export module std.foo;// loud-warning {{'std' is a reserved name for a module}} //--- std0.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif export module std0; // loud-warning {{'std0' is a reserved name for a module}} //--- std1000000.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif export module std1000000; // loud-warning {{'std1000000' is a reserved name for a module}} //--- should_diag._Test.cppm +module; #ifdef NODIAGNOSTICS // expected-no-diagnostics #endif export module should_diag._Test; // loud-warning {{'_Test' is a reserved name for a module}} //--- system-module.cppm +module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}} // Show that being in a system header doesn't save you from diagnostics about // use of an invalid module-name identifier. # 34 "reserved-names-1.cpp" 1 3 export module module; // expected-error {{'module' is an invalid name for a module}} //--- system._Test.import.cppm +module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}} # 34 "reserved-names-1.cpp" 1 3 export module _Test.import; // expected-error {{'import' is an invalid name for a module}} diff --git a/clang/test/Modules/reserved-names-system-header-1.cpp b/clang/test/Modules/reserved-names-system-header-1.cpp index 2db4c08add1d..fa869483980f 100644 --- a/clang/test/Modules/reserved-names-system-header-1.cpp +++ b/clang/test/Modules/reserved-names-system-header-1.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s // expected-no-diagnostics +module; // Show that we suppress the reserved identifier diagnostic in a system header. # 100 "file.cpp" 1 3 // Enter a system header export module std; diff --git a/clang/test/Modules/reserved-names-system-header-2.cpp b/clang/test/Modules/reserved-names-system-header-2.cpp index 2087f487721c..d429e58dc171 100644 --- a/clang/test/Modules/reserved-names-system-header-2.cpp +++ b/clang/test/Modules/reserved-names-system-header-2.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s // expected-no-diagnostics +module; // Show that we suppress the reserved identifier diagnostic in a system header. # 100 "file.cpp" 1 3 // Enter a system header export module __test; diff --git a/clang/test/Modules/var-init-side-effects.cpp b/clang/test/Modules/var-init-side-effects.cpp new file mode 100644 index 000000000000..438a9eb20427 --- /dev/null +++ b/clang/test/Modules/var-init-side-effects.cpp @@ -0,0 +1,37 @@ +// Tests referencing variable with initializer containing side effect across module boundary +// +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/Foo.cppm \ +// RUN: -o %t/Foo.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface \ +// RUN: -fmodule-file=Foo=%t/Foo.pcm \ +// RUN: %t/Bar.cppm \ +// RUN: -o %t/Bar.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-obj \ +// RUN: -main-file-name Bar.cppm \ +// RUN: -fmodule-file=Foo=%t/Foo.pcm \ +// RUN: -x pcm %t/Bar.pcm \ +// RUN: -o %t/Bar.o + +//--- Foo.cppm +export module Foo; + +export { +class S {}; + +inline S s = S{}; +} + +//--- Bar.cppm +export module Bar; +import Foo; + +S bar() { + return s; +} + diff --git a/clang/test/OpenMP/begin_declare_variant_messages.c b/clang/test/OpenMP/begin_declare_variant_messages.c index d8d8f4211678..8878188e7ceb 100644 --- a/clang/test/OpenMP/begin_declare_variant_messages.c +++ b/clang/test/OpenMP/begin_declare_variant_messages.c @@ -83,7 +83,7 @@ const int var; #pragma omp end declare variant #pragma omp begin declare variant match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score (''); score ignored}} #pragma omp end declare variant -#pragma omp begin declare variant match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('()'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp begin declare variant match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score (''); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} #pragma omp end declare variant #pragma omp begin declare variant match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} #pragma omp end declare variant diff --git a/clang/test/OpenMP/declare_mapper_ast_print.c b/clang/test/OpenMP/declare_mapper_ast_print.c index 3c554a106fe4..bb83f23a0c18 100644 --- a/clang/test/OpenMP/declare_mapper_ast_print.c +++ b/clang/test/OpenMP/declare_mapper_ast_print.c @@ -49,6 +49,23 @@ struct dat { #pragma omp declare mapper(struct dat d) map(to: d.d) // CHECK: #pragma omp declare mapper (default : struct dat d) map(to: d.d){{$}} +// Verify that nested default mappers do not lead to a crash during parsing / sema. +// CHECK: struct inner { +struct inner { + int size; + int *data; +}; +#pragma omp declare mapper(struct inner i) map(i, i.data[0 : i.size]) +// CHECK: #pragma omp declare mapper (default : struct inner i) map(tofrom: default::i,i.data[0:i.size]){{$}} + +// CHECK: struct outer { +struct outer { + int a; + struct inner i; +}; +#pragma omp declare mapper(struct outer o) map(o) +// CHECK: #pragma omp declare mapper (default : struct outer o) map(tofrom: default::o) map(tofrom: o.i){{$}} + // CHECK: int main(void) { int main(void) { #pragma omp declare mapper(id: struct vec v) map(v.len) @@ -77,6 +94,14 @@ int main(void) { #pragma omp declare mapper(id1: struct vec vvec) map(iterator(it=0:vvec.len:2), tofrom:vvec.data[it]) // OMP52: #pragma omp declare mapper (id1 : struct vec vvec) map(iterator(int it = 0:vvec.len:2),tofrom: vvec.data[it]); #endif + + { + struct outer outer; +#pragma omp target map(outer) +// CHECK: #pragma omp target map(tofrom: outer) + { } + } + return 0; } // CHECK: } diff --git a/clang/test/OpenMP/declare_mapper_ast_print.cpp b/clang/test/OpenMP/declare_mapper_ast_print.cpp index 422fa9981672..9ca3412e3e3d 100644 --- a/clang/test/OpenMP/declare_mapper_ast_print.cpp +++ b/clang/test/OpenMP/declare_mapper_ast_print.cpp @@ -34,6 +34,28 @@ public: // CHECK: } // CHECK: ; +// Verify that nested default mappers do not lead to a crash during parsing / sema. +// CHECK: namespace N2 { +namespace N2 +{ +// CHECK: struct inner { +struct inner { + int size; + int *data; +}; +#pragma omp declare mapper(struct inner i) map(i, i.data[0 : i.size]) +// CHECK: #pragma omp declare mapper (default : struct inner i) map(tofrom: N2::default::i,i.data[0:i.size]){{$}} + +// CHECK: struct outer { +struct outer { + int a; + struct inner i; +}; +#pragma omp declare mapper(struct outer o) map(o) +// CHECK: #pragma omp declare mapper (default : struct outer o) map(tofrom: N2::default::o) map(tofrom: o.i){{$}} +} // namespace N2 +// CHECK: } + template class dat { public: @@ -122,6 +144,7 @@ T foo(T a) { int main() { N1::vec vv, vvv; N1::vecchild vc; + N2::outer outer; dat dd; #pragma omp target map(mapper(N1::id) tofrom: vv) map(mapper(dat::id) alloc: vvv) // CHECK: #pragma omp target map(mapper(N1::id),tofrom: vv) map(mapper(dat::id),alloc: vvv) @@ -132,6 +155,9 @@ int main() { #pragma omp target map(mapper(default) tofrom: dd) // CHECK: #pragma omp target map(mapper(default),tofrom: dd) { dd.d++; } +#pragma omp target map(outer) +// CHECK: #pragma omp target map(tofrom: outer) + { } #pragma omp target update to(mapper(N1::id) : vc) // CHECK: #pragma omp target update to(mapper(N1::id): vc) diff --git a/clang/test/OpenMP/declare_reduction_messages.cpp b/clang/test/OpenMP/declare_reduction_messages.cpp index 752cc4fb05a1..f91d952dfa14 100644 --- a/clang/test/OpenMP/declare_reduction_messages.cpp +++ b/clang/test/OpenMP/declare_reduction_messages.cpp @@ -69,7 +69,7 @@ class Class2 : public Class1 { #pragma omp declare reduction(fun77 : long : omp_out += omp_in) initializer(omp_priv Class2 < int > ()) // expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare reduction(fun8 : long : omp_out += omp_in) initializer(omp_priv 23) // expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare reduction(fun88 : long : omp_out += omp_in) initializer(omp_priv 23)) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} -#pragma omp declare reduction(fun9 : long : omp_out += omp_priv) initializer(omp_in = 23) // expected-error {{use of undeclared identifier 'omp_priv'; did you mean 'omp_in'?}} expected-note {{'omp_in' declared here}} +#pragma omp declare reduction(fun9 : long : omp_out += omp_priv) initializer(omp_in = 23) // expected-error {{use of undeclared identifier 'omp_priv'}} #pragma omp declare reduction(fun10 : long : omp_out += omp_in) initializer(omp_priv = 23) template diff --git a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp index 172dd1670421..c14e19cc8b7e 100644 --- a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp +++ b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp @@ -54,9 +54,9 @@ void foo_v3(float *AAA, float *BBB, int *I) {return;} //DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v1 //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' -//PRINT: #pragma omp declare variant(foo_v3) match(construct={dispatch}, device={arch(x86, x86_64)}) adjust_args(nothing:I) adjust_args(need_device_ptr:BBB) +//PRINT: #pragma omp declare variant(foo_v3) match(construct={dispatch}, device={arch(x86, x86_64)}) adjust_args(nothing:I) adjust_args(need_device_ptr:BBB) adjust_args(need_device_addr:AAA) -//PRINT: #pragma omp declare variant(foo_v2) match(construct={dispatch}, device={arch(ppc)}) adjust_args(need_device_ptr:AAA) +//PRINT: #pragma omp declare variant(foo_v2) match(construct={dispatch}, device={arch(ppc)}) adjust_args(need_device_ptr:AAA) adjust_args(need_device_addr:BBB) //PRINT: omp declare variant(foo_v1) match(construct={dispatch}, device={arch(arm)}) adjust_args(need_device_ptr:AAA,BBB) @@ -66,42 +66,48 @@ void foo_v3(float *AAA, float *BBB, int *I) {return;} #pragma omp declare variant(foo_v2) \ match(construct={dispatch}, device={arch(ppc)}), \ - adjust_args(need_device_ptr:AAA) + adjust_args(need_device_ptr:AAA) \ + adjust_args(need_device_addr:BBB) #pragma omp declare variant(foo_v3) \ adjust_args(need_device_ptr:BBB) adjust_args(nothing:I) \ + adjust_args(need_device_addr:AAA) \ match(construct={dispatch}, device={arch(x86,x86_64)}) void foo(float *AAA, float *BBB, int *I) {return;} -void Foo_Var(float *AAA, float *BBB) {return;} +void Foo_Var(float *AAA, float *BBB, float *CCC) {return;} #pragma omp declare variant(Foo_Var) \ match(construct={dispatch}, device={arch(x86_64)}) \ - adjust_args(need_device_ptr:AAA) adjust_args(nothing:BBB) + adjust_args(need_device_ptr:AAA) adjust_args(nothing:BBB) \ + adjust_args(need_device_addr:CCC) template -void Foo(T *AAA, T *BBB) {return;} +void Foo(T *AAA, T *BBB, T *CCC) {return;} -//PRINT: #pragma omp declare variant(Foo_Var) match(construct={dispatch}, device={arch(x86_64)}) adjust_args(nothing:BBB) adjust_args(need_device_ptr:AAA) -//DUMP: FunctionDecl{{.*}} Foo 'void (T *, T *)' +//PRINT: #pragma omp declare variant(Foo_Var) match(construct={dispatch}, device={arch(x86_64)}) adjust_args(nothing:BBB) adjust_args(need_device_ptr:AAA) adjust_args(need_device_addr:CCC) +//DUMP: FunctionDecl{{.*}} Foo 'void (T *, T *, T *)' //DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} //DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'CCC' // -//DUMP: FunctionDecl{{.*}} Foo 'void (float *, float *)' +//DUMP: FunctionDecl{{.*}} Foo 'void (float *, float *, float *)' //DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} //DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'CCC' void func() { float *A; float *B; + float *C; //#pragma omp dispatch - Foo(A, B); + Foo(A, B, C); } typedef void *omp_interop_t; diff --git a/clang/test/OpenMP/declare_variant_clauses_messages.cpp b/clang/test/OpenMP/declare_variant_clauses_messages.cpp index 284e49bbd21b..aadded7699ea 100644 --- a/clang/test/OpenMP/declare_variant_clauses_messages.cpp +++ b/clang/test/OpenMP/declare_variant_clauses_messages.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -std=c++11 -o - %s -// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -std=c++11 \ +// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -fopenmp-version=60 -std=c++11 -o - %s +// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -fopenmp-version=60 -std=c++11 \ // RUN: -DNO_INTEROP_T_DEF -o - %s -// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -std=c++11 -o - %s -// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -Wno-strict-prototypes -DC -x c -o - %s +// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -fopenmp-version=60 -std=c++11 -o - %s +// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux -fopenmp -fopenmp-version=60 -Wno-strict-prototypes -DC -x c -o - %s // RUN: %clang_cc1 -verify -triple x86_64-pc-windows-msvc -fms-compatibility \ -// RUN: -fopenmp -Wno-strict-prototypes -DC -DWIN -x c -o - %s +// RUN: -fopenmp -fopenmp-version=60 -Wno-strict-prototypes -DC -DWIN -x c -o - %s #ifdef NO_INTEROP_T_DEF void foo_v1(float *, void *); @@ -114,6 +114,16 @@ void vararg_bar2(const char *fmt) { return; } match(construct={dispatch}, device={arch(ppc)}), \ adjust_args(need_device_ptr:AAA) adjust_args(nothing:AAA) +// expected-error@+3 {{'adjust_arg' argument 'AAA' used in multiple clauses}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(arm)}) \ + adjust_args(need_device_ptr:AAA,BBB) adjust_args(need_device_addr:AAA) + +// expected-error@+3 {{'adjust_arg' argument 'AAA' used in multiple clauses}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(ppc)}), \ + adjust_args(need_device_addr:AAA) adjust_args(nothing:AAA) + // expected-error@+2 {{use of undeclared identifier 'J'}} #pragma omp declare variant(foo_v1) \ adjust_args(nothing:J) \ @@ -186,12 +196,12 @@ void vararg_bar2(const char *fmt) { return; } // expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)'}} #pragma omp declare variant(foo_v4) match(construct={dispatch}) -// expected-error@+3 {{incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'}} +// expected-error@+3 {{incorrect 'adjust_args' type, expected 'need_device_ptr', 'need_device_addr', or 'nothing'}} #pragma omp declare variant(foo_v1) \ match(construct={dispatch}, device={arch(arm)}) \ adjust_args(badaaop:AAA,BBB) -// expected-error@+3 {{incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'}} +// expected-error@+3 {{incorrect 'adjust_args' type, expected 'need_device_ptr', 'need_device_addr', or 'nothing'}} #pragma omp declare variant(foo_v1) \ match(construct={dispatch}, device={arch(arm)}) \ adjust_args(badaaop AAA,BBB) diff --git a/clang/test/OpenMP/declare_variant_messages.c b/clang/test/OpenMP/declare_variant_messages.c index 32e365cc415b..d1e36e5d1e7e 100644 --- a/clang/test/OpenMP/declare_variant_messages.c +++ b/clang/test/OpenMP/declare_variant_messages.c @@ -11,7 +11,7 @@ int foo(void); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} #pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foo // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} -#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} #pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) xxx // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} @@ -42,7 +42,7 @@ int foo(void); #pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(device={kind()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} #pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score (''); score ignored}} -#pragma omp declare variant(foo) match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('()'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(device = {kind(score(ibm) }) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score (''); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('foo()'); score ignored}} expected-warning {{'ibm' is not a valid context property for the context selector 'kind' and the context set 'device'; property ignored}} expected-note {{try 'match(implementation={vendor(ibm)})'}} expected-note {{the ignored property spans until here}} #pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'kind' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'kind' used here}} expected-note {{the ignored selector spans until here}} @@ -56,7 +56,7 @@ int foo(void); #pragma omp declare variant(foo) match(target_device={device_num}) // expected-warning {{the context selector 'device_num' in context set 'target_device' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foo) match(target_device={device_num()}) // expected-error {{expected expression}} #pragma omp declare variant(foo) match(target_device={device_num(-1)}) // expected-error {{argument to 'device_num' clause must be a non-negative integer value}} -#pragma omp declare variant(foo) match(target_device={device_num(abc)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'abc'}} +#pragma omp declare variant(foo) match(target_device={device_num(abc)}) // expected-error {{use of undeclared identifier 'abc'}} int bar(void); diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp index 8eb37bc64cbc..06da8a8e5b05 100644 --- a/clang/test/OpenMP/declare_variant_messages.cpp +++ b/clang/test/OpenMP/declare_variant_messages.cpp @@ -16,7 +16,7 @@ T foofoo(); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} #pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foo // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} -#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} #pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) xxx // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} @@ -57,7 +57,7 @@ int bar(); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} #pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo // expected-error {{expected ')'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} -#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} #pragma omp declare variant(foo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} diff --git a/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_ast_dump.cpp b/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_ast_dump.cpp new file mode 100644 index 000000000000..a5847709d3e7 --- /dev/null +++ b/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_ast_dump.cpp @@ -0,0 +1,34 @@ +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -ast-dump %s | FileCheck %s --check-prefix=DUM + +typedef struct { + int a; +} C; +#pragma omp declare mapper(C s) map(to : s.a) + +typedef struct { + int e; + C f; + int h; +} D; + +void foo() { + D sa[10]; + sa[1].e = 111; + sa[1].f.a = 222; + +#pragma omp target map(tofrom : sa) + { + sa[0].e = 333; + sa[1].f.a = 444; + } +} + +// DUM: -OMPDeclareMapperDecl{{.*}}<> +// DUM-NEXT: |-OMPMapClause {{.*}}<> +// DUM-NEXT: | |-MemberExpr {{.*}} 'int' lvalue .e +// DUM-NEXT: | | `-DeclRefExpr {{.*}}<> 'D' lvalue Var {{.*}} '_s' 'D' +// DUM-NEXT: | |-MemberExpr {{.*}} 'C' lvalue .f {{.*}} +// DUM-NEXT: | | `-DeclRefExpr {{.*}}<> 'D' lvalue Var {{.*}} '_s' 'D' +// DUM-NEXT: | `-MemberExpr {{.*}} 'int' lvalue .h {{.*}} +// DUM-NEXT: | `-DeclRefExpr {{.*}}<> 'D' lvalue Var {{.*}} '_s' 'D' +// DUM-NEXT: `-VarDecl {{.*}} col:1 implicit used _s 'D' diff --git a/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_codegen.cpp b/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_codegen.cpp new file mode 100644 index 000000000000..5df1e958ad55 --- /dev/null +++ b/clang/test/OpenMP/target_map_array_of_structs_with_nested_mapper_codegen.cpp @@ -0,0 +1,323 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ --global-value-regex "\.offload_.*" +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s + +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +typedef struct { + int a; +} C; +#pragma omp declare mapper(C s) map(to : s.a) + +typedef struct { + int e; + C f; + int h; +} D; + +void foo() { + D sa[10]; + sa[1].e = 111; + sa[1].f.a = 222; + +#pragma omp target map(tofrom : sa) + { + sa[1].e = 333; + sa[1].f.a = 444; + } +} +#endif +//. +// CHECK: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 120] +// CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 35] +//. +// CHECK-LABEL: define {{[^@]+}}@_Z3foov +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SA:%.*]] = alloca [10 x %struct.D], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS:%.*]] = alloca [1 x ptr], align 8 +// CHECK-NEXT: [[DOTOFFLOAD_PTRS:%.*]] = alloca [1 x ptr], align 8 +// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS:%.*]] = alloca [1 x ptr], align 8 +// CHECK-NEXT: [[KERNEL_ARGS:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS:%.*]], align 8 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x %struct.D], ptr [[SA]], i64 0, i64 1 +// CHECK-NEXT: [[E:%.*]] = getelementptr inbounds nuw [[STRUCT_D:%.*]], ptr [[ARRAYIDX]], i32 0, i32 0 +// CHECK-NEXT: store i32 111, ptr [[E]], align 4 +// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x %struct.D], ptr [[SA]], i64 0, i64 1 +// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds nuw [[STRUCT_D]], ptr [[ARRAYIDX1]], i32 0, i32 1 +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_C:%.*]], ptr [[F]], i32 0, i32 0 +// CHECK-NEXT: store i32 222, ptr [[A]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[SA]], ptr [[TMP0]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[SA]], ptr [[TMP1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS]], i64 0, i64 0 +// CHECK-NEXT: store ptr @.omp_mapper._ZTS1D.default, ptr [[TMP2]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 +// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 +// CHECK-NEXT: store i32 3, ptr [[TMP5]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 1 +// CHECK-NEXT: store i32 1, ptr [[TMP6]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP3]], ptr [[TMP7]], align 8 +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 +// CHECK-NEXT: store ptr [[TMP4]], ptr [[TMP8]], align 8 +// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 +// CHECK-NEXT: store ptr @.offload_sizes, ptr [[TMP9]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 +// CHECK-NEXT: store ptr @.offload_maptypes, ptr [[TMP10]], align 8 +// CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 +// CHECK-NEXT: store ptr null, ptr [[TMP11]], align 8 +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 +// CHECK-NEXT: store ptr [[DOTOFFLOAD_MAPPERS]], ptr [[TMP12]], align 8 +// CHECK-NEXT: [[TMP13:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 8 +// CHECK-NEXT: store i64 0, ptr [[TMP13]], align 8 +// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 9 +// CHECK-NEXT: store i64 0, ptr [[TMP14]], align 8 +// CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 10 +// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP15]], align 4 +// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 11 +// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4 +// CHECK-NEXT: [[TMP17:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 +// CHECK-NEXT: store i32 0, ptr [[TMP17]], align 4 +// CHECK-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1:[0-9]+]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l26.region_id, ptr [[KERNEL_ARGS]]) +// CHECK-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0 +// CHECK-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]] +// CHECK: omp_offload.failed: +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l26(ptr [[SA]]) #[[ATTR3:[0-9]+]] +// CHECK-NEXT: br label [[OMP_OFFLOAD_CONT]] +// CHECK: omp_offload.cont: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l26 +// CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(120) [[SA:%.*]]) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SA_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[SA]], ptr [[SA_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SA_ADDR]], align 8, !nonnull [[META5:![0-9]+]], !align [[META6:![0-9]+]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x %struct.D], ptr [[TMP0]], i64 0, i64 1 +// CHECK-NEXT: [[E:%.*]] = getelementptr inbounds nuw [[STRUCT_D:%.*]], ptr [[ARRAYIDX]], i32 0, i32 0 +// CHECK-NEXT: store i32 333, ptr [[E]], align 4 +// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x %struct.D], ptr [[TMP0]], i64 0, i64 1 +// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds nuw [[STRUCT_D]], ptr [[ARRAYIDX1]], i32 0, i32 1 +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_C:%.*]], ptr [[F]], i32 0, i32 0 +// CHECK-NEXT: store i32 444, ptr [[A]], align 4 +// CHECK-NEXT: ret void +// +// +// 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: [[TMP6:%.*]] = udiv exact i64 [[TMP3]], 12 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr [[STRUCT_D:%.*]], ptr [[TMP2]], i64 [[TMP6]] +// CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY:%.*]] = icmp sgt i64 [[TMP6]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[TMP9:%.*]] = icmp ne ptr [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP10:%.*]] = and i64 [[TMP4]], 16 +// CHECK-NEXT: [[TMP11:%.*]] = icmp ne i64 [[TMP10]], 0 +// CHECK-NEXT: [[TMP12:%.*]] = and i1 [[TMP9]], [[TMP11]] +// CHECK-NEXT: [[TMP13:%.*]] = or i1 [[OMP_ARRAYINIT_ISARRAY]], [[TMP12]] +// CHECK-NEXT: [[DOTOMP_ARRAY__INIT__DELETE:%.*]] = icmp eq i64 [[TMP8]], 0 +// CHECK-NEXT: [[TMP14:%.*]] = and i1 [[TMP13]], [[DOTOMP_ARRAY__INIT__DELETE]] +// CHECK-NEXT: br i1 [[TMP14]], label [[DOTOMP_ARRAY__INIT:%.*]], label [[OMP_ARRAYMAP_HEAD:%.*]] +// CHECK: .omp.array..init: +// CHECK-NEXT: [[TMP15:%.*]] = mul nuw i64 [[TMP6]], 12 +// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP4]], -4 +// CHECK-NEXT: [[TMP17:%.*]] = or i64 [[TMP16]], 512 +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP15]], i64 [[TMP17]], ptr [[TMP5]]) +// CHECK-NEXT: br label [[OMP_ARRAYMAP_HEAD]] +// CHECK: omp.arraymap.head: +// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP7]] +// 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 [ [[TMP2]], [[OMP_ARRAYMAP_HEAD]] ], [ [[OMP_ARRAYMAP_NEXT:%.*]], [[OMP_TYPE_END20:%.*]] ] +// 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 +// CHECK-NEXT: [[TMP18:%.*]] = getelementptr i32, ptr [[H]], i32 1 +// CHECK-NEXT: [[TMP19:%.*]] = ptrtoint ptr [[TMP18]] to i64 +// CHECK-NEXT: [[TMP20:%.*]] = ptrtoint ptr [[E]] to i64 +// CHECK-NEXT: [[TMP21:%.*]] = sub i64 [[TMP19]], [[TMP20]] +// CHECK-NEXT: [[TMP22:%.*]] = sdiv exact i64 [[TMP21]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK-NEXT: [[TMP23:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP0]]) +// CHECK-NEXT: [[TMP24:%.*]] = shl i64 [[TMP23]], 48 +// CHECK-NEXT: [[TMP25:%.*]] = add nuw i64 0, [[TMP24]] +// CHECK-NEXT: [[TMP26:%.*]] = and i64 [[TMP4]], 3 +// CHECK-NEXT: [[TMP27:%.*]] = icmp eq i64 [[TMP26]], 0 +// CHECK-NEXT: br i1 [[TMP27]], label [[OMP_TYPE_ALLOC:%.*]], label [[OMP_TYPE_ALLOC_ELSE:%.*]] +// CHECK: omp.type.alloc: +// CHECK-NEXT: [[TMP28:%.*]] = and i64 [[TMP25]], -4 +// CHECK-NEXT: br label [[OMP_TYPE_END:%.*]] +// CHECK: omp.type.alloc.else: +// CHECK-NEXT: [[TMP29:%.*]] = icmp eq i64 [[TMP26]], 1 +// CHECK-NEXT: br i1 [[TMP29]], label [[OMP_TYPE_TO:%.*]], label [[OMP_TYPE_TO_ELSE:%.*]] +// CHECK: omp.type.to: +// CHECK-NEXT: [[TMP30:%.*]] = and i64 [[TMP25]], -3 +// CHECK-NEXT: br label [[OMP_TYPE_END]] +// CHECK: omp.type.to.else: +// CHECK-NEXT: [[TMP31:%.*]] = icmp eq i64 [[TMP26]], 2 +// CHECK-NEXT: br i1 [[TMP31]], label [[OMP_TYPE_FROM:%.*]], label [[OMP_TYPE_END]] +// CHECK: omp.type.from: +// CHECK-NEXT: [[TMP32:%.*]] = and i64 [[TMP25]], -2 +// CHECK-NEXT: br label [[OMP_TYPE_END]] +// CHECK: omp.type.end: +// CHECK-NEXT: [[OMP_MAPTYPE:%.*]] = phi i64 [ [[TMP28]], [[OMP_TYPE_ALLOC]] ], [ [[TMP30]], [[OMP_TYPE_TO]] ], [ [[TMP32]], [[OMP_TYPE_FROM]] ], [ [[TMP25]], [[OMP_TYPE_TO_ELSE]] ] +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 [[TMP22]], i64 [[OMP_MAPTYPE]], ptr null) +// CHECK-NEXT: [[TMP33:%.*]] = add nuw i64 281474976711171, [[TMP24]] +// CHECK-NEXT: [[TMP34:%.*]] = and i64 [[TMP4]], 3 +// CHECK-NEXT: [[TMP35:%.*]] = icmp eq i64 [[TMP34]], 0 +// CHECK-NEXT: br i1 [[TMP35]], label [[OMP_TYPE_ALLOC1:%.*]], label [[OMP_TYPE_ALLOC_ELSE2:%.*]] +// CHECK: omp.type.alloc1: +// CHECK-NEXT: [[TMP36:%.*]] = and i64 [[TMP33]], -4 +// CHECK-NEXT: br label [[OMP_TYPE_END6:%.*]] +// CHECK: omp.type.alloc.else2: +// CHECK-NEXT: [[TMP37:%.*]] = icmp eq i64 [[TMP34]], 1 +// CHECK-NEXT: br i1 [[TMP37]], label [[OMP_TYPE_TO3:%.*]], label [[OMP_TYPE_TO_ELSE4:%.*]] +// CHECK: omp.type.to3: +// CHECK-NEXT: [[TMP38:%.*]] = and i64 [[TMP33]], -3 +// CHECK-NEXT: br label [[OMP_TYPE_END6]] +// CHECK: omp.type.to.else4: +// CHECK-NEXT: [[TMP39:%.*]] = icmp eq i64 [[TMP34]], 2 +// CHECK-NEXT: br i1 [[TMP39]], label [[OMP_TYPE_FROM5:%.*]], label [[OMP_TYPE_END6]] +// CHECK: omp.type.from5: +// CHECK-NEXT: [[TMP40:%.*]] = and i64 [[TMP33]], -2 +// CHECK-NEXT: br label [[OMP_TYPE_END6]] +// CHECK: omp.type.end6: +// CHECK-NEXT: [[OMP_MAPTYPE7:%.*]] = phi i64 [ [[TMP36]], [[OMP_TYPE_ALLOC1]] ], [ [[TMP38]], [[OMP_TYPE_TO3]] ], [ [[TMP40]], [[OMP_TYPE_FROM5]] ], [ [[TMP33]], [[OMP_TYPE_TO_ELSE4]] ] +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 4, i64 [[OMP_MAPTYPE7]], ptr null) +// CHECK-NEXT: [[TMP41:%.*]] = add nuw i64 281474976711171, [[TMP24]] +// CHECK-NEXT: [[TMP42:%.*]] = and i64 [[TMP4]], 3 +// CHECK-NEXT: [[TMP43:%.*]] = icmp eq i64 [[TMP42]], 0 +// CHECK-NEXT: br i1 [[TMP43]], label [[OMP_TYPE_ALLOC8:%.*]], label [[OMP_TYPE_ALLOC_ELSE9:%.*]] +// CHECK: omp.type.alloc8: +// CHECK-NEXT: [[TMP44:%.*]] = and i64 [[TMP41]], -4 +// CHECK-NEXT: br label [[OMP_TYPE_END13:%.*]] +// CHECK: omp.type.alloc.else9: +// CHECK-NEXT: [[TMP45:%.*]] = icmp eq i64 [[TMP42]], 1 +// CHECK-NEXT: br i1 [[TMP45]], label [[OMP_TYPE_TO10:%.*]], label [[OMP_TYPE_TO_ELSE11:%.*]] +// CHECK: omp.type.to10: +// CHECK-NEXT: [[TMP46:%.*]] = and i64 [[TMP41]], -3 +// CHECK-NEXT: br label [[OMP_TYPE_END13]] +// CHECK: omp.type.to.else11: +// CHECK-NEXT: [[TMP47:%.*]] = icmp eq i64 [[TMP42]], 2 +// CHECK-NEXT: br i1 [[TMP47]], label [[OMP_TYPE_FROM12:%.*]], label [[OMP_TYPE_END13]] +// CHECK: omp.type.from12: +// CHECK-NEXT: [[TMP48:%.*]] = and i64 [[TMP41]], -2 +// CHECK-NEXT: br label [[OMP_TYPE_END13]] +// CHECK: omp.type.end13: +// CHECK-NEXT: [[OMP_MAPTYPE14:%.*]] = phi i64 [ [[TMP44]], [[OMP_TYPE_ALLOC8]] ], [ [[TMP46]], [[OMP_TYPE_TO10]] ], [ [[TMP48]], [[OMP_TYPE_FROM12]] ], [ [[TMP41]], [[OMP_TYPE_TO_ELSE11]] ] +// CHECK-NEXT: call void @.omp_mapper._ZTS1C.default(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[F]], i64 4, i64 [[OMP_MAPTYPE14]], ptr null) #[[ATTR3]] +// CHECK-NEXT: [[TMP49:%.*]] = add nuw i64 281474976711171, [[TMP24]] +// CHECK-NEXT: [[TMP50:%.*]] = and i64 [[TMP4]], 3 +// CHECK-NEXT: [[TMP51:%.*]] = icmp eq i64 [[TMP50]], 0 +// CHECK-NEXT: br i1 [[TMP51]], label [[OMP_TYPE_ALLOC15:%.*]], label [[OMP_TYPE_ALLOC_ELSE16:%.*]] +// CHECK: omp.type.alloc15: +// CHECK-NEXT: [[TMP52:%.*]] = and i64 [[TMP49]], -4 +// CHECK-NEXT: br label [[OMP_TYPE_END20]] +// CHECK: omp.type.alloc.else16: +// CHECK-NEXT: [[TMP53:%.*]] = icmp eq i64 [[TMP50]], 1 +// CHECK-NEXT: br i1 [[TMP53]], label [[OMP_TYPE_TO17:%.*]], label [[OMP_TYPE_TO_ELSE18:%.*]] +// CHECK: omp.type.to17: +// CHECK-NEXT: [[TMP54:%.*]] = and i64 [[TMP49]], -3 +// CHECK-NEXT: br label [[OMP_TYPE_END20]] +// CHECK: omp.type.to.else18: +// CHECK-NEXT: [[TMP55:%.*]] = icmp eq i64 [[TMP50]], 2 +// CHECK-NEXT: br i1 [[TMP55]], label [[OMP_TYPE_FROM19:%.*]], label [[OMP_TYPE_END20]] +// CHECK: omp.type.from19: +// CHECK-NEXT: [[TMP56:%.*]] = and i64 [[TMP49]], -2 +// CHECK-NEXT: br label [[OMP_TYPE_END20]] +// CHECK: omp.type.end20: +// CHECK-NEXT: [[OMP_MAPTYPE21:%.*]] = phi i64 [ [[TMP52]], [[OMP_TYPE_ALLOC15]] ], [ [[TMP54]], [[OMP_TYPE_TO17]] ], [ [[TMP56]], [[OMP_TYPE_FROM19]] ], [ [[TMP49]], [[OMP_TYPE_TO_ELSE18]] ] +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[H]], i64 4, i64 [[OMP_MAPTYPE21]], 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]], [[TMP7]] +// CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISDONE]], label [[OMP_ARRAYMAP_EXIT:%.*]], label [[OMP_ARRAYMAP_BODY]] +// CHECK: omp.arraymap.exit: +// CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY22:%.*]] = icmp sgt i64 [[TMP6]], 1 +// CHECK-NEXT: [[TMP57:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[DOTOMP_ARRAY__DEL__DELETE:%.*]] = icmp ne i64 [[TMP57]], 0 +// CHECK-NEXT: [[TMP58:%.*]] = and i1 [[OMP_ARRAYINIT_ISARRAY22]], [[DOTOMP_ARRAY__DEL__DELETE]] +// CHECK-NEXT: br i1 [[TMP58]], label [[DOTOMP_ARRAY__DEL:%.*]], label [[OMP_DONE]] +// CHECK: .omp.array..del: +// CHECK-NEXT: [[TMP59:%.*]] = mul nuw i64 [[TMP6]], 12 +// CHECK-NEXT: [[TMP60:%.*]] = and i64 [[TMP4]], -4 +// CHECK-NEXT: [[TMP61:%.*]] = or i64 [[TMP60]], 512 +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP59]], i64 [[TMP61]], ptr [[TMP5]]) +// CHECK-NEXT: br label [[OMP_DONE]] +// CHECK: omp.done: +// CHECK-NEXT: ret void +// +// +// 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: [[TMP6:%.*]] = udiv exact i64 [[TMP3]], 4 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[TMP2]], i64 [[TMP6]] +// CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY:%.*]] = icmp sgt i64 [[TMP6]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[TMP9:%.*]] = icmp ne ptr [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP10:%.*]] = and i64 [[TMP4]], 16 +// CHECK-NEXT: [[TMP11:%.*]] = icmp ne i64 [[TMP10]], 0 +// CHECK-NEXT: [[TMP12:%.*]] = and i1 [[TMP9]], [[TMP11]] +// CHECK-NEXT: [[TMP13:%.*]] = or i1 [[OMP_ARRAYINIT_ISARRAY]], [[TMP12]] +// CHECK-NEXT: [[DOTOMP_ARRAY__INIT__DELETE:%.*]] = icmp eq i64 [[TMP8]], 0 +// CHECK-NEXT: [[TMP14:%.*]] = and i1 [[TMP13]], [[DOTOMP_ARRAY__INIT__DELETE]] +// CHECK-NEXT: br i1 [[TMP14]], label [[DOTOMP_ARRAY__INIT:%.*]], label [[OMP_ARRAYMAP_HEAD:%.*]] +// CHECK: .omp.array..init: +// CHECK-NEXT: [[TMP15:%.*]] = mul nuw i64 [[TMP6]], 4 +// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP4]], -4 +// CHECK-NEXT: [[TMP17:%.*]] = or i64 [[TMP16]], 512 +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP15]], i64 [[TMP17]], ptr [[TMP5]]) +// CHECK-NEXT: br label [[OMP_ARRAYMAP_HEAD]] +// CHECK: omp.arraymap.head: +// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP7]] +// 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 [ [[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: [[TMP18:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP0]]) +// CHECK-NEXT: [[TMP19:%.*]] = shl i64 [[TMP18]], 48 +// CHECK-NEXT: [[TMP20:%.*]] = add nuw i64 1, [[TMP19]] +// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP4]], 3 +// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 0 +// CHECK-NEXT: br i1 [[TMP22]], label [[OMP_TYPE_ALLOC:%.*]], label [[OMP_TYPE_ALLOC_ELSE:%.*]] +// CHECK: omp.type.alloc: +// CHECK-NEXT: [[TMP23:%.*]] = and i64 [[TMP20]], -4 +// CHECK-NEXT: br label [[OMP_TYPE_END]] +// CHECK: omp.type.alloc.else: +// CHECK-NEXT: [[TMP24:%.*]] = icmp eq i64 [[TMP21]], 1 +// CHECK-NEXT: br i1 [[TMP24]], label [[OMP_TYPE_TO:%.*]], label [[OMP_TYPE_TO_ELSE:%.*]] +// CHECK: omp.type.to: +// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP20]], -3 +// CHECK-NEXT: br label [[OMP_TYPE_END]] +// CHECK: omp.type.to.else: +// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP21]], 2 +// CHECK-NEXT: br i1 [[TMP26]], label [[OMP_TYPE_FROM:%.*]], label [[OMP_TYPE_END]] +// CHECK: omp.type.from: +// CHECK-NEXT: [[TMP27:%.*]] = and i64 [[TMP20]], -2 +// CHECK-NEXT: br label [[OMP_TYPE_END]] +// CHECK: omp.type.end: +// CHECK-NEXT: [[OMP_MAPTYPE:%.*]] = phi i64 [ [[TMP23]], [[OMP_TYPE_ALLOC]] ], [ [[TMP25]], [[OMP_TYPE_TO]] ], [ [[TMP27]], [[OMP_TYPE_FROM]] ], [ [[TMP20]], [[OMP_TYPE_TO_ELSE]] ] +// 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]], [[TMP7]] +// CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISDONE]], label [[OMP_ARRAYMAP_EXIT:%.*]], label [[OMP_ARRAYMAP_BODY]] +// CHECK: omp.arraymap.exit: +// CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY1:%.*]] = icmp sgt i64 [[TMP6]], 1 +// CHECK-NEXT: [[TMP28:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[DOTOMP_ARRAY__DEL__DELETE:%.*]] = icmp ne i64 [[TMP28]], 0 +// CHECK-NEXT: [[TMP29:%.*]] = and i1 [[OMP_ARRAYINIT_ISARRAY1]], [[DOTOMP_ARRAY__DEL__DELETE]] +// CHECK-NEXT: br i1 [[TMP29]], label [[DOTOMP_ARRAY__DEL:%.*]], label [[OMP_DONE]] +// CHECK: .omp.array..del: +// CHECK-NEXT: [[TMP30:%.*]] = mul nuw i64 [[TMP6]], 4 +// CHECK-NEXT: [[TMP31:%.*]] = and i64 [[TMP4]], -4 +// CHECK-NEXT: [[TMP32:%.*]] = or i64 [[TMP31]], 512 +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP30]], i64 [[TMP32]], ptr [[TMP5]]) +// CHECK-NEXT: br label [[OMP_DONE]] +// CHECK: omp.done: +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/target_map_nest_defalut_mapper_ast_dump.cpp b/clang/test/OpenMP/target_map_array_section_of_structs_with_nested_mapper_ast_dump.cpp similarity index 100% rename from clang/test/OpenMP/target_map_nest_defalut_mapper_ast_dump.cpp rename to clang/test/OpenMP/target_map_array_section_of_structs_with_nested_mapper_ast_dump.cpp diff --git a/clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp b/clang/test/OpenMP/target_map_array_section_of_structs_with_nested_mapper_codegen.cpp similarity index 100% rename from clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp rename to clang/test/OpenMP/target_map_array_section_of_structs_with_nested_mapper_codegen.cpp diff --git a/clang/test/OpenMP/target_update_messages.cpp b/clang/test/OpenMP/target_update_messages.cpp index 83191059202c..000cc80e513e 100644 --- a/clang/test/OpenMP/target_update_messages.cpp +++ b/clang/test/OpenMP/target_update_messages.cpp @@ -113,9 +113,11 @@ int main(int argc, char **argv) { // Check parsing with two modifiers. // lt51-warning@+1 {{missing ':' after ) - ignoring}} #pragma omp target update to(mapper(id), present: s) - // lt51-error@+3 {{use of undeclared identifier 'present'}} - // lt51-error@+2 {{use of undeclared identifier 'id'}} - // lt51-error@+1 {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}} + // lt51-error@+5 {{use of undeclared identifier 'present'}} + // lt51-error@+4 {{use of undeclared identifier 'id'}} + // lt51-error@+3 {{expected ',' or ')' in 'to' clause}} + // lt51-error@+2 {{expected ')'}} + // lt51-note@+1 {{to match this '('}} #pragma omp target update to(present, mapper(id): s) // lt51-warning@+1 {{missing ':' after ) - ignoring}} #pragma omp target update to(mapper(id) present: s) @@ -141,10 +143,9 @@ int main(int argc, char **argv) { #pragma omp target update to(present,,: s) // lt51-warning@+1 {{missing ':' after ) - ignoring}} #pragma omp target update to(mapper(id), present,: s) - // lt51-error@+4 {{use of undeclared identifier 'present'}} - // lt51-error@+3 {{use of undeclared identifier 'id'}} - // lt51-error@+2 {{expected expression}} - // lt51-error@+1 {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}} + // lt51-error@+3 {{use of undeclared identifier 'present'}} + // lt51-error@+2 {{use of undeclared identifier 'id'}} + // lt51-error@+1 {{expected expression}} #pragma omp target update to(present, mapper(id),: s) #pragma omp target update from(m) allocate(m) // expected-error {{unexpected OpenMP clause 'allocate' in directive '#pragma omp target update'}} diff --git a/clang/test/Options/enable_16bit_types_validation_spirv.hlsl b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl index aad8836db106..f37d00503fe5 100644 --- a/clang/test/Options/enable_16bit_types_validation_spirv.hlsl +++ b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl @@ -4,7 +4,7 @@ // SPIRV: error: '-fnative-half-type' option requires target HLSL Version >= 2018, but HLSL Version is 'hlsl2016' // valid: "spirv-unknown-vulkan-library" -// valid: define spir_func void @{{.*main.*}}() #0 { +// valid: define hidden spir_func void @{{.*main.*}}() #0 { [numthreads(1,1,1)] void main() diff --git a/clang/test/PCH/Inputs/ignored-pch.h b/clang/test/PCH/Inputs/ignored-pch.h new file mode 100644 index 000000000000..56047037c331 --- /dev/null +++ b/clang/test/PCH/Inputs/ignored-pch.h @@ -0,0 +1,6 @@ +#ifndef IGNORED_PCH_H +#define IGNORED_PCH_H +inline int f() { + return 42; +} +#endif // IGNORED_PCH_H diff --git a/clang/test/PCH/ignored-pch.c b/clang/test/PCH/ignored-pch.c new file mode 100644 index 000000000000..c6ef3fe74cee --- /dev/null +++ b/clang/test/PCH/ignored-pch.c @@ -0,0 +1,109 @@ +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -o %t.ll +// RUN: ls %t.pch +// RUN: ls %t.ll + +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -o %t.pch +// RUN: %clang %s -emit-ast -include-pch %t.pch -o %t.ll +// RUN: ls %t.pch +// RUN: ls %t.ll + +// Check that -ignore-pch causes -emit-pch and -include-pch options to be ignored. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -emit-ast %s -include-pch %t.pch -ignore-pch -o %t.ll +// RUN: not ls %t.ll + +// Check that -ignore-pch works for multiple PCH related options. +// Test with -building-pch-with-obj. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -building-pch-with-obj -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -Xclang -building-pch-with-obj -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fallow-pch-with-compiler-errors. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -fallow-pch-with-compiler-errors -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -Xclang -fallow-pch-with-compiler-errors -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fallow-pch-with-different-modules-cache-path. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -fallow-pch-with-different-modules-cache-path -o %t.pch +// RUN: %clang -S -emit-llvm %s -ignore-pch -include-pch %t.pch -Xclang -fallow-pch-with-different-modules-cache-path -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fpch-codegen. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -fpch-codegen -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -fpch-codegen -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fpch-debuginfo. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -fpch-debuginfo -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -fpch-debuginfo -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fpch-instantiate-templates. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -fpch-instantiate-templates -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -fpch-instantiate-templates -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fno-pch-timestamp. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -fno-pch-timestamp -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -Xclang -fno-pch-timestamp -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -fno-validate-pch. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -fno-validate-pch -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -Xclang -fno-validate-pch -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -relocatable-pch. +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -relocatable-pch -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -relocatable-pch -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + +// Test with -pch-through-hdrstop-create/-pch-through-hdrstop-use +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -ignore-pch -Xclang -pch-through-hdrstop-create -o %t.pch +// RUN: %clang -S -emit-llvm %s -include-pch %t.pch -ignore-pch -Xclang -pch-through-hdrstop-use -o %t.ll +// RUN: not ls %t.pch +// RUN: ls %t.ll + + +// Test with AST dump output: +// RUN: rm -rf %t.pch %t.ll +// RUN: %clang -x c-header %S/Inputs/ignored-pch.h -o %t.pch +// RUN: %clang %s -include-pch %t.pch -Xclang -ast-dump-all -c | FileCheck --check-prefix=CHECK-AST-PCH %s +// RUN: %clang %s -include-pch %t.pch -ignore-pch -Xclang -ast-dump-all -c | FileCheck --check-prefix=CHECK-AST %s + +// CHECK-AST-PCH: +// CHECK-AST-NOT: + +#pragma hdrstop +#include "Inputs/ignored-pch.h" +int main() { + return f(); +} diff --git a/clang/test/Parser/cxx-invalid-using-decl-in-constexpr-crash.cpp b/clang/test/Parser/cxx-invalid-using-decl-in-constexpr-crash.cpp new file mode 100644 index 000000000000..94fa8c8c820a --- /dev/null +++ b/clang/test/Parser/cxx-invalid-using-decl-in-constexpr-crash.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// issue144264 +constexpr void test() +{ + using TT = struct T[; + // expected-error@-1 {{expected expression}} +} diff --git a/clang/test/Parser/cxx11-base-spec-attributes.cpp b/clang/test/Parser/cxx11-base-spec-attributes.cpp index 7338c5116c16..6f2f54ead62b 100644 --- a/clang/test/Parser/cxx11-base-spec-attributes.cpp +++ b/clang/test/Parser/cxx11-base-spec-attributes.cpp @@ -7,4 +7,4 @@ struct D : [[]] public virtual A {}; struct E : public [[]] virtual A {}; // expected-error {{an attribute list cannot appear here}} struct F : virtual [[]] public A {}; // expected-error {{an attribute list cannot appear here}} struct G : [[noreturn]] A {}; // expected-error {{'noreturn' attribute cannot be applied to a base specifier}} -struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'foobar' ignored}} +struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'unknown::foobar' ignored}} diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 3e2526979be8..b7a8d30bd16c 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-unknown-linux-gnu -verify=expected,cxx2c,post2b -fcxx-exceptions // RUN: not %clang_cc1 -std=c++17 %s -triple x86_64-unknown-linux-gnu -emit-llvm-only -fcxx-exceptions -struct S { int a, b, c; }; +struct S { int a, b, c; }; // expected-note 2 {{'S::a' declared here}} // A simple-declaration can be a decompsition declaration. namespace SimpleDecl { @@ -32,7 +32,7 @@ namespace ForRangeDecl { namespace OtherDecl { // A parameter-declaration is not a simple-declaration. // This parses as an array declaration. - void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error {{'a'}} + void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error 1+{{'a'}} void g() { // A condition is allowed as a Clang extension. @@ -46,7 +46,7 @@ namespace OtherDecl { // An exception-declaration is not a simple-declaration. try {} - catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error {{'a'}} + catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error 1+{{'a'}} } // A member-declaration is not a simple-declaration. diff --git a/clang/test/Parser/cxx1z-fold-expressions.cpp b/clang/test/Parser/cxx1z-fold-expressions.cpp index 4a329646b799..d798a9cbb99b 100644 --- a/clang/test/Parser/cxx1z-fold-expressions.cpp +++ b/clang/test/Parser/cxx1z-fold-expressions.cpp @@ -37,14 +37,14 @@ template int bad12() { return (... N); } // expected-error {{expected template void as_operand_of_cast(int a, T ...t) { return - (int)(a + ... + undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}} + (int)(a + ... + undeclared_junk) + // expected-error {{undeclared}} (int)(t + ... + undeclared_junk) + // expected-error {{undeclared}} - (int)(... + undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}} + (int)(... + undeclared_junk) + // expected-error {{undeclared}} (int)(undeclared_junk + ...) + // expected-error {{undeclared}} (int)(a + ...) + // expected-error {{does not contain any unexpanded}} (int)(a, ...) + // expected-error {{does not contain any unexpanded}} (int)(..., a) + // expected-error {{does not contain any unexpanded}} - (int)(a, ..., undeclared_junk) + // expected-error {{undeclared}} expected-error {{does not contain any unexpanded}} + (int)(a, ..., undeclared_junk) + // expected-error {{undeclared}} (int)(t, ...) + (int)(..., t) + (int)(t, ..., a); diff --git a/clang/test/Parser/cxx2c-pack-indexing.cpp b/clang/test/Parser/cxx2c-pack-indexing.cpp index 72e286322fa9..79069a86ea70 100644 --- a/clang/test/Parser/cxx2c-pack-indexing.cpp +++ b/clang/test/Parser/cxx2c-pack-indexing.cpp @@ -69,7 +69,8 @@ template requires( ); // expected-error {{expected expression}} struct SS { void f( ) { - (*p).~T...[](); // expected-error {{use of undeclared identifier 'p'}} + (*p).~T...[](); // expected-error {{use of undeclared identifier 'p'}} \ + expected-error {{undeclared identifier 'T' in destructor name}} } }; } diff --git a/clang/test/Parser/macro-expansion-recovery.cpp b/clang/test/Parser/macro-expansion-recovery.cpp new file mode 100644 index 000000000000..6826cc04e4df --- /dev/null +++ b/clang/test/Parser/macro-expansion-recovery.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace GH143216 { +#define A x y +enum { A }; // expected-error {{missing ',' between enumerators}} + +#define B x y +void f() { + int a[2]; + auto [B] = a; // expected-error {{expected ','}} +} + +#define C class D; +D C; // expected-error {{expected unqualified-id}} \ + // expected-error {{expected '>'}} \ + // expected-note {{to match this '<'}} + +#define E F::{ +class F { E }}; // expected-error {{expected identifier}} \ + // expected-error {{expected member name or ';' after declaration specifiers}} +} diff --git a/clang/test/Parser/objc-foreach-syntax.m b/clang/test/Parser/objc-foreach-syntax.m index 2158d8062f6c..1ff84f393b9f 100644 --- a/clang/test/Parser/objc-foreach-syntax.m +++ b/clang/test/Parser/objc-foreach-syntax.m @@ -21,6 +21,5 @@ MyList * el; static int test7(id keys) { - for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}} \ - // expected-error {{expected ';' in 'for' statement specifier}} + for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}} } diff --git a/clang/test/Parser/objcxx11-attributes.mm b/clang/test/Parser/objcxx11-attributes.mm index d7ba609ebd74..88fa3103593e 100644 --- a/clang/test/Parser/objcxx11-attributes.mm +++ b/clang/test/Parser/objcxx11-attributes.mm @@ -57,7 +57,7 @@ void f(X *noreturn) { template void f(Ts ...x) { [[test::foo(bar, baz)...]]; // expected-error {{attribute 'foo' cannot be used as an attribute pack}} \ - // expected-warning {{unknown attribute 'foo' ignored}} + // expected-warning {{unknown attribute 'test::foo' ignored}} [[used(x)...]]; // expected-error {{attribute 'used' cannot be used as an attribute pack}} \ // expected-warning {{unknown attribute 'used' ignored}} diff --git a/clang/test/Parser/opencl-atomics-cl20.cl b/clang/test/Parser/opencl-atomics-cl20.cl index 2648142f28e7..2cd2c6ca133e 100644 --- a/clang/test/Parser/opencl-atomics-cl20.cl +++ b/clang/test/Parser/opencl-atomics-cl20.cl @@ -39,23 +39,17 @@ void atomic_types_test(void) { // expected-error@-11 {{use of undeclared identifier 'atomic_ulong'}} // expected-error@-11 {{use of undeclared identifier 'atomic_double'}} #if defined(LANG_VER_OK) -// expected-error@-15 {{expected ';' after expression}} -// expected-error@-16 {{use of undeclared identifier 'l'}} -// expected-error@-16 {{expected ';' after expression}} -// expected-error@-17 {{use of undeclared identifier 'ul'}} #endif #if !defined(LANG_VER_OK) || defined(__SPIR64__) -// expected-error@-18 {{use of undeclared identifier 'atomic_size_t'}} -// expected-error@-16 {{use of undeclared identifier 'atomic_ptrdiff_t'}} +// expected-error@-14 {{use of undeclared identifier 'atomic_size_t'}} +// expected-error@-12 {{use of undeclared identifier 'atomic_ptrdiff_t'}} #if !defined(LANG_VER_OK) -// expected-error@-20 {{use of undeclared identifier 'atomic_intptr_t'}} -// expected-error@-20 {{use of undeclared identifier 'atomic_uintptr_t'}} +// expected-error@-16 {{use of undeclared identifier 'atomic_intptr_t'}} +// expected-error@-16 {{use of undeclared identifier 'atomic_uintptr_t'}} #else -// expected-error@-24 {{expected ';' after expression}} -// expected-error@-25 {{use of undeclared identifier 's'}} -// expected-error@-25 {{unknown type name 'atomic_intptr_t'; did you mean 'atomic_int'?}} +// expected-error@-19 {{unknown type name 'atomic_intptr_t'; did you mean 'atomic_int'?}} // expected-note@* {{'atomic_int' declared here}} -// expected-error@-26 {{unknown type name 'atomic_uintptr_t'; did you mean 'atomic_uint'?}} +// expected-error@-20 {{unknown type name 'atomic_uintptr_t'; did you mean 'atomic_uint'?}} // expected-note@* {{'atomic_uint' declared here}} #endif #endif diff --git a/clang/test/Parser/recovery.c b/clang/test/Parser/recovery.c index 6fdbedffd236..0d86bd0608bf 100644 --- a/clang/test/Parser/recovery.c +++ b/clang/test/Parser/recovery.c @@ -11,7 +11,7 @@ float test2241[2] = { static void f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; // expected-error {{identifier}} - s = g (p, __builtin_va_arg(v, int)); // expected-error {{identifier}} + s = g (p, __builtin_va_arg(v, int)); // expected-error {{identifier}} expected-error {{extraneous ')' before ';'}} } diff --git a/clang/test/Parser/switch-recovery.cpp b/clang/test/Parser/switch-recovery.cpp index baf703cd03ae..40712799933c 100644 --- a/clang/test/Parser/switch-recovery.cpp +++ b/clang/test/Parser/switch-recovery.cpp @@ -104,7 +104,7 @@ void test9(int x) { // expected-note {{'x' declared here}} expected-error {{expected expression}} 8:: x; // expected-error {{expected ';' after expression}} \ expected-error {{no member named 'x' in the global namespace; did you mean simply 'x'?}} \ - expected-warning {{expression result unused}} + expected-warning 2 {{expression result unused}} 9:: :y; // expected-error {{expected ';' after expression}} \ expected-error {{expected unqualified-id}} \ expected-warning {{expression result unused}} @@ -229,3 +229,16 @@ void fn1() { } } // expected-error{{expected statement}} } + +namespace GH143216 { +#define FOO 1 case 3: + +int f(int x) { + switch (x) { + case FOO // expected-error {{expected ':' after 'case'}} + return 0; + default: + return 1; + } +} +} diff --git a/clang/test/Parser/switch-typo-correction.cpp b/clang/test/Parser/switch-typo-correction.cpp index ebf1c18f2b86..95d610b9cdd2 100644 --- a/clang/test/Parser/switch-typo-correction.cpp +++ b/clang/test/Parser/switch-typo-correction.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -namespace c { double xxx; } // expected-note{{'c::xxx' declared here}} +namespace c { double xxx; } namespace d { float xxx; } namespace z { namespace xxx {} } void crash() { - switch (xxx) {} // expected-error{{use of undeclared identifier 'xxx'; did you mean }} + switch (xxx) {} // expected-error{{use of undeclared identifier 'xxx'}} } diff --git a/clang/test/ParserOpenACC/parse-cache-construct.cpp b/clang/test/ParserOpenACC/parse-cache-construct.cpp index a5a1e58028c3..948f2e30f149 100644 --- a/clang/test/ParserOpenACC/parse-cache-construct.cpp +++ b/clang/test/ParserOpenACC/parse-cache-construct.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 %s -verify -fopenacc namespace NS { - static char* NSArray;// expected-note{{declared here}} - static int NSInt;// expected-note 2{{declared here}} + static char* NSArray; // expected-note {{'NS::NSArray' declared here}} + static int NSInt; // expected-note 2 {{'NS::NSInt' declared here}} } char *getArrayPtr(); template @@ -21,17 +21,17 @@ void func() { } for (int i = 0; i < 10; ++i) { - // expected-error@+1{{use of undeclared identifier 'NSArray'; did you mean 'NS::NSArray'}} + // expected-error@+1{{use of undeclared identifier 'NSArray'}} #pragma acc cache(NSArray[NS::NSInt : NS::NSInt]) } for (int i = 0; i < 10; ++i) { - // expected-error@+1{{use of undeclared identifier 'NSInt'; did you mean 'NS::NSInt'}} + // expected-error@+1{{use of undeclared identifier 'NSInt'}} #pragma acc cache(NS::NSArray[NSInt : NS::NSInt]) } for (int i = 0; i < 10; ++i) { - // expected-error@+1{{use of undeclared identifier 'NSInt'; did you mean 'NS::NSInt'}} + // expected-error@+1{{use of undeclared identifier 'NSInt'}} #pragma acc cache(NS::NSArray[NS::NSInt : NSInt]) } } diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 6d771e858d24..a9ad7ab176cb 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -347,9 +347,7 @@ void SelfUpdate() { #pragma acc update host(s) self for(int i = 0; i < 5;++i) {} - // expected-error@+3{{use of undeclared identifier 'zero'}} - // expected-error@+2{{expected ','}} - // expected-error@+1{{expected expression}} + // expected-error@+1{{use of undeclared identifier 'zero'}} #pragma acc update self(zero : s.array[s.value : 5], s.value), if_present for(int i = 0; i < 5;++i) {} @@ -453,8 +451,6 @@ void VarListClauses() { #pragma acc parallel copy(always, alwaysin, always: HasMem.MemArr[3:]) self for(int i = 0; i < 5;++i) {} - // expected-error@+3{{use of undeclared identifier 'always'}} - // expected-error@+2{{use of undeclared identifier 'alwaysin'}} // expected-error@+1{{use of undeclared identifier 'always'}} #pragma acc parallel copy(always, alwaysin, always, HasMem.MemArr[3:]) self for(int i = 0; i < 5;++i) {} @@ -591,8 +587,7 @@ void VarListClauses() { #pragma acc serial copyout(zero : s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'zero'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'zero'}} #pragma acc serial copyout(zero s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} @@ -608,8 +603,7 @@ void VarListClauses() { #pragma acc serial copyout(invalid:s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'invalid'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'invalid'}} #pragma acc serial copyout(invalid s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} @@ -657,8 +651,7 @@ void VarListClauses() { #pragma acc serial create(zero : s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'zero'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'zero'}} #pragma acc serial create(zero s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} @@ -674,8 +667,7 @@ void VarListClauses() { #pragma acc serial create(invalid:s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'invalid'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'invalid'}} #pragma acc serial create(invalid s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} @@ -700,8 +692,7 @@ void VarListClauses() { #pragma acc serial copyin(readonly : s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'readonly'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'readonly'}} #pragma acc serial copyin(readonly s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} @@ -717,8 +708,7 @@ void VarListClauses() { #pragma acc serial copyin(invalid:s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{use of undeclared identifier 'invalid'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'invalid'}} #pragma acc serial copyin(invalid s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} diff --git a/clang/test/ParserOpenACC/parse-constructs.cpp b/clang/test/ParserOpenACC/parse-constructs.cpp index 814f6a1fd09f..69b04bcbad9e 100644 --- a/clang/test/ParserOpenACC/parse-constructs.cpp +++ b/clang/test/ParserOpenACC/parse-constructs.cpp @@ -18,13 +18,13 @@ namespace NS { #pragma acc routine(NS::foo) seq // expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}} -// expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}} +// expected-error@+1{{OpenACC routine name 'templ' names a set of overloads}} #pragma acc routine(templ) seq // expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}} #pragma acc routine(NS::templ) seq // expected-error@+2{{use of undeclared identifier 'templ'; did you mean 'NS::templ'?}} -// expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}} +// expected-error@+1{{OpenACC routine name 'templ' names a set of overloads}} #pragma acc routine(templ) seq // expected-error@+1{{OpenACC routine name 'NS::templ' names a set of overloads}} #pragma acc routine(NS::templ) seq diff --git a/clang/test/ParserOpenACC/parse-wait-clause.c b/clang/test/ParserOpenACC/parse-wait-clause.c index 16e31a67c094..5c006b4379a2 100644 --- a/clang/test/ParserOpenACC/parse-wait-clause.c +++ b/clang/test/ParserOpenACC/parse-wait-clause.c @@ -85,19 +85,16 @@ void func() { #pragma acc parallel wait (devnum: i + j:queues:) clause-list {} - // expected-error@+4{{use of undeclared identifier 'devnum'}} - // expected-error@+3{{expected ','}} + // expected-error@+3{{use of undeclared identifier 'devnum'}} // expected-error@+2{{expected ')'}} // expected-note@+1{{to match this '('}} #pragma acc parallel wait (queues:devnum: i + j {} - // expected-error@+2{{expected ','}} // expected-error@+1{{use of undeclared identifier 'devnum'}} #pragma acc parallel wait (queues:devnum: i + j) {} - // expected-error@+3{{expected ','}} // expected-error@+2{{use of undeclared identifier 'devnum'}} // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait (queues:devnum: i + j) clause-list diff --git a/clang/test/ParserOpenACC/parse-wait-construct.c b/clang/test/ParserOpenACC/parse-wait-construct.c index 491c3bee4ac5..27a3a02dc263 100644 --- a/clang/test/ParserOpenACC/parse-wait-construct.c +++ b/clang/test/ParserOpenACC/parse-wait-construct.c @@ -68,18 +68,15 @@ void func() { // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum: i + j:queues:) clause-list - // expected-error@+4{{use of undeclared identifier 'devnum'}} - // expected-error@+3{{expected ','}} + // expected-error@+3{{use of undeclared identifier 'devnum'}} // expected-error@+2{{expected ')'}} // expected-note@+1{{to match this '('}} #pragma acc wait (queues:devnum: i + j - // expected-error@+2{{use of undeclared identifier 'devnum'}} - // expected-error@+1{{expected ','}} + // expected-error@+1{{use of undeclared identifier 'devnum'}} #pragma acc wait (queues:devnum: i + j) - // expected-error@+3{{use of undeclared identifier 'devnum'}} - // expected-error@+2{{expected ','}} + // expected-error@+2{{use of undeclared identifier 'devnum'}} // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (queues:devnum: i + j) clause-list diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c index 4cb9b6ce53b0..fd83e4b689a2 100644 --- a/clang/test/Preprocessor/aarch64-target-features.c +++ b/clang/test/Preprocessor/aarch64-target-features.c @@ -744,7 +744,10 @@ // CHECK-SMEB16B16: __ARM_FEATURE_SME2 1 // CHECK-SMEB16B16: __ARM_FEATURE_SME_B16B16 1 // CHECK-SMEB16B16: __ARM_FEATURE_SVE_B16B16 1 -// + +// RUN: %clang --target=aarch64 -march=armv9-a+cssc -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-CSSC %s +// CHECK-CSSC: __ARM_FEATURE_CSSC 1 + // RUN: %clang --target=aarch64 -march=armv9-a+fp8 -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-FP8 %s // CHECK-FP8: __ARM_FEATURE_FP8 1 diff --git a/clang/test/Preprocessor/init-loongarch.c b/clang/test/Preprocessor/init-loongarch.c index ac461b371162..71a266b8a915 100644 --- a/clang/test/Preprocessor/init-loongarch.c +++ b/clang/test/Preprocessor/init-loongarch.c @@ -946,6 +946,10 @@ // RUN: | FileCheck --match-full-lines --check-prefix=MNO-LSX %s // RUN: %clang --target=loongarch64 -mno-lasx -mno-lsx -x c -E -dM %s -o - \ // RUN: | FileCheck --match-full-lines --check-prefix=MNO-LSX %s +// RUN: %clang --target=loongarch64 -march=la464 -mno-lsx -x c -E -dM %s -o - \ +// RUN: | FileCheck --match-full-lines --check-prefix=MNO-LSX %s +// RUN: %clang --target=loongarch64 -mno-lsx -march=la464 -x c -E -dM %s -o - \ +// RUN: | FileCheck --match-full-lines --check-prefix=MNO-LSX %s // MNO-LSX-NOT: #define __loongarch_asx // MNO-LSX-NOT: #define __loongarch_simd_width // MNO-LSX-NOT: #define __loongarch_sx diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index 031a6c1a755b..bed39dc3e34d 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -1622,6 +1622,11 @@ // RUN: %clang_cc1 -x c -std=c99 -E -dM -ffreestanding -triple=amd64-unknown-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD-STDC-N %s // OPENBSD-STDC-N-NOT:#define __STDC_NO_THREADS__ 1 // +// RUN: %clang_cc1 -triple=aarch64-unknown-managarm-mlibc -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix MANAGARM %s +// RUN: %clang_cc1 -triple=riscv64-unknown-managarm-mlibc -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix MANAGARM %s +// RUN: %clang_cc1 -triple=x86_64-unknown-managarm-mlibc -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix MANAGARM %s +// MANAGARM: #define __managarm__ 1 + // RUN: %clang_cc1 -E -dM -ffreestanding -triple=xcore-none-none < /dev/null | FileCheck -match-full-lines -check-prefix XCORE %s // XCORE:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ // XCORE:#define __LITTLE_ENDIAN__ 1 diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index 2d17891071aa..86d51820ae5b 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -2102,7 +2102,7 @@ // CHECK_ADL_M32: #define __AVX__ 1 // CHECK_ADL_M32: #define __BMI2__ 1 // CHECK_ADL_M32: #define __BMI__ 1 -// CHECK_ADL_M32: #define __CLDEMOTE__ 1 +// CHECK_ADL_M32-NOT: #define __CLDEMOTE__ 1 // CHECK_ADL_M32: #define __CLFLUSHOPT__ 1 // CHECK_ADL_M32: #define __CLWB__ 1 // CHECK_ADL_M32: #define __F16C__ 1 @@ -2173,7 +2173,7 @@ // CHECK_ADL_M64: #define __AVX__ 1 // CHECK_ADL_M64: #define __BMI2__ 1 // CHECK_ADL_M64: #define __BMI__ 1 -// CHECK_ADL_M64: #define __CLDEMOTE__ 1 +// CHECK_ADL_M64-NOT: #define __CLDEMOTE__ 1 // CHECK_ADL_M64: #define __CLFLUSHOPT__ 1 // CHECK_ADL_M64: #define __CLWB__ 1 // CHECK_ADL_M64: #define __F16C__ 1 @@ -2556,209 +2556,211 @@ // RUN: %clang -march=sierraforest -m32 -E -dM %s -o - 2>&1 \ // RUN: --target=i386 \ -// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SRF_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M32,CHECK_SRF_M32 // RUN: %clang -march=grandridge -m32 -E -dM %s -o - 2>&1 \ // RUN: --target=i386 \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M32,CHECK_SRF_M32 // RUN: %clang -march=arrowlake -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SRF_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_ARL_M32 // RUN: %clang -march=arrowlake-s -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M32,CHECK_ARLS_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M32,CHECK_ARLS_M32 // RUN: %clang -march=lunarlake -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M32,CHECK_ARLS_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M32,CHECK_ARLS_M32 // RUN: %clang -march=pantherlake -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M32,CHECK_ARLS_M32,CHECK_PTL_M32 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M32,CHECK_ARLS_M32,CHECK_PTL_M32 // RUN: %clang -march=clearwaterforest -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ // RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M32,CHECK_ARLS_M32,CHECK_PTL_M32,CHECK_CWF_M32 -// CHECK_SRF_M32: #define __ADX__ 1 -// CHECK_SRF_M32: #define __AES__ 1 -// CHECK_SRF_M32: #define __AVX2__ 1 -// CHECK_SRF_M32-NOT: AVX512 -// CHECK_SRF_M32: #define __AVXIFMA__ 1 -// CHECK_SRF_M32: #define __AVXNECONVERT__ 1 -// CHECK_SRF_M32-NOT: #define __AVXVNNIINT16__ 1 +// CHECK_ARL_M32: #define __ADX__ 1 +// CHECK_ARL_M32: #define __AES__ 1 +// CHECK_ARL_M32: #define __AVX2__ 1 +// CHECK_ARL_M32-NOT: AVX512 +// CHECK_ARL_M32: #define __AVXIFMA__ 1 +// CHECK_ARL_M32: #define __AVXNECONVERT__ 1 +// CHECK_ARL_M32-NOT: #define __AVXVNNIINT16__ 1 // CHECK_ARLS_M32: #define __AVXVNNIINT16__ 1 -// CHECK_SRF_M32: #define __AVXVNNIINT8__ 1 -// CHECK_SRF_M32: #define __AVXVNNI__ 1 -// CHECK_SRF_M32: #define __AVX__ 1 -// CHECK_SRF_M32: #define __BMI2__ 1 -// CHECK_SRF_M32: #define __BMI__ 1 +// CHECK_ARL_M32: #define __AVXVNNIINT8__ 1 +// CHECK_ARL_M32: #define __AVXVNNI__ 1 +// CHECK_ARL_M32: #define __AVX__ 1 +// CHECK_ARL_M32: #define __BMI2__ 1 +// CHECK_ARL_M32: #define __BMI__ 1 +// CHECK_ARLS_M32-NOT: __CLDEMOTE__ // CHECK_SRF_M32: #define __CLDEMOTE__ 1 -// CHECK_SRF_M32: #define __CLFLUSHOPT__ 1 -// CHECK_SRF_M32: #define __CLWB__ 1 -// CHECK_SRF_M32: #define __CMPCCXADD__ 1 -// CHECK_SRF_M32: #define __ENQCMD__ 1 -// CHECK_SRF_M32: #define __F16C__ 1 -// CHECK_SRF_M32: #define __FMA__ 1 -// CHECK_SRF_M32: #define __FSGSBASE__ 1 -// CHECK_SRF_M32: #define __FXSR__ 1 -// CHECK_SRF_M32: #define __GFNI__ 1 -// CHECK_SRF_M32: #define __HRESET__ 1 -// CHECK_SRF_M32: #define __INVPCID__ 1 -// CHECK_SRF_M32: #define __KL__ 1 -// CHECK_SRF_M32: #define __LZCNT__ 1 -// CHECK_SRF_M32: #define __MMX__ 1 -// CHECK_SRF_M32: #define __MOVBE__ 1 -// CHECK_SRF_M32: #define __MOVDIR64B__ 1 -// CHECK_SRF_M32: #define __MOVDIRI__ 1 -// CHECK_SRF_M32: #define __PCLMUL__ 1 -// CHECK_SRF_M32: #define __PCONFIG__ 1 -// CHECK_SRF_M32: #define __PKU__ 1 -// CHECK_SRF_M32: #define __POPCNT__ 1 -// CHECK_SRF_M32-NOT: #define __PREFETCHI__ 1 +// CHECK_ARL_M32: #define __CLFLUSHOPT__ 1 +// CHECK_ARL_M32: #define __CLWB__ 1 +// CHECK_ARL_M32: #define __CMPCCXADD__ 1 +// CHECK_ARL_M32: #define __ENQCMD__ 1 +// CHECK_ARL_M32: #define __F16C__ 1 +// CHECK_ARL_M32: #define __FMA__ 1 +// CHECK_ARL_M32: #define __FSGSBASE__ 1 +// CHECK_ARL_M32: #define __FXSR__ 1 +// CHECK_ARL_M32: #define __GFNI__ 1 +// CHECK_ARL_M32: #define __HRESET__ 1 +// CHECK_ARL_M32: #define __INVPCID__ 1 +// CHECK_ARL_M32: #define __KL__ 1 +// CHECK_ARL_M32: #define __LZCNT__ 1 +// CHECK_ARL_M32: #define __MMX__ 1 +// CHECK_ARL_M32: #define __MOVBE__ 1 +// CHECK_ARL_M32: #define __MOVDIR64B__ 1 +// CHECK_ARL_M32: #define __MOVDIRI__ 1 +// CHECK_ARL_M32: #define __PCLMUL__ 1 +// CHECK_ARL_M32: #define __PCONFIG__ 1 +// CHECK_ARL_M32: #define __PKU__ 1 +// CHECK_ARL_M32: #define __POPCNT__ 1 +// CHECK_ARL_M32-NOT: #define __PREFETCHI__ 1 // CHECK_ARLS_M32-NOT: #define __PREFETCHI__ 1 // CHECK_PTL_M32: #define __PREFETCHI__ 1 -// CHECK_SRF_M32: #define __PRFCHW__ 1 -// CHECK_SRF_M32: #define __PTWRITE__ 1 -// CHECK_SRF_M32-NOT: #define __RAOINT__ 1 -// CHECK_SRF_M32: #define __RDPID__ 1 -// CHECK_SRF_M32: #define __RDRND__ 1 -// CHECK_SRF_M32: #define __RDSEED__ 1 -// CHECK_SRF_M32: #define __SERIALIZE__ 1 -// CHECK_SRF_M32: #define __SGX__ 1 -// CHECK_SRF_M32-NOT: #define __SHA512__ 1 +// CHECK_ARL_M32: #define __PRFCHW__ 1 +// CHECK_ARL_M32: #define __PTWRITE__ 1 +// CHECK_ARL_M32-NOT: #define __RAOINT__ 1 +// CHECK_ARL_M32: #define __RDPID__ 1 +// CHECK_ARL_M32: #define __RDRND__ 1 +// CHECK_ARL_M32: #define __RDSEED__ 1 +// CHECK_ARL_M32: #define __SERIALIZE__ 1 +// CHECK_ARL_M32: #define __SGX__ 1 +// CHECK_ARL_M32-NOT: #define __SHA512__ 1 // CHECK_ARLS_M32: #define __SHA512__ 1 -// CHECK_SRF_M32: #define __SHA__ 1 -// CHECK_SRF_M32: #define __SHSTK__ 1 -// CHECK_SRF_M32-NOT: #define __SM3__ 1 +// CHECK_ARL_M32: #define __SHA__ 1 +// CHECK_ARL_M32: #define __SHSTK__ 1 +// CHECK_ARL_M32-NOT: #define __SM3__ 1 // CHECK_ARLS_M32: #define __SM3__ 1 -// CHECK_SRF_M32-NOT: #define __SM4__ 1 +// CHECK_ARL_M32-NOT: #define __SM4__ 1 // CHECK_ARLS_M32: #define __SM4__ 1 -// CHECK_SRF_M32: #define __SSE2__ 1 -// CHECK_SRF_M32: #define __SSE3__ 1 -// CHECK_SRF_M32: #define __SSE4_1__ 1 -// CHECK_SRF_M32: #define __SSE4_2__ 1 -// CHECK_SRF_M32: #define __SSE_MATH__ 1 -// CHECK_SRF_M32: #define __SSE__ 1 -// CHECK_SRF_M32: #define __SSSE3__ 1 -// CHECK_SRF_M32: #define __UINTR__ 1 -// CHECK_SRF_M32-NOT: #define __USERMSR__ 1 +// CHECK_ARL_M32: #define __SSE2__ 1 +// CHECK_ARL_M32: #define __SSE3__ 1 +// CHECK_ARL_M32: #define __SSE4_1__ 1 +// CHECK_ARL_M32: #define __SSE4_2__ 1 +// CHECK_ARL_M32: #define __SSE_MATH__ 1 +// CHECK_ARL_M32: #define __SSE__ 1 +// CHECK_ARL_M32: #define __SSSE3__ 1 +// CHECK_ARL_M32: #define __UINTR__ 1 +// CHECK_ARL_M32-NOT: #define __USERMSR__ 1 // CHECK_ARLS_M32-NOT: #define __USERMSR__ 1 // CHECK_PTL_M32-NOT: #define __USERMSR__ 1 // CHECK_CWF_M32: #define __USERMSR__ 1 -// CHECK_SRF_M32: #define __VAES__ 1 -// CHECK_SRF_M32: #define __VPCLMULQDQ__ 1 -// CHECK_SRF_M32: #define __WAITPKG__ 1 -// CHECK_SRF_M32: #define __WIDEKL__ 1 -// CHECK_SRF_M32: #define __XSAVEC__ 1 -// CHECK_SRF_M32: #define __XSAVEOPT__ 1 -// CHECK_SRF_M32: #define __XSAVES__ 1 -// CHECK_SRF_M32: #define __XSAVE__ 1 -// CHECK_SRF_M32: #define __corei7 1 -// CHECK_SRF_M32: #define __corei7__ 1 -// CHECK_SRF_M32: #define __i386 1 -// CHECK_SRF_M32: #define __i386__ 1 -// CHECK_SRF_M32: #define __tune_corei7__ 1 -// CHECK_SRF_M32: #define i386 1 +// CHECK_ARL_M32: #define __VAES__ 1 +// CHECK_ARL_M32: #define __VPCLMULQDQ__ 1 +// CHECK_ARL_M32: #define __WAITPKG__ 1 +// CHECK_ARL_M32: #define __WIDEKL__ 1 +// CHECK_ARL_M32: #define __XSAVEC__ 1 +// CHECK_ARL_M32: #define __XSAVEOPT__ 1 +// CHECK_ARL_M32: #define __XSAVES__ 1 +// CHECK_ARL_M32: #define __XSAVE__ 1 +// CHECK_ARL_M32: #define __corei7 1 +// CHECK_ARL_M32: #define __corei7__ 1 +// CHECK_ARL_M32: #define __i386 1 +// CHECK_ARL_M32: #define __i386__ 1 +// CHECK_ARL_M32: #define __tune_corei7__ 1 +// CHECK_ARL_M32: #define i386 1 // RUN: %clang -march=sierraforest -m64 -E -dM %s -o - 2>&1 \ // RUN: --target=i386 \ -// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SRF_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_SRF_M64 // RUN: %clang -march=grandridge -m64 -E -dM %s -o - 2>&1 \ // RUN: --target=i386 \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_SRF_M64 // RUN: %clang -march=arrowlake -m64 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SRF_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_ARL_M64 // RUN: %clang -march=arrowlake-s -m64 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M64,CHECK_ARLS_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_ARLS_M64 // RUN: %clang -march=lunarlake -m64 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M64,CHECK_ARLS_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_ARLS_M64 // RUN: %clang -march=pantherlake -m64 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M64,CHECK_ARLS_M64,CHECK_PTL_M64 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_ARLS_M64,CHECK_PTL_M64 // RUN: %clang -march=clearwaterforest -m64 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ -// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_SRF_M64,CHECK_ARLS_M64,CHECK_PTL_M64,CHECK_CWF_M64 -// CHECK_SRF_M64: #define __ADX__ 1 -// CHECK_SRF_M64: #define __AES__ 1 -// CHECK_SRF_M64: #define __AVX2__ 1 -// CHECK_SRF_M64-NOT: AVX512 -// CHECK_SRF_M64: #define __AVXIFMA__ 1 -// CHECK_SRF_M64: #define __AVXNECONVERT__ 1 -// CHECK_SRF_M64-NOT: #define __AVXVNNIINT16__ 1 +// RUN: | FileCheck -match-full-lines %s -check-prefixes=CHECK_ARL_M64,CHECK_SRF_M64,CHECK_ARLS_M64,CHECK_PTL_M64,CHECK_CWF_M64 +// CHECK_ARL_M64: #define __ADX__ 1 +// CHECK_ARL_M64: #define __AES__ 1 +// CHECK_ARL_M64: #define __AVX2__ 1 +// CHECK_ARL_M64-NOT: AVX512 +// CHECK_ARL_M64: #define __AVXIFMA__ 1 +// CHECK_ARL_M64: #define __AVXNECONVERT__ 1 +// CHECK_ARL_M64-NOT: #define __AVXVNNIINT16__ 1 // CHECK_ARLS_M64: #define __AVXVNNIINT16__ 1 -// CHECK_SRF_M64: #define __AVXVNNIINT8__ 1 -// CHECK_SRF_M64: #define __AVXVNNI__ 1 -// CHECK_SRF_M64: #define __AVX__ 1 -// CHECK_SRF_M64: #define __BMI2__ 1 -// CHECK_SRF_M64: #define __BMI__ 1 +// CHECK_ARL_M64: #define __AVXVNNIINT8__ 1 +// CHECK_ARL_M64: #define __AVXVNNI__ 1 +// CHECK_ARL_M64: #define __AVX__ 1 +// CHECK_ARL_M64: #define __BMI2__ 1 +// CHECK_ARL_M64: #define __BMI__ 1 +// CHECK_ARLS_M64-NOT: __CLDEMOTE__ // CHECK_SRF_M64: #define __CLDEMOTE__ 1 -// CHECK_SRF_M64: #define __CLFLUSHOPT__ 1 -// CHECK_SRF_M64: #define __CLWB__ 1 -// CHECK_SRF_M64: #define __CMPCCXADD__ 1 -// CHECK_SRF_M64: #define __ENQCMD__ 1 -// CHECK_SRF_M64: #define __F16C__ 1 -// CHECK_SRF_M64: #define __FMA__ 1 -// CHECK_SRF_M64: #define __FSGSBASE__ 1 -// CHECK_SRF_M64: #define __FXSR__ 1 -// CHECK_SRF_M64: #define __GFNI__ 1 -// CHECK_SRF_M64: #define __HRESET__ 1 -// CHECK_SRF_M64: #define __INVPCID__ 1 -// CHECK_SRF_M64: #define __KL__ 1 -// CHECK_SRF_M64: #define __LZCNT__ 1 -// CHECK_SRF_M64: #define __MMX__ 1 -// CHECK_SRF_M64: #define __MOVBE__ 1 -// CHECK_SRF_M64: #define __MOVDIR64B__ 1 -// CHECK_SRF_M64: #define __MOVDIRI__ 1 -// CHECK_SRF_M64: #define __PCLMUL__ 1 -// CHECK_SRF_M64: #define __PCONFIG__ 1 -// CHECK_SRF_M64: #define __PKU__ 1 -// CHECK_SRF_M64: #define __POPCNT__ 1 -// CHECK_SRF_M64-NOT: #define __PREFETCHI__ 1 +// CHECK_ARL_M64: #define __CLFLUSHOPT__ 1 +// CHECK_ARL_M64: #define __CLWB__ 1 +// CHECK_ARL_M64: #define __CMPCCXADD__ 1 +// CHECK_ARL_M64: #define __ENQCMD__ 1 +// CHECK_ARL_M64: #define __F16C__ 1 +// CHECK_ARL_M64: #define __FMA__ 1 +// CHECK_ARL_M64: #define __FSGSBASE__ 1 +// CHECK_ARL_M64: #define __FXSR__ 1 +// CHECK_ARL_M64: #define __GFNI__ 1 +// CHECK_ARL_M64: #define __HRESET__ 1 +// CHECK_ARL_M64: #define __INVPCID__ 1 +// CHECK_ARL_M64: #define __KL__ 1 +// CHECK_ARL_M64: #define __LZCNT__ 1 +// CHECK_ARL_M64: #define __MMX__ 1 +// CHECK_ARL_M64: #define __MOVBE__ 1 +// CHECK_ARL_M64: #define __MOVDIR64B__ 1 +// CHECK_ARL_M64: #define __MOVDIRI__ 1 +// CHECK_ARL_M64: #define __PCLMUL__ 1 +// CHECK_ARL_M64: #define __PCONFIG__ 1 +// CHECK_ARL_M64: #define __PKU__ 1 +// CHECK_ARL_M64: #define __POPCNT__ 1 +// CHECK_ARL_M64-NOT: #define __PREFETCHI__ 1 // CHECK_ARLS_M64-NOT: #define __PREFETCHI__ 1 // CHECK_PTL_M64: #define __PREFETCHI__ 1 -// CHECK_SRF_M64: #define __PRFCHW__ 1 -// CHECK_SRF_M64: #define __PTWRITE__ 1 -// CHECK_SRF_M64-NOT: #define __RAOINT__ 1 -// CHECK_SRF_M64: #define __RDPID__ 1 -// CHECK_SRF_M64: #define __RDRND__ 1 -// CHECK_SRF_M64: #define __RDSEED__ 1 -// CHECK_SRF_M64: #define __SERIALIZE__ 1 -// CHECK_SRF_M64: #define __SGX__ 1 -// CHECK_SRF_M64-NOT: #define __SHA512__ 1 +// CHECK_ARL_M64: #define __PRFCHW__ 1 +// CHECK_ARL_M64: #define __PTWRITE__ 1 +// CHECK_ARL_M64-NOT: #define __RAOINT__ 1 +// CHECK_ARL_M64: #define __RDPID__ 1 +// CHECK_ARL_M64: #define __RDRND__ 1 +// CHECK_ARL_M64: #define __RDSEED__ 1 +// CHECK_ARL_M64: #define __SERIALIZE__ 1 +// CHECK_ARL_M64: #define __SGX__ 1 +// CHECK_ARL_M64-NOT: #define __SHA512__ 1 // CHECK_ARLS_M64: #define __SHA512__ 1 -// CHECK_SRF_M64: #define __SHA__ 1 -// CHECK_SRF_M64: #define __SHSTK__ 1 -// CHECK_SRF_M64-NOT: #define __SM3__ 1 +// CHECK_ARL_M64: #define __SHA__ 1 +// CHECK_ARL_M64: #define __SHSTK__ 1 +// CHECK_ARL_M64-NOT: #define __SM3__ 1 // CHECK_ARLS_M64: #define __SM3__ 1 -// CHECK_SRF_M64-NOT: #define __SM4__ 1 +// CHECK_ARL_M64-NOT: #define __SM4__ 1 // CHECK_ARLS_M64: #define __SM4__ 1 -// CHECK_SRF_M64: #define __SSE2_MATH__ 1 -// CHECK_SRF_M64: #define __SSE2__ 1 -// CHECK_SRF_M64: #define __SSE3__ 1 -// CHECK_SRF_M64: #define __SSE4_1__ 1 -// CHECK_SRF_M64: #define __SSE4_2__ 1 -// CHECK_SRF_M64: #define __SSE_MATH__ 1 -// CHECK_SRF_M64: #define __SSE__ 1 -// CHECK_SRF_M64: #define __SSSE3__ 1 -// CHECK_SRF_M64: #define __UINTR__ 1 -// CHECK_SRF_M64-NOT: #define __USERMSR__ 1 +// CHECK_ARL_M64: #define __SSE2_MATH__ 1 +// CHECK_ARL_M64: #define __SSE2__ 1 +// CHECK_ARL_M64: #define __SSE3__ 1 +// CHECK_ARL_M64: #define __SSE4_1__ 1 +// CHECK_ARL_M64: #define __SSE4_2__ 1 +// CHECK_ARL_M64: #define __SSE_MATH__ 1 +// CHECK_ARL_M64: #define __SSE__ 1 +// CHECK_ARL_M64: #define __SSSE3__ 1 +// CHECK_ARL_M64: #define __UINTR__ 1 +// CHECK_ARL_M64-NOT: #define __USERMSR__ 1 // CHECK_ARLS_M64-NOT: #define __USERMSR__ 1 // CHECK_PTL_M64-NOT: #define __USERMSR__ 1 // CHECK_CWF_M64: #define __USERMSR__ 1 -// CHECK_SRF_M64: #define __VAES__ 1 -// CHECK_SRF_M64: #define __VPCLMULQDQ__ 1 -// CHECK_SRF_M64: #define __WAITPKG__ 1 -// CHECK_SRF_M64: #define __WIDEKL__ 1 -// CHECK_SRF_M64: #define __XSAVEC__ 1 -// CHECK_SRF_M64: #define __XSAVEOPT__ 1 -// CHECK_SRF_M64: #define __XSAVES__ 1 -// CHECK_SRF_M64: #define __XSAVE__ 1 -// CHECK_SRF_M64: #define __amd64 1 -// CHECK_SRF_M64: #define __amd64__ 1 -// CHECK_SRF_M64: #define __corei7 1 -// CHECK_SRF_M64: #define __corei7__ 1 -// CHECK_SRF_M64: #define __tune_corei7__ 1 -// CHECK_SRF_M64: #define __x86_64 1 -// CHECK_SRF_M64: #define __x86_64__ 1 +// CHECK_ARL_M64: #define __VAES__ 1 +// CHECK_ARL_M64: #define __VPCLMULQDQ__ 1 +// CHECK_ARL_M64: #define __WAITPKG__ 1 +// CHECK_ARL_M64: #define __WIDEKL__ 1 +// CHECK_ARL_M64: #define __XSAVEC__ 1 +// CHECK_ARL_M64: #define __XSAVEOPT__ 1 +// CHECK_ARL_M64: #define __XSAVES__ 1 +// CHECK_ARL_M64: #define __XSAVE__ 1 +// CHECK_ARL_M64: #define __amd64 1 +// CHECK_ARL_M64: #define __amd64__ 1 +// CHECK_ARL_M64: #define __corei7 1 +// CHECK_ARL_M64: #define __corei7__ 1 +// CHECK_ARL_M64: #define __tune_corei7__ 1 +// CHECK_ARL_M64: #define __x86_64 1 +// CHECK_ARL_M64: #define __x86_64__ 1 // RUN: %clang -march=geode -m32 -E -dM %s -o - 2>&1 \ // RUN: -target i386-unknown-linux \ diff --git a/clang/test/Preprocessor/predefined-macros-no-warnings.c b/clang/test/Preprocessor/predefined-macros-no-warnings.c index 4e3e29ccfa8a..fe27ed8814ee 100644 --- a/clang/test/Preprocessor/predefined-macros-no-warnings.c +++ b/clang/test/Preprocessor/predefined-macros-no-warnings.c @@ -14,6 +14,7 @@ // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-fuchsia // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-linux // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-linux-openhos +// RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-managarm // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-netbsd // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-openbsd // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple aarch64-win32-gnu @@ -108,6 +109,7 @@ // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple riscv64-fuchsia // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple riscv64-linux // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple riscv64-linux-openhos +// RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple riscv64-managarm // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple sparc // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple sparc-linux // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple sparc-solaris @@ -167,6 +169,7 @@ // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple x86_64-nacl // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple x86_64-ps4 // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple x86_64-ps5 +// RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple x86_64-managarm // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple spir // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple spir64 // RUN: %clang_cc1 %s -Eonly -Wsystem-headers -Werror -triple spirv32 diff --git a/clang/test/Preprocessor/riscv-target-features-andes.c b/clang/test/Preprocessor/riscv-target-features-andes.c index 3cd9b0435413..c66d4427b5cf 100644 --- a/clang/test/Preprocessor/riscv-target-features-andes.c +++ b/clang/test/Preprocessor/riscv-target-features-andes.c @@ -15,6 +15,14 @@ // RUN: -o - | FileCheck --check-prefix=CHECK-XANDESPERF %s // CHECK-XANDESPERF: __riscv_xandesperf 5000000{{$}} +// RUN: %clang --target=riscv32 \ +// RUN: -march=rv32i_xandesvbfhcvt -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XANDESVBFHCVT %s +// RUN: %clang --target=riscv64 \ +// RUN: -march=rv64i_xandesvbfhcvt -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XANDESVBFHCVT %s +// CHECK-XANDESVBFHCVT: __riscv_xandesvbfhcvt 5000000{{$}} + // RUN: %clang --target=riscv32 \ // RUN: -march=rv32i_xandesvpackfph -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-XANDESVPACKFPH %s diff --git a/clang/test/Sema/PR28181.c b/clang/test/Sema/PR28181.c index 8d0a4ad33562..7e9d5cc91038 100644 --- a/clang/test/Sema/PR28181.c +++ b/clang/test/Sema/PR28181.c @@ -5,9 +5,9 @@ struct spinlock_t { } audit_skb_queue; void fn1(void) { - audit_skb_queue = (lock); // expected-error {{use of undeclared identifier 'lock'; did you mean 'long'?}} -} // expected-error@-1 {{assigning to 'struct spinlock_t' from incompatible type ''}} + audit_skb_queue = (lock); // expected-error {{use of undeclared identifier 'lock'}} +} void fn2(void) { - audit_skb_queue + (lock); // expected-error {{use of undeclared identifier 'lock'; did you mean 'long'?}} -} // expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}} + audit_skb_queue + (lock); // expected-error {{use of undeclared identifier 'lock'}} +} diff --git a/clang/test/Sema/builtin-unary-fp.c b/clang/test/Sema/builtin-unary-fp.c index fb8e341156a5..9bfcb30b9eba 100644 --- a/clang/test/Sema/builtin-unary-fp.c +++ b/clang/test/Sema/builtin-unary-fp.c @@ -17,5 +17,4 @@ void a(void) { check(__builtin_fpclassify(0,0,0,0,0, (invalid))); // expected-error{{use of undeclared identifier 'invalid'}} check(__builtin_fpclassify(0,0,0,0,0, (inf))); // expected-error{{use of undeclared identifier 'inf'}} - // expected-error@-1{{reference to overloaded function could not be resolved}} } diff --git a/clang/test/Sema/c23-delayed-typo-correction-crashes.c b/clang/test/Sema/c23-delayed-typo-correction-crashes.c new file mode 100644 index 000000000000..6afd3fd32c36 --- /dev/null +++ b/clang/test/Sema/c23-delayed-typo-correction-crashes.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s + +void GH139913(...); +void GH139913_test() { + GH139913(CONCAT(foo, )); // expected-error {{use of undeclared identifier 'CONCAT'}} \ + expected-error {{use of undeclared identifier 'foo'}} \ + expected-error {{expected expression}} +} + +struct GH137867 { + char value; +}; +void GH137867_test() { + _Atomic(struct GH137867) t; + while (!atomic_load(&t.value)->value) // expected-error {{use of undeclared identifier 'atomic_load'}} \ + expected-error {{accessing a member of an atomic structure or union is undefined behavior}} + ; +} diff --git a/clang/test/Sema/delayed-typo-correction-crashes.c b/clang/test/Sema/delayed-typo-correction-crashes.c new file mode 100644 index 000000000000..81c966789ccb --- /dev/null +++ b/clang/test/Sema/delayed-typo-correction-crashes.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -ffixed-point -verify %s + +void GH137860_test(void) { + struct S { + char h; + }; + _Atomic struct S s = { .h = UINT8_MIN }; // expected-error {{use of undeclared identifier 'UINT8_MIN'}} + __c11_atomic_fetch_add(&s.h, UINT8_MIN); // expected-error {{use of undeclared identifier 'UINT8_MIN'}} \ + expected-error {{accessing a member of an atomic structure or union is undefined behavior}} +} + +int (^GH69470) (int i, int j) = ^(int i, int j) +{ return i / j; }/ j; // expected-error {{use of undeclared identifier 'j'}} + +void GH69874(void) { + *a = (a_struct){0}; // expected-error {{use of undeclared identifier 'a'}} \ + expected-error {{use of undeclared identifier 'a_struct'}} +} diff --git a/clang/test/Sema/gh87867.c b/clang/test/Sema/gh87867.c new file mode 100644 index 000000000000..0568c734424c --- /dev/null +++ b/clang/test/Sema/gh87867.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s + +// Compound literal doesn't need a constant expression inside a initializer-list if it is already inside a function +// see: https://github.com/llvm/llvm-project/issues/87867 +int foo(int *a, int b) { + return 0; +} + +int x; +struct{int t;} a = (struct { + typeof(foo(&(struct { int t; }){.t = x}.t, 0)) t; // expected-error {{initializer element is not a compile-time constant}} +}){0}; + +void inside_a_func(){ + int x; + (void)(struct { + typeof(foo(&(struct { int t; }){.t = x}.t, 0)) t; + }){0}; +} + +// see: https://github.com/llvm/llvm-project/issues/143613 +#define bitcast(type, value) \ + (((union{ typeof(value) src; type dst; }){ (value) }).dst) + +double placeholder = 10.0; +double bar = bitcast(double, placeholder); // expected-error {{initializer element is not a compile-time constant}} + +int main(void) +{ + int foo = 4; + foo = bitcast(int, bitcast(double, foo)); + return 0; +} diff --git a/clang/test/Sema/invalid-member.cpp b/clang/test/Sema/invalid-member.cpp index 57ee187ccf4d..0e3fec1b18ee 100644 --- a/clang/test/Sema/invalid-member.cpp +++ b/clang/test/Sema/invalid-member.cpp @@ -20,10 +20,12 @@ class Z { // Should be able to evaluate sizeof without crashing. static_assert(sizeof(Z) == 1, "No valid members"); -constexpr int N = undef; // expected-error {{use of undeclared identifier}} +constexpr int N = undef; // expected-error {{use of undeclared identifier}} \ + expected-note {{declared here}} template class ABC {}; class T { - ABC abc; + ABC abc; // expected-error {{non-type template argument is not a constant expression}} \ + expected-note {{initializer of 'N' is unknown}} }; static_assert(sizeof(T) == 1, "No valid members"); diff --git a/clang/test/Sema/ppc-dmf-types.c b/clang/test/Sema/ppc-dmf-types.c new file mode 100644 index 000000000000..b3da72df2508 --- /dev/null +++ b/clang/test/Sema/ppc-dmf-types.c @@ -0,0 +1,103 @@ +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -target-cpu future %s -verify +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -fsyntax-only \ +// RUN: -target-cpu future %s -verify + +// The use of PPC MMA types is strongly restricted. Non-pointer MMA variables +// can only be declared in functions and a limited number of operations are +// supported on these types. This test case checks that invalid uses of MMA +// types are correctly prevented. + +// vector dmr + +// typedef +typedef __dmr1024 dmr_t; + +// function argument +void testDmrArg1(__dmr1024 vdmr, int *ptr) { // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = vdmr; +} + +void testDmrArg2(const __dmr1024 vdmr, int *ptr) { // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = vdmr; +} + +void testDmrArg3(const dmr_t vdmr, int *ptr) { // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + *vdmrp = vdmr; +} + +// function return +__dmr1024 testDmrRet1(int *ptr) { // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + return *vdmrp; // expected-error {{invalid use of PPC MMA type}} +} + +const dmr_t testDmrRet4(int *ptr) { // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + return *vdmrp; // expected-error {{invalid use of PPC MMA type}} +} + +// global +__dmr1024 globalvdmr; // expected-error {{invalid use of PPC MMA type}} +const __dmr1024 globalvdmr2; // expected-error {{invalid use of PPC MMA type}} +__dmr1024 *globalvdmrp; +const __dmr1024 *const globalvdmrp2; +dmr_t globalvdmr_t; // expected-error {{invalid use of PPC MMA type}} + +// struct field +struct TestDmrStruct { + int a; + float b; + __dmr1024 c; // expected-error {{invalid use of PPC MMA type}} + __dmr1024 *vq; +}; + +// operators +int testDmrOperators1(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + __dmr1024 vdmr1 = *(vdmrp + 0); + __dmr1024 vdmr2 = *(vdmrp + 1); + __dmr1024 vdmr3 = *(vdmrp + 2); + if (vdmr1) // expected-error {{statement requires expression of scalar type ('__dmr1024' invalid)}} + *(vdmrp + 10) = vdmr1; + if (!vdmr2) // expected-error {{invalid argument type '__dmr1024' to unary expression}} + *(vdmrp + 11) = vdmr3; + int c1 = vdmr1 && vdmr2; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + int c2 = vdmr2 == vdmr3; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + int c3 = vdmr2 < vdmr1; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + return c1 || c2 || c3; +} + +void testDmrOperators2(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + __dmr1024 vdmr1 = *(vdmrp + 0); + __dmr1024 vdmr2 = *(vdmrp + 1); + __dmr1024 vdmr3 = *(vdmrp + 2); + vdmr1 = -vdmr1; // expected-error {{invalid argument type '__dmr1024' to unary expression}} + vdmr2 = vdmr1 + vdmr3; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + vdmr2 = vdmr2 * vdmr3; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + vdmr3 = vdmr3 | vdmr3; // expected-error {{invalid operands to binary expression ('__dmr1024' and '__dmr1024')}} + vdmr3 = vdmr3 << 2; // expected-error {{invalid operands to binary expression ('__dmr1024' and 'int')}} + *(vdmrp + 10) = vdmr1; + *(vdmrp + 11) = vdmr2; + *(vdmrp + 12) = vdmr3; +} + +vector unsigned char testDmrOperators3(int *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + __dmr1024 vdmr1 = *(vdmrp + 0); + __dmr1024 vdmr2 = *(vdmrp + 1); + __dmr1024 vdmr3 = *(vdmrp + 2); + vdmr1 ? *(vdmrp + 10) = vdmr2 : *(vdmrp + 11) = vdmr3; // expected-error {{used type '__dmr1024' where arithmetic or pointer type is required}} + vdmr2 = vdmr3; + return vdmr2[1]; // expected-error {{subscripted value is not an array, pointer, or vector}} +} + +void testDmrOperators4(int v, void *ptr) { + __dmr1024 *vdmrp = (__dmr1024 *)ptr; + __dmr1024 vdmr1 = (__dmr1024)v; // expected-error {{used type '__dmr1024' where arithmetic or pointer type is required}} + __dmr1024 vdmr2 = (__dmr1024)vdmrp; // expected-error {{used type '__dmr1024' where arithmetic or pointer type is required}} +} diff --git a/clang/test/Sema/typo-correction-ambiguity.cpp b/clang/test/Sema/typo-correction-ambiguity.cpp index 9dcff3d68c82..b2dae1d7696c 100644 --- a/clang/test/Sema/typo-correction-ambiguity.cpp +++ b/clang/test/Sema/typo-correction-ambiguity.cpp @@ -18,12 +18,12 @@ void testAmbiguousNoSuggestions() namespace MultipleCorrectionsButNotAmbiguous { - int PrefixType_Name(int value); // expected-note {{'PrefixType_Name' declared here}} + int PrefixType_Name(int value); int PrefixType_MIN(); int PrefixType_MAX(); }; int testMultipleCorrectionsButNotAmbiguous() { - int val = MultipleCorrectionsButNotAmbiguous::PrefixType_Enum(0); // expected-error {{no member named 'PrefixType_Enum' in namespace 'MultipleCorrectionsButNotAmbiguous'; did you mean 'PrefixType_Name'?}} + int val = MultipleCorrectionsButNotAmbiguous::PrefixType_Enum(0); // expected-error {{no member named 'PrefixType_Enum' in namespace 'MultipleCorrectionsButNotAmbiguous'}} return val; } diff --git a/clang/test/Sema/typo-correction-no-hang.c b/clang/test/Sema/typo-correction-no-hang.c index e6041704ff32..da234a2c7373 100644 --- a/clang/test/Sema/typo-correction-no-hang.c +++ b/clang/test/Sema/typo-correction-no-hang.c @@ -2,16 +2,15 @@ // PR50797 struct a { - int xxx; // expected-note {{'xxx' declared here}} + int xxx; }; int g_107; int g_108; int g_109; -struct a g_999; // expected-note 4{{'g_999' declared here}} +struct a g_999; -void b(void) { (g_910.xxx = g_910.xxx); } //expected-error 2{{use of undeclared identifier 'g_910'; did you mean 'g_999'}} +void b(void) { (g_910.xxx = g_910.xxx); } //expected-error 2{{use of undeclared identifier 'g_910'}} -void c(void) { (g_910.xxx = g_910.xxx1); } //expected-error 2{{use of undeclared identifier 'g_910'; did you mean 'g_999'}} \ - expected-error {{no member named 'xxx1' in 'struct a'; did you mean 'xxx'}} +void c(void) { (g_910.xxx = g_910.xxx1); } //expected-error 2{{use of undeclared identifier 'g_910'}} diff --git a/clang/test/Sema/typo-correction-no-hang.cpp b/clang/test/Sema/typo-correction-no-hang.cpp index 3c591645be25..34b8486bed90 100644 --- a/clang/test/Sema/typo-correction-no-hang.cpp +++ b/clang/test/Sema/typo-correction-no-hang.cpp @@ -8,10 +8,12 @@ struct rdar38642201 { void rdar38642201_callee(int x, int y); void rdar38642201_caller() { - struct rdar38642201 structVar; + struct rdar38642201 structVar; //expected-note 2{{'structVar' declared here}} rdar38642201_callee( - structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} - structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} + structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} \ + expected-error{{no member named 'fieldName1' in 'rdar38642201'}} + structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} \ + expected-error{{no member named 'fieldName2' in 'rdar38642201'}} } // Similar reproducer. @@ -20,7 +22,7 @@ public: int minut() const = delete; int hour() const = delete; - int longit() const; //expected-note{{'longit' declared here}} + int longit() const; int latit() const; }; @@ -35,6 +37,6 @@ int Foo(const B &b) { } int Bar(const B &b) { - return b.depar().longitude() + //expected-error{{no member named 'longitude' in 'A'; did you mean 'longit'?}} + return b.depar().longitude() + //expected-error{{no member named 'longitude' in 'A'}} b.depar().latitude(); //expected-error{{no member named 'latitude' in 'A'}} } diff --git a/clang/test/Sema/typo-correction-recursive.cpp b/clang/test/Sema/typo-correction-recursive.cpp index b39beb5493f6..a7d7127564b7 100644 --- a/clang/test/Sema/typo-correction-recursive.cpp +++ b/clang/test/Sema/typo-correction-recursive.cpp @@ -8,13 +8,13 @@ class DeepClass { public: - void trigger() const; // expected-note {{'trigger' declared here}} + void trigger() const; }; class Y { public: - const DeepClass& getX() const { return m_deepInstance; } // expected-note {{'getX' declared here}} + const DeepClass& getX() const { return m_deepInstance; } private: DeepClass m_deepInstance; int m_n; @@ -23,7 +23,7 @@ private: class Z { public: - const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared here}} + const Y& getY0() const { return m_y0; } const Y& getActiveY() const { return m_y0; } private: @@ -35,9 +35,9 @@ Z z_obj; void testMultipleCorrections() { - z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'; did you mean 'getY0'}} - getM(). // expected-error {{no member named 'getM' in 'Y'; did you mean 'getX'}} - triggee(); // expected-error {{no member named 'triggee' in 'DeepClass'; did you mean 'trigger'}} + z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'}} + getM(). + triggee(); } void testNoCorrections() @@ -53,19 +53,19 @@ struct A { C get_me_a_C(); }; struct B { - D get_me_a_D(); // expected-note {{'get_me_a_D' declared here}} + D get_me_a_D(); }; class Scope { public: A make_an_A(); - B make_a_B(); // expected-note {{'make_a_B' declared here}} + B make_a_B(); }; Scope scope_obj; int testDiscardedCorrections() { - return scope_obj.make_an_E(). // expected-error {{no member named 'make_an_E' in 'Scope'; did you mean 'make_a_B'}} - get_me_a_Z().value; // expected-error {{no member named 'get_me_a_Z' in 'B'; did you mean 'get_me_a_D'}} + return scope_obj.make_an_E(). // expected-error {{no member named 'make_an_E' in 'Scope'}} + get_me_a_Z().value; } class AmbiguousHelper { @@ -120,13 +120,13 @@ int testDeepAmbiguity() { } struct Dog { - int age; //expected-note{{'age' declared here}} - int size; //expected-note{{'size' declared here}} + int age; + int size; }; int from_dog_years(int DogYears, int DogSize); int get_dog_years() { struct Dog doggo; - return from_dog_years(doggo.agee, //expected-error{{no member named 'agee' in 'Dog'; did you mean 'age'}} - doggo.sizee); //expected-error{{no member named 'sizee' in 'Dog'; did you mean 'size'}} + return from_dog_years(doggo.agee, //expected-error{{no member named 'agee' in 'Dog'}} + doggo.sizee); //expected-error{{no member named 'sizee' in 'Dog'}} } diff --git a/clang/test/Sema/typo-correction.c b/clang/test/Sema/typo-correction.c index 4157207a9ac4..510a67e725f9 100644 --- a/clang/test/Sema/typo-correction.c +++ b/clang/test/Sema/typo-correction.c @@ -50,10 +50,12 @@ void fn1(void) { cabs(errij); // expected-error {{use of undeclared identifier 'errij'}} } -extern long afunction(int); +extern long afunction(int); // expected-note {{'afunction' declared here}} \ + expected-note {{passing argument to parameter here}} void fn2(void) { f(THIS_IS_AN_ERROR, // expected-error {{use of undeclared identifier 'THIS_IS_AN_ERROR'}} - afunction(afunction_)); // expected-error {{use of undeclared identifier 'afunction_'}} + afunction(afunction_)); // expected-error {{use of undeclared identifier 'afunction_'}} \ + expected-error {{incompatible pointer to integer conversion passing 'long (int)' to parameter of type 'int'}} } int d = X ? d : L; // expected-error 2 {{use of undeclared identifier}} @@ -94,22 +96,24 @@ struct rdar38642201 { void rdar38642201_callee(int x, int y); void rdar38642201_caller(void) { - struct rdar38642201 structVar; + struct rdar38642201 structVar; // expected-note 2{{'structVar' declared here}} rdar38642201_callee( - structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} - structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} + structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} \ + expected-error{{no member named 'fieldName1' in 'struct rdar38642201'}} + structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} \ + expected-error{{no member named 'fieldName2' in 'struct rdar38642201'}} } void PR40286_g(int x, int y); void PR40286_h(int x, int y, int z); -void PR40286_1(int the_value) { - PR40286_g(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +void PR40286_1(int the_value) { // expected-note {{'the_value' declared here}} + PR40286_g(the_walue, 0); // expected-error {{use of undeclared identifier 'the_walue'}} } -void PR40286_2(int the_value) { - PR40286_h(the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +void PR40286_2(int the_value) { // expected-note {{'the_value' declared here}} + PR40286_h(the_value, the_walue, 0); // expected-error {{use of undeclared identifier 'the_walue'}} } -void PR40286_3(int the_value) { - PR40286_h(the_walue); // expected-error {{use of undeclared identifier 'the_walue'}} +void PR40286_3(int the_value) { // expected-note {{'the_value' declared here}} + PR40286_h(the_walue, 0, 0); // expected-error {{use of undeclared identifier 'the_walue'}} } void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}} PR40286_h(the_value, the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'; did you mean 'the_value'?}} diff --git a/clang/test/Sema/unknown-attributes.c b/clang/test/Sema/unknown-attributes.c index a701650c9e05..4711c9fa667b 100644 --- a/clang/test/Sema/unknown-attributes.c +++ b/clang/test/Sema/unknown-attributes.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c++ -Wunknown-attributes -fsyntax-only -verify %s +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify=expected,c %s +// RUN: %clang_cc1 -x c++ -Wunknown-attributes -fsyntax-only -verify=expected,cxx %s [[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} int f1(void) { @@ -20,3 +20,10 @@ int f3(void) { int f4(void) { return 0; } + +[[using gnu : deprected]] // c-error {{expected ','}} \ + // c-warning {{unknown attribute 'using' ignored}} \ + // cxx-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f5(void) { + return 0; +} diff --git a/clang/test/SemaCXX/arrow-operator.cpp b/clang/test/SemaCXX/arrow-operator.cpp index 295dea3c1756..a789c4e36e4c 100644 --- a/clang/test/SemaCXX/arrow-operator.cpp +++ b/clang/test/SemaCXX/arrow-operator.cpp @@ -47,23 +47,22 @@ class wrapped_ptr { public: wrapped_ptr(T* ptr) : ptr_(ptr) {} T* operator->() { return ptr_; } - void Check(); // expected-note {{'Check' declared here}} + void Check(); private: T *ptr_; }; class Worker { public: - void DoSomething(); // expected-note {{'DoSomething' declared here}} + void DoSomething(); void Chuck(); }; void test() { wrapped_ptr worker(new Worker); worker.DoSomething(); // expected-error {{no member named 'DoSomething' in 'arrow_suggest::wrapped_ptr'; did you mean to use '->' instead of '.'?}} - worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr'; did you mean to use '->' instead of '.'?}} \ - // expected-error {{no member named 'DoSamething' in 'arrow_suggest::Worker'; did you mean 'DoSomething'?}} - worker.Chuck(); // expected-error {{no member named 'Chuck' in 'arrow_suggest::wrapped_ptr'; did you mean 'Check'?}} + worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr'}} + worker.Chuck(); // expected-error {{no member named 'Chuck' in 'arrow_suggest::wrapped_ptr'}} } } // namespace arrow_suggest diff --git a/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp b/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp index 00fa5bd7336b..acd9846bb20f 100644 --- a/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp +++ b/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp @@ -11,7 +11,7 @@ __attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-w __attribute__((no_caller_saved_registers)) void foo(int *){} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} -[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} +[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'gnu::no_caller_saved_registers' ignored}} typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} diff --git a/clang/test/SemaCXX/builtin-is-constant-evaluated.cpp b/clang/test/SemaCXX/builtin-is-constant-evaluated.cpp index c775fe71069d..66981acf87a8 100644 --- a/clang/test/SemaCXX/builtin-is-constant-evaluated.cpp +++ b/clang/test/SemaCXX/builtin-is-constant-evaluated.cpp @@ -154,3 +154,17 @@ namespace narrowing { // expected-note {{insert an explicit cast to silence this issue}} } } + +struct GH99680 { + static const int x1 = 1/(1-__builtin_is_constant_evaluated()); // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // expected-note {{division by zero}} + static const int x2 = __builtin_is_constant_evaluated(); + static_assert(x2 == 1); + static const float x3 = 1/(1-__builtin_is_constant_evaluated()); // expected-error {{in-class initializer for static data member of type 'const float' requires 'constexpr' specifier}} \ + // expected-note {{add 'constexpr'}} \ + // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // expected-note {{division by zero}} + static const float x4 = __builtin_is_constant_evaluated(); // expected-error {{in-class initializer for static data member of type 'const float' requires 'constexpr' specifier}} \ + // expected-note {{add 'constexpr'}} + static_assert(fold(x4 == 1)); +}; diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index 2f59544e7f36..f1e02d5158aa 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11 -Wc++11-compat %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s -std=c++98 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s -std=c++98 class C { public: auto int errx; // expected-error {{storage class specified for a member declaration}} @@ -32,7 +32,7 @@ public: int : 1, : 2; typedef int E : 1; // expected-error {{typedef member 'E' cannot be a bit-field}} static int sb : 1; // expected-error {{static member 'sb' cannot be a bit-field}} - static int vs; + static int vs; // cxx11-note {{declared here}} typedef int func(); func tm; @@ -48,20 +48,28 @@ public: #endif static int si = 0; // expected-error {{non-const static data member must be initialized out of line}} static const NestedC ci = 0; // expected-error {{static data member of type 'const NestedC' must be initialized out of line}} - static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}} + static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{read of non-const variable 'vs' is not allowed in a constant expression}} \ + // cxx98-note {{subexpression not valid in a constant expression}} static const int vi = 0; static const volatile int cvi = 0; // ok, illegal in C++11 #if __cplusplus >= 201103L // expected-error@-2 {{static const volatile data member must be initialized out of line}} #endif static const E evi = 0; - static const int overflow = 1000000*1000000; // cxx11-error {{in-class initializer for static data member is not a constant expression}} - // expected-warning@-1 {{overflow in expression}} - static const int overflow_shift = 1<<32; // cxx11-error {{in-class initializer for static data member is not a constant expression}} - static const int overflow_shift2 = 1>>32; // cxx11-error {{in-class initializer for static data member is not a constant expression}} - static const int overflow_shift3 = 1<<-1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} - static const int overflow_shift4 = 1<<-1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} - static const int overflow_shift5 = -1<<1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} + static const int overflow = 1000000*1000000; // cxx11-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{value 1000000000000 is outside the range of representable values of type 'int'}} \ + // expected-warning {{overflow in expression}} + static const int overflow_shift = 1<<32; // cxx11-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{shift count 32 >= width of type 'int' (32 bits)}} + static const int overflow_shift2 = 1>>32; // cxx11-error {{in-class initializer for static data member is not a constant expression}}\ + // cxx11-note {{shift count 32 >= width of type 'int' (32 bits)}} + static const int overflow_shift3 = 1<<-1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{negative shift count -1}} + static const int overflow_shift4 = 1<<-1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{negative shift count -1}} + static const int overflow_shift5 = -1<<1; // cxx11-error {{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{left shift of negative value -1}} void m() { sx = 0; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 222c0d35d067..0a8202871968 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1888,10 +1888,11 @@ namespace PR15884 { } namespace AfterError { - constexpr int error() { + constexpr int error() { // pre-cxx23-error {{no return statement in constexpr function}} return foobar; // expected-error {{undeclared identifier}} - } - constexpr int k = error(); // expected-error {{constexpr variable 'k' must be initialized by a constant expression}} + } // cxx23-note {{control reached end of constexpr function}} + constexpr int k = error(); // cxx23-error {{constexpr variable 'k' must be initialized by a constant expression}} \ + cxx23-note {{in call to 'error()'}} } namespace std { diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index b653a3bf1a1d..717c73c4786e 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -458,7 +458,7 @@ namespace PR18234 { #endif } a; A::S s = a; // expected-error {{no viable conversion from 'struct A' to 'A::S'}} - A::E e = a; + A::E e = a; // expected-note {{'e' declared here}} bool k1 = e == A::e; // expected-error {{no member named 'e'}} bool k2 = e.n == 0; } diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp index 068fdab4bfe3..c9cefeb30c15 100644 --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -8,19 +8,16 @@ // RUN: not %clang_cc1 -std=c++20 -fsyntax-only %s -fcxx-exceptions -fexceptions -Wunused-result 2>&1 | FileCheck %s void no_coroutine_traits_bad_arg_await() { - co_await a; // expected-error {{include }} - // expected-error@-1 {{use of undeclared identifier 'a'}} + co_await a; // expected-error {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_yield() { - co_yield a; // expected-error {{include }} - // expected-error@-1 {{use of undeclared identifier 'a'}} + co_yield a; // expected-error {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_return() { - co_return a; // expected-error {{include }} - // expected-error@-1 {{use of undeclared identifier 'a'}} + co_return a; // expected-error {{use of undeclared identifier 'a'}} } void no_coroutine_traits() { @@ -208,8 +205,7 @@ void mixed_yield() { void mixed_yield_invalid() { co_yield blah; // expected-error {{use of undeclared identifier}} - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} + return; } void mixed_yield_return_first(bool b) { @@ -231,8 +227,7 @@ void mixed_return_for_range(bool b, T t) { template void mixed_yield_template(T) { co_yield blah; // expected-error {{use of undeclared identifier}} - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} + return; } template @@ -314,10 +309,9 @@ template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{r template void mixed_coreturn_template2(bool b, T) { if (b) - co_return v; // expected-note {{use of 'co_return'}} - // expected-error@-1 {{use of undeclared identifier 'v'}} + co_return v; // expected-error {{use of undeclared identifier 'v'}} else - return; // expected-error {{not allowed in coroutine}} + return; } struct promise_handle; diff --git a/clang/test/SemaCXX/cxx-delayed-typo-correction-crashes.cpp b/clang/test/SemaCXX/cxx-delayed-typo-correction-crashes.cpp new file mode 100644 index 000000000000..f3aa05153281 --- /dev/null +++ b/clang/test/SemaCXX/cxx-delayed-typo-correction-crashes.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace GH138850 { +void test() { + int tmp = add(int, 0, 0); // expected-error {{expected '(' for function-style cast or type construction}} \ + expected-note {{previous definition is here}} + uint tmp = add(uint, 1, 1); // expected-error {{use of undeclared identifier 'uint'; did you mean 'int'?}} \ + expected-error {{redefinition of 'tmp'}} \ + expected-error {{use of undeclared identifier 'uint'}} + call(void, f, (int)tmp); // expected-error {{expected '(' for function-style cast or type construction}} \ + expected-error {{use of undeclared identifier 'f'}} +} +} + +namespace GH107840 { +struct tm {}; // expected-note {{'tm' declared here}} + +auto getCache = [&] { // expected-error {{non-local lambda expression cannot have a capture-default}} + ::foo([=] { // expected-error {{no member named 'foo' in the global namespace}} + tms time; // expected-error {{unknown type name 'tms'; did you mean 'tm'?}} + (void)time; + }); +}; +} + +namespace GH59391 { +template class c { + c(b); + b e; + void f() { + for (auto core : a::c(cores)) { // expected-error {{use of undeclared identifier 'cores'}} \ + expected-error {{use of undeclared identifier 'a'}} + } + } +}; +} + +namespace GH45915 { +short g_volatile_ushort; // expected-note {{'g_volatile_ushort' declared here}} +namespace a { + int b = l_volatile_uwchar.a ::c ::~d<>; // expected-error {{use of undeclared identifier 'l_volatile_uwchar'}} \ + expected-error {{no member named 'd' in namespace 'GH45915::a'}} +} +} + +namespace GH45891 { +int a = b.c < enum , > :: template ~d < > [ e; // expected-error {{use of undeclared identifier 'b'}} \ + expected-error {{expected identifier or '{'}} \ + expected-error {{expected ';' after top level declarator}} +} + +namespace GH32903 { +void +B( + char cat_dog_3, char cat_dog_2, char cat_dog_1, char cat_dog_0, char pigeon_dog_3, char pigeon_dog_2, + char pigeon_dog_1, char pigeon_dog_0, short &elefant15_lion, short &elefant14_lion, short &elefant13_lion, // expected-note 3 {{declared here}} + short &elefant12_lion, short &elefant11_lion, short &elefant10_lion, short &elefant9_lion, short &elefant8_lion, // expected-note 5 {{declared here}} + short &elefant7_lion, short &elefant6_lion, short &elefant5_lion, short &elefant4_lion, short &elefant3_lion, // expected-note 2 {{declared here}} + short &elefant2_lion, short &elefant1_lion, short &elefant0_lion, char& no_animal) +{ + + A( // FIXME: it's surprising that we don't issue a "use of undeclared identifier" diagnostic for the call itself. + elefant_15_lion, elefant_14_lion, elefant_13_lion, elefant_12_lion, elefant_11_lion, elefant_10_lion, elefant_9_lion, // expected-error 7 {{use of undeclared identifier}} + elefant_8_lion, elefant_7_lion, elefant_6_lion, elefant_5_lion, elefant_4_lion, elefant_3_lion, elefant_2_lion, // expected-error 7 {{use of undeclared identifier}} + elefant_1_lion, elefant_0_lion, no_animal, other_mammal); // expected-error 3 {{use of undeclared identifier}} +} +} diff --git a/clang/test/SemaCXX/cxx0x-class.cpp b/clang/test/SemaCXX/cxx0x-class.cpp index a612a5c07e6e..4b54221cceff 100644 --- a/clang/test/SemaCXX/cxx0x-class.cpp +++ b/clang/test/SemaCXX/cxx0x-class.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -Wno-uninitialized -fsyntax-only -verify -std=c++11 -Wno-error=static-float-init %s -int vs = 0; +int vs = 0; // expected-note {{declared here}} class C { public: @@ -11,17 +11,20 @@ public: int i = 0; static int si = 0; // expected-error {{non-const static data member must be initialized out of line}} static const NestedC ci = 0; // expected-error {{static data member of type 'const NestedC' must be initialized out of line}} - static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}} + static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // expected-note {{read of non-const variable 'vs' is not allowed in a constant expression}} static const int vi = 0; static const volatile int cvi = 0; // expected-error {{static const volatile data member must be initialized out of line}} }; namespace rdar8367341 { - float foo(); // expected-note {{here}} + float foo(); // expected-note 2 {{here}} struct A { static const float x = 5.0f; // expected-warning {{requires 'constexpr'}} expected-note {{add 'constexpr'}} - static const float y = foo(); // expected-warning {{requires 'constexpr'}} expected-note {{add 'constexpr'}} + static const float y = foo(); // expected-warning {{requires 'constexpr'}} expected-note {{add 'constexpr'}} \ + // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // expected-note {{non-constexpr function 'foo' cannot be used in a constant expression}} static constexpr float x2 = 5.0f; static constexpr float y2 = foo(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr function 'foo'}} }; diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 95c64bc3b8bf..6ee1249a66c3 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -121,7 +121,8 @@ void for_range() { } int error_recovery() { - auto [foobar]; // expected-error {{requires an initializer}} + auto [foobar]; // expected-error {{requires an initializer}} \ + expected-note {{'foobar' declared here}} return foobar_; // expected-error {{undeclared identifier 'foobar_'}} } diff --git a/clang/test/SemaCXX/cxx20-delayed-typo-correction-crashes.cpp b/clang/test/SemaCXX/cxx20-delayed-typo-correction-crashes.cpp new file mode 100644 index 000000000000..a16a7f8255f7 --- /dev/null +++ b/clang/test/SemaCXX/cxx20-delayed-typo-correction-crashes.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s + +#include "Inputs/std-coroutine.h" + +namespace GH58172 { +template +int f2(int, Fn&&) +{ + return 0; +} + +int f1() +{ + return f2(v1, []() -> task { // expected-error {{no template named 'task'}} \ + expected-error {{use of undeclared identifier 'v1'}} + co_return v2; // expected-error {{use of undeclared identifier 'v2'}} + }); +} +} diff --git a/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp b/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp index 5c0d89d9125f..1bc7f2cce3c9 100644 --- a/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp +++ b/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp @@ -61,7 +61,7 @@ struct A : X { // expected-error {{no template named 'X'}} // Similarly for treating overload sets of functions as template names. struct g {}; // expected-error {{'g' refers to a function template}} g::Y xy; // expected-error {{no template named 'g'}} FIXME lies -void xf(g x); // expected-error {{variable has incomplete type 'void'}} expected-error 1+{{}} expected-note {{}} +void xf(g x); // expected-error {{variable has incomplete type 'void'}} expected-error 1+{{}} struct B : g { // expected-error {{expected class name}} B() : g() {} // expected-error {{expected class member or base class name}} }; diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index d9932e4dd824..1474c48cda3c 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1154,20 +1154,20 @@ namespace GH65985 { int consteval operator""_foo(unsigned long long V) { return 0; } -int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}} +int consteval operator""_bar(unsigned long long V); // expected-note 4 {{here}} int consteval f() { return 0; } -int consteval g(); // expected-note {{here}} +int consteval g(); // expected-note 2 {{here}} struct C { static const int a = 1_foo; static constexpr int b = 1_foo; static const int c = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \ - // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \ + // expected-note 2 {{undefined function 'operator""_bar' cannot be used in a constant expression}} \ // expected-error {{in-class initializer for static data member is not a constant expression}} // FIXME: remove duplicate diagnostics @@ -1179,7 +1179,7 @@ struct C { static const int e = f(); static const int f = g(); // expected-error {{call to consteval function 'GH65985::g' is not a constant expression}} \ // expected-error {{in-class initializer for static data member is not a constant expression}} \ - // expected-note {{undefined function 'g' cannot be used in a constant expression}} + // expected-note 2 {{undefined function 'g' cannot be used in a constant expression}} }; } diff --git a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp index 9d43994ee766..7152a5937d9b 100644 --- a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp +++ b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++2c -verify %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-intrinsics -fptrauth-calls -std=c++2c -verify %s class Trivial {}; static_assert(__builtin_is_cpp_trivially_relocatable(Trivial)); diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index ed4802943ad3..b9e0b17d510a 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -553,14 +553,11 @@ namespace crash_on_invalid_base_dtor { struct Test { virtual ~Test(); }; -struct Baz : public Test { // expected-warning {{non-virtual destructor}} +struct Baz : public Test { Baz() {} - ~Baz() = defaul; // expected-error {{undeclared identifier 'defaul'}} \ - // expected-error {{initializer on function}} \ - // expected-note {{overridden virtual function is here}} + ~Baz() = defaul; // expected-error {{undeclared identifier 'defaul'}} }; -struct Foo : public Baz { // expected-error {{cannot override a non-deleted function}} \ - // expected-note {{destructor of 'Foo' is implicitly deleted}} +struct Foo : public Baz { Foo() {} }; } @@ -579,11 +576,9 @@ static_assert(!__is_trivially_constructible(Foo, Foo &&), ""); namespace GH97230 { struct X { - ~X() = defaul; // expected-error {{initializer on function does not look like a pure-specifier}} \ - // expected-error {{use of undeclared identifier 'defaul'}} + ~X() = defaul; // expected-error {{use of undeclared identifier 'defaul'}} }; -struct Y : X {} y1{ }; // expected-error {{call to implicitly-deleted default constructor of 'struct Y'}} \ - // expected-note {{default constructor of 'Y' is implicitly deleted because base class 'X' has no destructor}} +struct Y : X {} y1{ }; } namespace GH121706 { diff --git a/clang/test/SemaCXX/exception-spec.cpp b/clang/test/SemaCXX/exception-spec.cpp index 6ad19aab397b..31c691b28da4 100644 --- a/clang/test/SemaCXX/exception-spec.cpp +++ b/clang/test/SemaCXX/exception-spec.cpp @@ -52,3 +52,24 @@ namespace AssignmentOp { D2 &operator=(const D2&); // expected-error {{more lax}} }; } + +namespace OverloadedFunctions { + +template +void f(T&) noexcept; + +template +void f(T (&arr)[N]) noexcept(noexcept(f(*arr))); + +template +inline void f(T&) noexcept {} + +template +inline void f(T (&arr)[N]) noexcept(noexcept(f(*arr))) {} + +void g() { + int x[1]; + f(x); +} + +} diff --git a/clang/test/SemaCXX/gh102293.cpp b/clang/test/SemaCXX/gh102293.cpp index d4218cc13dce..fe417e697841 100644 --- a/clang/test/SemaCXX/gh102293.cpp +++ b/clang/test/SemaCXX/gh102293.cpp @@ -45,3 +45,20 @@ class quux : quux { // expected-error {{base class has incomplete type}} \ virtual int c(); }; } + +// Ensure we don't get infinite recursion from the check, however. See GH141789 +namespace GH141789 { +template +struct S { + Ty t; // expected-error {{field has incomplete type 'GH141789::X'}} +}; + +struct T { + ~T(); +}; + +struct X { // expected-note {{definition of 'GH141789::X' is not complete until the closing '}'}} + S next; // expected-note {{in instantiation of template class 'GH141789::S' requested here}} + T m; +}; +} diff --git a/clang/test/SemaCXX/invalid-if-constexpr.cpp b/clang/test/SemaCXX/invalid-if-constexpr.cpp index 0007f2739cbb..9f2774187148 100644 --- a/clang/test/SemaCXX/invalid-if-constexpr.cpp +++ b/clang/test/SemaCXX/invalid-if-constexpr.cpp @@ -2,12 +2,16 @@ namespace GH61885 { void similar() { // expected-note {{'similar' declared here}} - if constexpr (similer<>) {} // expected-error {{use of undeclared identifier 'similer'; did you mean 'similar'?}} + if constexpr (similer<>) {} // expected-error {{use of undeclared identifier 'similer'; did you mean 'similar'?}} \ + expected-warning {{address of function 'similar<>' will always evaluate to 'true'}} \ + expected-note {{prefix with the address-of operator to silence this warning}} } -void a() { if constexpr (__adl_swap<>) {}} // expected-error{{use of undeclared identifier '__adl_swap'; did you mean '__sync_swap'?}} +void a() { if constexpr (__adl_swap<>) {}} // expected-error{{use of undeclared identifier '__adl_swap'}} int AA() { return true;} // expected-note {{'AA' declared here}} -void b() { if constexpr (AAA<>) {}} // expected-error {{use of undeclared identifier 'AAA'; did you mean 'AA'?}} +void b() { if constexpr (AAA<>) {}} // expected-error {{use of undeclared identifier 'AAA'; did you mean 'AA'?}} \ + expected-warning {{address of function 'AA<>' will always evaluate to 'true'}} \ + expected-note {{prefix with the address-of operator to silence this warning}} } diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp index 0596e40f6c2f..902b09097a12 100644 --- a/clang/test/SemaCXX/member-expr.cpp +++ b/clang/test/SemaCXX/member-expr.cpp @@ -96,11 +96,11 @@ namespace test5 { namespace PR7508 { struct A { struct CleanupScope {}; - void PopCleanupBlock(); // expected-note{{'PopCleanupBlock' declared here}} + void PopCleanupBlock(); }; void foo(A &a) { - a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'; did you mean 'PopCleanupBlock'?}} + a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'}} } } @@ -189,7 +189,7 @@ namespace PR15045 { } struct bar { - void func(); // expected-note {{'func' declared here}} + void func(); }; struct foo { @@ -207,7 +207,7 @@ namespace PR15045 { // Show that recovery has happened by also triggering typo correction e->Func(); // expected-error {{member reference type 'bar' is not a pointer; did you mean to use '.'?}} \ - // expected-error {{no member named 'Func' in 'PR15045::bar'; did you mean 'func'?}} + // expected-error {{no member named 'Func' in 'PR15045::bar'}} // Make sure a fixit isn't given in the case that the '->' isn't actually // the problem (the problem is with the return value of an operator->). diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm index 41204be76eaf..5d0d6da44a2e 100644 --- a/clang/test/SemaCXX/modules.cppm +++ b/clang/test/SemaCXX/modules.cppm @@ -1,19 +1,20 @@ -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t.0.pcm -verify -DTEST=0 -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t.1.pcm -verify -DTEST=1 -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -fmodule-file=foo=%t.0.pcm -o %t.2.pcm -verify -DTEST=2 -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -fmodule-file=foo=%t.0.pcm -o %t.3.pcm -verify -Dfoo=bar -DTEST=3 +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t -#if TEST == 0 || TEST == 2 +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test0.cpp -o %t/test0.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test1.cpp -o %t/test1.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test2.cpp -fmodule-file=foo=%t/test0.pcm -o %t/test2.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test3.cpp -fmodule-file=foo=%t/test0.pcm -o %t/test3.pcm -verify + +//--- test0.cpp // expected-no-diagnostics -#endif - export module foo; static int m; int n; -#if TEST == 0 export { int a; int b; @@ -27,10 +28,52 @@ export void f() {} export struct T { } t; -#elif TEST == 3 + +//--- test1.cpp +export module foo; + +static int m; + +int n; + +struct S { + export int n; // expected-error {{expected member name or ';'}} + export static int n; // expected-error {{expected member name or ';'}} +}; + +// FIXME: Exports of declarations without external linkage are disallowed. +// Exports of declarations with non-external-linkage types are disallowed. + +// Cannot export within another export. This isn't precisely covered by the +// language rules right now, but (per personal correspondence between zygoloid +// and gdr) is the intent. +export { // expected-note {{export block begins here}} + extern "C++" { + namespace NestedExport { + export { // expected-error {{export declaration appears within another export declaration}} + int q; + } + } // namespace NestedExport + } +} + +//--- test2.cpp +// expected-no-diagnostics +export module foo; + +static int m; + +int n; + +//--- test3.cpp +export module bar; + +static int m; + +int n; + int use_a = a; // expected-error {{use of undeclared identifier 'a'}} -#undef foo import foo; // expected-error {{imports must immediately follow the module declaration}} export {} @@ -46,29 +89,3 @@ int use_n = n; // FIXME: this should not be visible, because it is not exported extern int n; static_assert(&n != p); // expected-error{{use of undeclared identifier 'p'}} -#endif - -#if TEST == 1 -struct S { - export int n; // expected-error {{expected member name or ';'}} - export static int n; // expected-error {{expected member name or ';'}} -}; -#endif - -// FIXME: Exports of declarations without external linkage are disallowed. -// Exports of declarations with non-external-linkage types are disallowed. - -// Cannot export within another export. This isn't precisely covered by the -// language rules right now, but (per personal correspondence between zygoloid -// and gdr) is the intent. -#if TEST == 1 -export { // expected-note {{export block begins here}} - extern "C++" { - namespace NestedExport { - export { // expected-error {{export declaration appears within another export declaration}} - int q; - } - } // namespace NestedExport - } -} -#endif diff --git a/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 36398aed7ac5..abeaba9d8dde 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/test/SemaCXX/nested-name-spec.cpp @@ -409,7 +409,8 @@ T1 var_1a; T1 var_1b; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} template int F() {} int (*X1)() = (B1::B2 ? F<1> : F<2>); -int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} \ + expected-note{{'PR18587::X2' declared here}} // Bit fields + templates struct S7a { @@ -445,7 +446,8 @@ namespace PR16951 { int x4 = enumerator_2::ENUMERATOR_2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} int x5 = enumerator_2::X2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \ - // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}} + // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}} \ + // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'int (*)()'}} } diff --git a/clang/test/SemaCXX/pr13394-crash-on-invalid.cpp b/clang/test/SemaCXX/pr13394-crash-on-invalid.cpp deleted file mode 100644 index 304ee92f6a8d..000000000000 --- a/clang/test/SemaCXX/pr13394-crash-on-invalid.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -// Don't crash (PR13394). - -namespace stretch_v1 { - struct closure_t { - const stretch_v1::ops_t* d_methods; // expected-error {{no type named 'ops_t' in namespace 'stretch_v1'}} - }; -} -namespace gatekeeper_v1 { - namespace gatekeeper_factory_v1 { - struct closure_t { // expected-note {{'closure_t' declared here}} expected-note {{'gatekeeper_factory_v1::closure_t' declared here}} - gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean simply 'closure_t'?}} - }; - } - // FIXME: Typo correction should remove the 'gatekeeper_v1::' name specifier - gatekeeper_v1::closure_t *x; // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean 'gatekeeper_factory_v1::closure_t'}} -} - -namespace Foo { -struct Base { - void Bar() {} // expected-note{{'Bar' declared here}} -}; -} - -struct Derived : public Foo::Base { - void test() { - Foo::Bar(); // expected-error{{no member named 'Bar' in namespace 'Foo'; did you mean simply 'Bar'?}} - } -}; diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp b/clang/test/SemaCXX/ptrauth-triviality.cpp index 60d1b57230f1..ba8a8273d5c0 100644 --- a/clang/test/SemaCXX/ptrauth-triviality.cpp +++ b/clang/test/SemaCXX/ptrauth-triviality.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++20 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s -// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++26 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++26 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s #define AQ __ptrauth(1,1,50) #define IQ __ptrauth(1,0,50) @@ -83,7 +83,7 @@ static_assert(!__is_trivially_constructible(Holder, const Holder&)); static_assert(!__is_trivially_assignable(Holder, const Holder&)); static_assert(__is_trivially_destructible(Holder)); static_assert(!__is_trivially_copyable(Holder)); -static_assert(__is_trivially_relocatable(Holder)); // expected-warning{{deprecated}} +static_assert(!__is_trivially_relocatable(Holder)); // expected-warning{{deprecated}} static_assert(__builtin_is_cpp_trivially_relocatable(Holder)); static_assert(!__is_trivially_equality_comparable(Holder)); @@ -99,7 +99,6 @@ static_assert(!__is_trivially_assignable(S4, const S4&)); static_assert(__is_trivially_destructible(S4)); static_assert(!__is_trivially_copyable(S4)); static_assert(!__is_trivially_relocatable(S4)); // expected-warning{{deprecated}} -//FIXME static_assert(__builtin_is_cpp_trivially_relocatable(S4)); static_assert(!__is_trivially_equality_comparable(S4)); @@ -124,7 +123,6 @@ static_assert(!__is_trivially_assignable(S5, const S5&)); static_assert(__is_trivially_destructible(S5)); static_assert(!__is_trivially_copyable(S5)); static_assert(!__is_trivially_relocatable(S5)); // expected-warning{{deprecated}} -//FIXME static_assert(__builtin_is_cpp_trivially_relocatable(S5)); static_assert(!__is_trivially_equality_comparable(S5)); @@ -182,3 +180,39 @@ static_assert(__is_trivially_copyable(Holder)); static_assert(__is_trivially_relocatable(Holder)); // expected-warning{{deprecated}} static_assert(__builtin_is_cpp_trivially_relocatable(Holder)); static_assert(__is_trivially_equality_comparable(Holder)); + +template struct MultipleInheriter : Bases... { +}; + +template static const bool test_is_trivially_relocatable_v = __builtin_is_cpp_trivially_relocatable(T); +template static const bool multiple_inheritance_is_relocatable = test_is_trivially_relocatable_v>; +template static const bool inheritance_relocatability_matches_bases_v = + (test_is_trivially_relocatable_v && ...) == multiple_inheritance_is_relocatable; + +static_assert(multiple_inheritance_is_relocatable == multiple_inheritance_is_relocatable); +static_assert(inheritance_relocatability_matches_bases_v); +static_assert(inheritance_relocatability_matches_bases_v); + +struct AA AddressDiscriminatedPolymorphicBase trivially_relocatable_if_eligible { + virtual void foo(); +}; + +struct IA NoAddressDiscriminatedPolymorphicBase trivially_relocatable_if_eligible { + virtual void bar(); +}; + +template struct UnionWrapper trivially_relocatable_if_eligible { + union U { + T field1; + } u; +}; + +static_assert(test_is_trivially_relocatable_v); +static_assert(test_is_trivially_relocatable_v); +static_assert(inheritance_relocatability_matches_bases_v); +static_assert(inheritance_relocatability_matches_bases_v); + +static_assert(!test_is_trivially_relocatable_v>); +static_assert(test_is_trivially_relocatable_v>); +static_assert(!test_is_trivially_relocatable_v>>); +static_assert(!test_is_trivially_relocatable_v>>); diff --git a/clang/test/SemaCXX/return.cpp b/clang/test/SemaCXX/return.cpp index 17d7892d8dbd..796c9ae91ded 100644 --- a/clang/test/SemaCXX/return.cpp +++ b/clang/test/SemaCXX/return.cpp @@ -130,5 +130,5 @@ void cxx_unresolved_expr() { // CXXUnresolvedConstructExpr, and the missing ')' gives it an invalid source // location for its rparen. Check that emitting a diag on the range of the // expr doesn't assert. - return int(undeclared, 4; // expected-error {{expected ')'}} expected-note{{to match this '('}} expected-error {{use of undeclared identifier 'undeclared'}} + return int(undeclared, 4; // expected-error {{use of undeclared identifier 'undeclared'}} } diff --git a/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp new file mode 100644 index 000000000000..b38499a634fc --- /dev/null +++ b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 -triple arm64 -fptrauth-calls -fptrauth-intrinsics -std=c++26 -verify %s + +// This test intentionally does not enable the global address discrimination +// of vtable pointers. This lets us configure them with different schemas +// and verify that we're correctly tracking the existence of address discrimination + +// expected-no-diagnostics + +struct NonAddressDiscPtrauth { + void * __ptrauth(1, 0, 1234) p; +}; + +static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscPtrauth)); + +struct AddressDiscPtrauth { + void * __ptrauth(1, 1, 1234) p; +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(AddressDiscPtrauth)); + +struct MultipleBaseClasses : NonAddressDiscPtrauth, AddressDiscPtrauth { + +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(MultipleBaseClasses)); + +struct MultipleMembers1 { + NonAddressDiscPtrauth field0; + AddressDiscPtrauth field1; +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(MultipleMembers1)); + +struct MultipleMembers2 { + NonAddressDiscPtrauth field0; + NonAddressDiscPtrauth field1; +}; + +static_assert(__builtin_is_cpp_trivially_relocatable(MultipleMembers2)); + +struct UnionOfPtrauth { + union { + NonAddressDiscPtrauth field0; + AddressDiscPtrauth field1; + } u; +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPtrauth)); + +struct [[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]] Polymorphic trivially_relocatable_if_eligible { + virtual ~Polymorphic(); +}; + +struct Foo : Polymorphic { + Foo(const Foo&); + ~Foo(); +}; + + +static_assert(__builtin_is_cpp_trivially_relocatable(Polymorphic)); + +struct [[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,no_extra_discrimination)]] NonAddressDiscriminatedPolymorphic trivially_relocatable_if_eligible { + virtual ~NonAddressDiscriminatedPolymorphic(); +}; + +static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscriminatedPolymorphic)); + + +struct PolymorphicMembers { + Polymorphic field; +}; + +static_assert(__builtin_is_cpp_trivially_relocatable(PolymorphicMembers)); + +struct UnionOfPolymorphic { + union trivially_relocatable_if_eligible { + Polymorphic p; + int i; + } u; +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPolymorphic)); + + +struct UnionOfNonAddressDiscriminatedPolymorphic { + union trivially_relocatable_if_eligible { + NonAddressDiscriminatedPolymorphic p; + int i; + } u; +}; +static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPolymorphic)); + +struct UnionOfNonAddressDiscriminatedPtrauth { + union { + NonAddressDiscPtrauth p; + int i; + } u; +}; + +static_assert(__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPtrauth)); + +struct UnionOfAddressDisriminatedPtrauth { + union { + AddressDiscPtrauth p; + int i; + } u; +}; + +static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfAddressDisriminatedPtrauth)); diff --git a/clang/test/SemaCXX/type-aware-new-delete-transparent-contexts.cpp b/clang/test/SemaCXX/type-aware-new-delete-transparent-contexts.cpp index 7c0b967a3c03..30fea464a8dc 100644 --- a/clang/test/SemaCXX/type-aware-new-delete-transparent-contexts.cpp +++ b/clang/test/SemaCXX/type-aware-new-delete-transparent-contexts.cpp @@ -1,12 +1,22 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=0 -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=1 -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=2 +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -fsyntax-only -verify %t/testing.cpp -std=c++26 -fexceptions -DTRANSPARENT_DECL=0 +// RUN: %clang_cc1 -fsyntax-only -verify %t/testing.cpp -std=c++26 -fexceptions -DTRANSPARENT_DECL=1 +// RUN: %clang_cc1 -fsyntax-only -verify %t/module_testing.cppm -std=c++26 -fexceptions -DTRANSPARENT_DECL=2 + +//--- module_testing.cppm // expected-no-diagnostics -#if TRANSPARENT_DECL==2 export module Testing; -#endif +#include "testing.inc" + +//--- testing.cpp +// expected-no-diagnostics +#include "testing.inc" + +//--- testing.inc namespace std { template struct type_identity {}; using size_t = __SIZE_TYPE__; diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp index a8c78f6304ca..5210354a66d4 100644 --- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp +++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp @@ -166,7 +166,7 @@ static_assert(__builtin_is_replaceable(const volatile int)); static_assert(__builtin_is_replaceable(void())); // expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(void ())}} \ // expected-note@-1 {{'void ()' is not replaceable}} \ -// expected-note@-1 {{because it not a scalar or class type}} +// expected-note@-1 {{because it is not a scalar or class type}} struct B { virtual ~B(); diff --git a/clang/test/SemaCXX/typo-correction-crash.cpp b/clang/test/SemaCXX/typo-correction-crash.cpp index 2a77c9df505e..434b70e3c509 100644 --- a/clang/test/SemaCXX/typo-correction-crash.cpp +++ b/clang/test/SemaCXX/typo-correction-crash.cpp @@ -4,10 +4,10 @@ auto check1() { return s; // expected-error {{use of undeclared identifier 's'}} } -int test = 11; // expected-note 2 {{'test' declared here}} +int test = 11; // expected-note 3 {{'test' declared here}} auto check2() { return "s"; - return tes; // expected-error {{use of undeclared identifier 'tes'; did you mean 'test'?}} + return tes; // expected-error {{use of undeclared identifier 'tes'}} // expected-error@-1 {{deduced as 'int' here but deduced as 'const char *' in earlier}} } @@ -16,9 +16,8 @@ template struct is_same { static constexpr bool value = true; }; auto L1 = [] { return s; }; // expected-error {{use of undeclared identifier 's'}} using T1 = decltype(L1()); -// FIXME: Suppress the 'undeclared identifier T1' diagnostic, the UsingDecl T1 is discarded because of an invalid L1(). -static_assert(is_same::value, "Return statement should be discarded"); // expected-error {{use of undeclared identifier 'T1'}} -auto L2 = [] { return tes; }; // expected-error {{use of undeclared identifier 'tes'; did you mean 'test'?}} +static_assert(is_same::value, "Return statement should be discarded"); +auto L2 = [] { return tes; }; // expected-error {{use of undeclared identifier 'tes'}} using T2 = decltype(L2()); static_assert(is_same::value, "Return statement was corrected"); @@ -32,13 +31,13 @@ FooRecord::NestedNamespace::type x; // expected-error {{no member named 'NestedN void cast_expr(int g) { +int(n)(g); } // expected-error {{undeclared identifier 'n'}} -void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}} +void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}} \ + expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}} namespace NoCrash { class S { void Function(int a) { - unknown1(unknown2, Function, unknown3); // expected-error 2{{use of undeclared identifier}} \ - expected-error {{reference to non-static member function must be called}} + unknown1(unknown2, Function, unknown3); // expected-error 2{{use of undeclared identifier}} } }; } @@ -46,8 +45,6 @@ class S { namespace NoCrashOnCheckArgAlignment { template void b(a &); void test() { - for (auto file_data :b(files_db_data)); // expected-error {{use of undeclared identifier 'files_db_data'; did you mean 'file_data'?}} \ - // expected-note {{'file_data' declared here}} \ - // expected-error {{cannot use type 'void' as a range}} + for (auto file_data :b(files_db_data)); // expected-error {{use of undeclared identifier 'files_db_data'}} } } diff --git a/clang/test/SemaCXX/typo-correction-cxx11.cpp b/clang/test/SemaCXX/typo-correction-cxx11.cpp index 8c588203cc12..9eb5f9c29962 100644 --- a/clang/test/SemaCXX/typo-correction-cxx11.cpp +++ b/clang/test/SemaCXX/typo-correction-cxx11.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s namespace PR23186 { -decltype(ned); // expected-error-re {{use of undeclared identifier 'ned'{{$}}}} +decltype(ned); // expected-error {{use of undeclared identifier 'ned'}} // The code below was triggering an UNREACHABLE in ASTContext::getTypeInfoImpl // once the above code failed to recover properly after making the bogus // correction of 'ned' to 'new'. @@ -19,8 +19,9 @@ struct S { namespace PR23140 { auto lneed = gned.*[] {}; // expected-error-re {{use of undeclared identifier 'gned'{{$}}}} -void test(int aaa, int bbb, int thisvar) { // expected-note {{'thisvar' declared here}} - int thatval = aaa * (bbb + thatvar); // expected-error {{use of undeclared identifier 'thatvar'; did you mean 'thisvar'?}} +void test(int aaa, int bbb, int thisvar) { + int thatval = aaa * (bbb + thatvar); // expected-error {{use of undeclared identifier 'thatvar'; did you mean 'thatval'}} \ + expected-note {{'thatval' declared here}} } } @@ -54,7 +55,7 @@ void run(A *annotations) { auto &annotation = *annotations; auto new_it = new_annotations.find(5); - auto &new_anotation = new_it.second; // expected-note {{'new_anotation' declared here}} - new_annotation->Swap(&annotation); // expected-error {{use of undeclared identifier 'new_annotation'; did you mean 'new_anotation'?}} + auto &new_anotation = new_it.second; + new_annotation->Swap(&annotation); // expected-error {{use of undeclared identifier 'new_annotation'}} } } diff --git a/clang/test/SemaCXX/typo-correction-delayed.cpp b/clang/test/SemaCXX/typo-correction-delayed.cpp deleted file mode 100644 index fdb1f740fda6..000000000000 --- a/clang/test/SemaCXX/typo-correction-delayed.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -Wno-c++11-extensions %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s - -struct A {}; -struct B {}; -struct D { - A fizbin; // expected-note 2 {{declared here}} - A foobar; // expected-note 2 {{declared here}} - B roxbin; // expected-note 2 {{declared here}} - B toobad; // expected-note 2 {{declared here}} - void BooHoo(); - void FoxBox(); -}; - -void something(A, B); -void test() { - D obj; - something(obj.fixbin, // expected-error {{did you mean 'fizbin'?}} - obj.toobat); // expected-error {{did you mean 'toobad'?}} - something(obj.toobat, // expected-error {{did you mean 'foobar'?}} - obj.fixbin); // expected-error {{did you mean 'roxbin'?}} - something(obj.fixbin, // expected-error {{did you mean 'fizbin'?}} - obj.fixbin); // expected-error {{did you mean 'roxbin'?}} - something(obj.toobat, // expected-error {{did you mean 'foobar'?}} - obj.toobat); // expected-error {{did you mean 'toobad'?}} - // Both members could be corrected to methods, but that isn't valid. - something(obj.boohoo, // expected-error-re {{no member named 'boohoo' in 'D'{{$}}}} - obj.foxbox); // expected-error-re {{no member named 'foxbox' in 'D'{{$}}}} - // The first argument has a usable correction but the second doesn't. - something(obj.boobar, // expected-error-re {{no member named 'boobar' in 'D'{{$}}}} - obj.foxbox); // expected-error-re {{no member named 'foxbox' in 'D'{{$}}}} -} - -// Ensure the delayed typo correction does the right thing when trying to -// recover using a seemingly-valid correction for which a valid expression to -// replace the TypoExpr cannot be created (but which does have a second -// correction candidate that would be a valid and usable correction). -class Foo { -public: - template <> void testIt(); // expected-error {{no function template matches}} - void textIt(); // expected-note {{'textIt' declared here}} -}; -void testMemberExpr(Foo *f) { - f->TestIt(); // expected-error {{no member named 'TestIt' in 'Foo'; did you mean 'textIt'?}} -} - -void callee(double, double); -void testNoCandidates() { - callee(xxxxxx, // expected-error-re {{use of undeclared identifier 'xxxxxx'{{$}}}} - zzzzzz); // expected-error-re {{use of undeclared identifier 'zzzzzz'{{$}}}} -} - -class string {}; -struct Item { - void Nest(); - string text(); - Item* next(); // expected-note {{'next' declared here}} -}; -void testExprFilter(Item *i) { - Item *j; - j = i->Next(); // expected-error {{no member named 'Next' in 'Item'; did you mean 'next'?}} -} - -// Test that initializer expressions are handled correctly and that the type -// being initialized is taken into account when choosing a correction. -namespace initializerCorrections { -struct Node { - string text() const; - // Node* Next() is not implemented yet -}; -void f(Node *node) { - // text is only an edit distance of 1 from Next, but would trigger type - // conversion errors if used in this initialization expression. - Node *next = node->Next(); // expected-error-re {{no member named 'Next' in 'initializerCorrections::Node'{{$}}}} -} - -struct LinkedNode { - LinkedNode* next(); // expected-note {{'next' declared here}} - string text() const; -}; -void f(LinkedNode *node) { - // text and next are equidistant from Next, but only one results in a valid - // initialization expression. - LinkedNode *next = node->Next(); // expected-error {{no member named 'Next' in 'initializerCorrections::LinkedNode'; did you mean 'next'?}} -} - -struct NestedNode { - NestedNode* Nest(); - NestedNode* next(); - string text() const; -}; -void f(NestedNode *node) { - // There are two equidistant, usable corrections for Next: next and Nest - NestedNode *next = node->Next(); // expected-error-re {{no member named 'Next' in 'initializerCorrections::NestedNode'{{$}}}} -} -} - -namespace PR21669 { -void f(int *i) { - // Check that arguments to a builtin with custom type checking are corrected - // properly, since calls to such builtins bypass much of the normal code path - // for building and checking the call. - __atomic_load(i, i, something_something); // expected-error-re {{use of undeclared identifier 'something_something'{{$}}}} -} -} - -const int DefaultArg = 9; // expected-note {{'DefaultArg' declared here}} -template struct S {}; // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}} -S<1> s; - -namespace foo {} -void test_paren_suffix() { - foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} -#if __cplusplus <= 199711L - // expected-error@-2 {{expected expression}} -#endif -} - -const int kNum = 10; // expected-note {{'kNum' declared here}} -class SomeClass { - int Kind; -public: - explicit SomeClass() : Kind(kSum) {} // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}} -}; - -// There used to be an issue with typo resolution inside overloads. -struct AssertionResult { ~AssertionResult(); }; -AssertionResult Overload(const char *a); -AssertionResult Overload(int a); -void UseOverload() { - // expected-note@+1 {{'result' declared here}} - const char *result; - // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}} - Overload(resulta); -} - -namespace PR21925 { -struct X { - int get() { return 7; } // expected-note {{'get' declared here}} -}; -void test() { - X variable; // expected-note {{'variable' declared here}} - - // expected-error@+2 {{use of undeclared identifier 'variableX'; did you mean 'variable'?}} - // expected-error@+1 {{no member named 'getX' in 'PR21925::X'; did you mean 'get'?}} - int x = variableX.getX(); -} -} - -namespace PR21905 { -int (*a)() = (void)Z; // expected-error-re {{use of undeclared identifier 'Z'{{$}}}} \ - // expected-error {{cannot initialize a variable of type 'int (*)()' with an rvalue of type 'void'}} -} - -namespace PR21947 { -int blue; // expected-note {{'blue' declared here}} -__typeof blur y; // expected-error {{use of undeclared identifier 'blur'; did you mean 'blue'?}} -} - -namespace PR22092 { -a = b ? : 0; // expected-error {{a type specifier is required for all declarations}} \ - // expected-error-re {{use of undeclared identifier 'b'{{$}}}} -} - -extern long clock (void); -struct Pointer { - void set_xpos(int); - void set_ypos(int); -}; -void MovePointer(Pointer &Click, int x, int y) { // expected-note 2 {{'Click' declared here}} - click.set_xpos(x); // expected-error {{use of undeclared identifier 'click'; did you mean 'Click'?}} - click.set_ypos(x); // expected-error {{use of undeclared identifier 'click'; did you mean 'Click'?}} -} - -namespace PR22250 { -// expected-error@+4 {{use of undeclared identifier 'size_t'; did you mean 'sizeof'?}} -// expected-error-re@+3 {{use of undeclared identifier 'y'{{$}}}} -// expected-error-re@+2 {{use of undeclared identifier 'z'{{$}}}} -// expected-error@+1 {{expected ';' after top level declarator}} -int getenv_s(size_t *y, char(&z)) {} -} - -namespace PR22291 { -template void f() { - unsigned *prio_bits_array; // expected-note {{'prio_bits_array' declared here}} - // expected-error@+1 {{use of undeclared identifier 'prio_op_array'; did you mean 'prio_bits_array'?}} - __atomic_store_n(prio_op_array + I, false, __ATOMIC_RELAXED); -} -} - -namespace PR22297 { -double pow(double x, double y); -struct TimeTicks { - static void Now(); // expected-note {{'Now' declared here}} -}; -void f() { - TimeTicks::now(); // expected-error {{no member named 'now' in 'PR22297::TimeTicks'; did you mean 'Now'?}} -} -} - -namespace PR23005 { -void f() { int a = Unknown::b(c); } // expected-error {{use of undeclared identifier 'Unknown'}} -// expected-error@-1 {{use of undeclared identifier 'c'}} -} - -namespace PR23350 { -int z = 1 ? N : ; // expected-error {{expected expression}} -// expected-error-re@-1 {{use of undeclared identifier 'N'{{$}}}} -} - -// PR 23285. This test must be at the end of the file to avoid additional, -// unwanted diagnostics. -// expected-error-re@+2 {{use of undeclared identifier 'uintmax_t'{{$}}}} -// expected-error@+1 {{expected ';' after top level declarator}} -unsigned int a = 0(uintmax_t diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp index 45f42c426035..e4dadf83e0a0 100644 --- a/clang/test/SemaCXX/typo-correction.cpp +++ b/clang/test/SemaCXX/typo-correction.cpp @@ -3,7 +3,6 @@ namespace PR21817{ int a(-rsing[2]); // expected-error {{undeclared identifier 'rsing'; did you mean 'using'?}} - // expected-error@-1 {{expected expression}} } struct errc { @@ -43,14 +42,14 @@ inline error_condition make_error_condition(errc _e) { // refer to a base class or non-static data member. struct BaseType { }; struct Derived : public BaseType { // expected-note {{base class 'BaseType' specified here}} - static int base_type; // expected-note {{'base_type' declared here}} + static int base_type; Derived() : basetype() {} // expected-error{{initializer 'basetype' does not name a non-static data member or base class; did you mean the base class 'BaseType'?}} }; // Test the improvement from passing a callback object to CorrectTypo in // the helper function LookupMemberExprInRecord. int get_type(struct Derived *st) { - return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'; did you mean 'base_type'?}} + return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'}} } // In this example, somename should not be corrected to the cached correction @@ -212,12 +211,11 @@ namespace PR13051 { }; void foo(); // expected-note{{'foo' declared here}} - void g(void(*)()); // expected-note{{candidate function not viable}} - void g(bool(S::*)() const); // expected-note{{candidate function not viable}} + void g(void(*)()); + void g(bool(S::*)() const); void test() { - g(&S::tempalte f); // expected-error{{did you mean 'template'?}} \ - // expected-error{{no matching function for call to 'g'}} + g(&S::tempalte f); // expected-error{{did you mean 'template'?}} g(&S::opeartor bool); // expected-error{{did you mean 'operator'?}} g(&S::foo); // expected-error{{no member named 'foo' in 'PR13051::S'; did you mean simply 'foo'?}} } @@ -251,13 +249,13 @@ namespace b6956809_test1 { struct S1 { void method(A*); // no note here - void method(B*); // expected-note{{'method' declared here}} + void method(B*); }; void test1() { B b; S1 s; - s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S1'; did you mean 'method'}} + s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S1'}} } struct S2 { @@ -275,15 +273,15 @@ namespace b6956809_test1 { } namespace b6956809_test2 { - template struct Err { typename T::error n; }; // expected-error{{type 'void *' cannot be used prior to '::' because it has no members}} + template struct Err { typename T::error n; }; struct S { - template typename Err::type method(T); // expected-note{{in instantiation of template class 'b6956809_test2::Err' requested here}} - template int method(T *); // expected-note{{'method' declared here}} + template typename Err::type method(T); + template int method(T *); }; void test() { S s; - int k = s.methodd((void*)0); // expected-error{{no member named 'methodd' in 'b6956809_test2::S'; did you mean 'method'?}} expected-note{{while substituting deduced template arguments into function template 'method' [with T = void *]}} + int k = s.methodd((void*)0); // expected-error{{no member named 'methodd' in 'b6956809_test2::S'}} } } @@ -309,12 +307,12 @@ struct A { void CreateBar(float, float); }; struct B : A { - using A::CreateFoo; // expected-note {{'CreateFoo' declared here}} - void CreateFoo(int, int); // expected-note {{'CreateFoo' declared here}} + using A::CreateFoo; + void CreateFoo(int, int); }; void f(B &x) { - x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} - x.Createfoo(0.f,0.f); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} + x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'}} + x.Createfoo(0.f,0.f); // expected-error {{no member named 'Createfoo' in 'PR13387::B'}} } } @@ -649,12 +647,12 @@ class AddObservation { // expected-note {{declared here}} namespace testNonStaticMemberHandling { struct Foo { - bool usesMetadata; // expected-note {{'usesMetadata' declared here}} + bool usesMetadata; }; int test(Foo f) { if (UsesMetadata) // expected-error-re {{use of undeclared identifier 'UsesMetadata'{{$}}}} return 5; - if (f.UsesMetadata) // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'; did you mean 'usesMetadata'?}} + if (f.UsesMetadata) // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'}} return 11; return 0; } @@ -707,7 +705,7 @@ using C::D::Foofoo; // expected-error {{no member named 'Foofoo' in namespace ' int d = ? L : d; // expected-error {{expected expression}} expected-error {{undeclared identifier}} struct B0 { - int : 0 | // expected-error {{invalid operands to binary expression}} + int : 0 | (struct B0)e; // expected-error {{use of undeclared identifier}} }; diff --git a/clang/test/SemaCXX/unique_object_duplication.cpp b/clang/test/SemaCXX/unique_object_duplication.cpp index 4b41bfbfdc2f..ff3b85d19fa6 100644 --- a/clang/test/SemaCXX/unique_object_duplication.cpp +++ b/clang/test/SemaCXX/unique_object_duplication.cpp @@ -1,7 +1,9 @@ -// RUN: %clang_cc1 -fsyntax-only -verify=hidden -Wunique-object-duplication -fvisibility=hidden -Wno-unused-value %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wunique-object-duplication -Wno-unused-value %s -// The check is currently disabled on windows in MSVC-like environments. The test should fail because we're not getting the expected warnings. -// XFAIL: target={{.*}}-windows-msvc, {{.*}}-ps{{(4|5)(-.+)?}} +// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \ +// RUN: -verify -triple=x86_64-pc-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \ +// RUN: -verify=hidden -triple=x86_64-pc-linux-gnu -fvisibility=hidden %s +// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \ +// RUN: -verify=windows -triple=x86_64-windows-msvc -DWINDOWS_TEST -fdeclspec %s #include "unique_object_duplication.h" diff --git a/clang/test/SemaCXX/unique_object_duplication.h b/clang/test/SemaCXX/unique_object_duplication.h index 537429d9ebda..bd0ee6bd14d6 100644 --- a/clang/test/SemaCXX/unique_object_duplication.h +++ b/clang/test/SemaCXX/unique_object_duplication.h @@ -3,8 +3,14 @@ * See the warning's documentation for more information. */ +#ifdef WINDOWS_TEST +#define HIDDEN +// dllimport also suffices for visibility, but those can't have definitions +#define VISIBLE __declspec(dllexport) +#else #define HIDDEN __attribute__((visibility("hidden"))) -#define DEFAULT __attribute__((visibility("default"))) +#define VISIBLE __attribute__((visibility("default"))) +#endif // Helper functions constexpr int init_constexpr(int x) { return x; }; @@ -17,10 +23,11 @@ namespace StaticLocalTest { inline void has_static_locals_external() { // Mutable - static int disallowedStatic1 = 0; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + static int disallowedStatic1 = 0; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} // Initialization might run more than once - static const double disallowedStatic2 = disallowedStatic1++; // hidden-warning {{initialization of 'disallowedStatic2' may run twice when built into a shared library: it has hidden visibility and external linkage}} - + static const double disallowedStatic2 = disallowedStatic1++; // hidden-warning {{initialization of 'disallowedStatic2' may run twice when built into a shared library: it has external linkage and hidden visibility}} + // windows-warning@-1 {{initialization of 'disallowedStatic2' may run twice when built into a shared library: it has external linkage and no import/export annotation}} // OK, because immutable and compile-time-initialized static constexpr int allowedStatic1 = 0; static const float allowedStatic2 = 1; @@ -53,29 +60,33 @@ void has_static_locals_anon() { static double allowedStatic2 = init_dynamic(2); static char allowedStatic3 = []() { return allowedStatic1++; }(); static constexpr int allowedStatic4 = init_constexpr(3); -} +} } // Anonymous namespace HIDDEN inline void static_local_always_hidden() { - static int disallowedStatic1 = 3; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - // expected-warning@-1 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + static int disallowedStatic1 = 3; // hidden-warning {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // expected-warning@-1 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-2 {{'disallowedStatic1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} { - static int disallowedStatic2 = 3; // hidden-warning {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - // expected-warning@-1 {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + static int disallowedStatic2 = 3; // hidden-warning {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // expected-warning@-1 {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-2 {{'disallowedStatic2' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} } auto lmb = []() { - static int disallowedStatic3 = 3; // hidden-warning {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - // expected-warning@-1 {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + static int disallowedStatic3 = 3; // hidden-warning {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // expected-warning@-1 {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-2 {{'disallowedStatic3' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} }; } -DEFAULT void static_local_never_hidden() { - static int allowedStatic1 = 3; +// Always visible +VISIBLE void static_local_never_hidden() { + static int allowedStatic1 = 3; { - static int allowedStatic2 = 3; + static int allowedStatic2 = 3; } auto lmb = []() { @@ -96,7 +107,8 @@ inline void has_regular_local() { inline void has_thread_local() { // thread_local variables are static by default - thread_local int disallowedThreadLocal = 0; // hidden-warning {{'disallowedThreadLocal' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + thread_local int disallowedThreadLocal = 0; // hidden-warning {{'disallowedThreadLocal' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'disallowedThreadLocal' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} } // Functions themselves are always immutable, so referencing them is okay @@ -109,11 +121,13 @@ inline auto& allowedFunctionReference = has_static_locals_external; ******************************************************************************/ namespace GlobalTest { // Mutable - inline float disallowedGlobal1 = 3.14; // hidden-warning {{'disallowedGlobal1' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - - // Initialization might run more than once - inline const double disallowedGlobal5 = disallowedGlobal1++; // hidden-warning {{initialization of 'disallowedGlobal5' may run twice when built into a shared library: it has hidden visibility and external linkage}} + inline float disallowedGlobal1 = 3.14; // hidden-warning {{'disallowedGlobal1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'disallowedGlobal1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} + + // Initialization might run more than once + inline const double disallowedGlobal5 = disallowedGlobal1++; // hidden-warning {{initialization of 'disallowedGlobal5' may run twice when built into a shared library: it has external linkage and hidden visibility}} + // windows-warning@-1 {{initialization of 'disallowedGlobal5' may run twice when built into a shared library: it has external linkage and no import/export annotation}} // OK because internal linkage, so duplication is intended static float allowedGlobal1 = 3.14; const double allowedGlobal2 = init_dynamic(2); @@ -129,34 +143,52 @@ namespace GlobalTest { // We don't warn on this because non-inline variables can't (legally) appear // in more than one TU. float allowedGlobal9 = 3.14; - + // Pointers need to be double-const-qualified - inline float& nonConstReference = disallowedGlobal1; // hidden-warning {{'nonConstReference' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + inline float& nonConstReference = disallowedGlobal1; // hidden-warning {{'nonConstReference' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'nonConstReference' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} const inline int& constReference = allowedGlobal5; - inline int* nonConstPointerToNonConst = nullptr; // hidden-warning {{'nonConstPointerToNonConst' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - inline int const* nonConstPointerToConst = nullptr; // hidden-warning {{'nonConstPointerToConst' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} - inline int* const constPointerToNonConst = nullptr; // hidden-warning {{'constPointerToNonConst' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + inline int* nonConstPointerToNonConst = nullptr; // hidden-warning {{'nonConstPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'nonConstPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} + inline int const* nonConstPointerToConst = nullptr; // hidden-warning {{'nonConstPointerToConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'nonConstPointerToConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} + inline int* const constPointerToNonConst = nullptr; // hidden-warning {{'constPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'constPointerToNonConst' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} inline int const* const constPointerToConst = nullptr; // Don't warn on new because it tends to generate false positives inline int const* const constPointerToConstNew = new int(7); inline int const * const * const * const nestedConstPointer = nullptr; - inline int const * const ** const * const nestedNonConstPointer = nullptr; // hidden-warning {{'nestedNonConstPointer' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + inline int const * const ** const * const nestedNonConstPointer = nullptr; // hidden-warning {{'nestedNonConstPointer' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'nestedNonConstPointer' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} struct Test { - static inline float disallowedStaticMember1; // hidden-warning {{'disallowedStaticMember1' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + static inline float disallowedStaticMember1; // hidden-warning {{'disallowedStaticMember1' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'disallowedStaticMember1' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} // Defined below, in the header file - static float disallowedStaticMember2; + static float disallowedStaticMember2; // Defined in the cpp file, so won't get duplicated static float allowedStaticMember1; + // Always visible + VISIBLE static inline float allowedStaticMember2 = 0.0; + // Tests here are sparse because the AddrTest case below will define plenty // more, which aren't problematic to define (because they're immutable), but // may still cause problems if their address is taken. }; - inline float Test::disallowedStaticMember2 = 2.3; // hidden-warning {{'disallowedStaticMember2' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}} + inline float Test::disallowedStaticMember2 = 2.3; // hidden-warning {{'disallowedStaticMember2' may be duplicated when built into a shared library: it is mutable, with external linkage and hidden visibility}} + // windows-warning@-1 {{'disallowedStaticMember2' may be duplicated when built into a shared library: it is mutable, with external linkage and no import/export annotation}} + + // This is always visible, so nothing inside it will get duplicated + struct VISIBLE NeverHidden { + static inline float allowedStaticMember3; + static float allowedStaticMember4; + }; + + inline float NeverHidden::allowedStaticMember4 = 3.4; } // namespace GlobalTest /****************************************************************************** @@ -165,7 +197,7 @@ namespace GlobalTest { namespace TemplateTest { -// We never warn inside templates because it's frequently infeasible to actually +// We never warn inside templates because it's usually infeasible to actually // fix the warning. template diff --git a/clang/test/SemaCXX/virtuals.cpp b/clang/test/SemaCXX/virtuals.cpp index 2a22ab9fc2b0..f6f52d51f650 100644 --- a/clang/test/SemaCXX/virtuals.cpp +++ b/clang/test/SemaCXX/virtuals.cpp @@ -58,10 +58,8 @@ struct Base { }; struct Derived final : Base { - virtual ~Derived() = defaul; // #default + virtual ~Derived() = defaul; // expected-error {{use of undeclared identifier 'defaul'}} } do_not_crash; -// expected-error@#default {{initializer on function does not look like a pure-specifier}} -// expected-error@#default {{use of undeclared identifier 'defaul'}} } namespace VirtualFriend { diff --git a/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl b/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl new file mode 100644 index 000000000000..e5152e72d480 --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify + +// expected-error@+1 {{resource ranges b[42;42] and b[42;42] overlap within space = 0 and visibility = All}} +[RootSignature("CBV(b42), CBV(b42)")] +void bad_root_signature_0() {} + +// expected-error@+1 {{resource ranges t[0;0] and t[0;0] overlap within space = 3 and visibility = All}} +[RootSignature("SRV(t0, space = 3), SRV(t0, space = 3)")] +void bad_root_signature_1() {} + +// expected-error@+1 {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +[RootSignature("UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)")] +void bad_root_signature_2() {} + +// expected-error@+1 {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +[RootSignature("UAV(u0, visibility = SHADER_VISIBILITY_ALL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)")] +void bad_root_signature_3() {} + +// expected-error@+1 {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +[RootSignature("UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_ALL)")] +void bad_root_signature_4() {} diff --git a/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl b/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl new file mode 100644 index 000000000000..5778fb2ae4eb --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify + +// expected-no-diagnostics + +[RootSignature("CBV(b0), CBV(b1)")] +void valid_root_signature_0() {} + +[RootSignature("CBV(b0, visibility = SHADER_VISIBILITY_DOMAIN), CBV(b0, visibility = SHADER_VISIBILITY_PIXEL)")] +void valid_root_signature_1() {} + +[RootSignature("CBV(b0, space = 1), CBV(b0, space = 2)")] +void valid_root_signature_2() {} + +[RootSignature("CBV(b0), SRV(t0)")] +void valid_root_signature_3() {} diff --git a/clang/test/SemaHLSL/num_threads.hlsl b/clang/test/SemaHLSL/num_threads.hlsl index b5f9ad6c33cd..96200312bbf6 100644 --- a/clang/test/SemaHLSL/num_threads.hlsl +++ b/clang/test/SemaHLSL/num_threads.hlsl @@ -10,6 +10,8 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel5.0-compute -x hlsl -ast-dump -o - %s -DFAIL -verify // RUN: %clang_cc1 -triple dxil-pc-shadermodel4.0-compute -x hlsl -ast-dump -o - %s -DFAIL -verify +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-compute -x hlsl -ast-dump -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + #if __SHADER_TARGET_STAGE == __SHADER_STAGE_COMPUTE || __SHADER_TARGET_STAGE == __SHADER_STAGE_MESH || __SHADER_TARGET_STAGE == __SHADER_STAGE_AMPLIFICATION || __SHADER_TARGET_STAGE == __SHADER_STAGE_LIBRARY #ifdef FAIL @@ -88,24 +90,30 @@ int entry() { // Because these two attributes match, they should both appear in the AST [numthreads(2,2,1)] -// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 2 2 1 +// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 2 2 1 int secondFn(); [numthreads(2,2,1)] -// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 2 2 1 +// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 2 2 1 int secondFn() { return 1; } [numthreads(4,2,1)] -// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 4 2 1 +// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 4 2 1 int onlyOnForwardDecl(); -// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} Inherited 4 2 1 +// CHECK: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} Inherited 4 2 1 int onlyOnForwardDecl() { return 1; } +#ifdef __spirv__ +[numthreads(4,2,128)] +// CHECK-SPIRV: HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 4 2 128 +int largeZ(); +#endif + #else // Vertex and Pixel only beyond here // expected-error-re@+1 {{attribute 'numthreads' is unsupported in '{{[A-Za-z]+}}' shaders, requires one of the following: compute, amplification, mesh}} [numthreads(1,1,1)] diff --git a/clang/test/SemaHLSL/vk.spec-constant.error.hlsl b/clang/test/SemaHLSL/vk.spec-constant.error.hlsl new file mode 100644 index 000000000000..24873d272a54 --- /dev/null +++ b/clang/test/SemaHLSL/vk.spec-constant.error.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -verify %s +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.8-compute -verify %s + +#ifndef __spirv__ +// expected-warning@+2{{'constant_id' attribute ignored}} +#endif +[[vk::constant_id(0)]] +const bool sc0 = true; + +#ifdef __spirv__ +// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}} +[[vk::constant_id(1)]] +const bool sc1 = sc0; // error + +// expected-warning@+1{{'constant_id' attribute only applies to external global variables}} +[[vk::constant_id(2)]] +static const bool sc2 = false; // error + +// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}} +[[vk::constant_id(3)]] +const bool sc3; // error + +// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}} +[[vk::constant_id(4)]] +bool sc4 = false; // error + +// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}} +[[vk::constant_id(5)]] +const int2 sc5 = {0,0}; // error + +[numthreads(1,1,1)] +void main() { + // expected-warning@+1{{'constant_id' attribute only applies to external global variables}} + [[vk::constant_id(6)]] + const bool sc6 = false; // error +} +#endif diff --git a/clang/test/SemaObjC/call-super-2.m b/clang/test/SemaObjC/call-super-2.m index 01acff70c230..885f392e353a 100644 --- a/clang/test/SemaObjC/call-super-2.m +++ b/clang/test/SemaObjC/call-super-2.m @@ -115,7 +115,7 @@ id objc_getClass(const char *s); @end @implementation B -- (instancetype)initWithCoder:(C *)coder { +- (instancetype)initWithCoder:(C *)coder { // expected-note {{'coder' declared here}} if (0 != (self = [super initWithCode:code])) // expected-error {{use of undeclared identifier 'code'}} expected-warning {{instance method '-initWithCode:' not found}} return (void *)0; return (void *)0; diff --git a/clang/test/SemaObjC/typo-correction-subscript.m b/clang/test/SemaObjC/typo-correction-subscript.m index 340f3cfe2743..6c09127dbb8d 100644 --- a/clang/test/SemaObjC/typo-correction-subscript.m +++ b/clang/test/SemaObjC/typo-correction-subscript.m @@ -7,8 +7,7 @@ @implementation Test - (void)rdar47403222:(Dictionary *)opts { [self undeclaredMethod:undeclaredArg]; - // expected-error@-1{{no visible @interface for 'Test' declares the selector 'undeclaredMethod:'}} - // expected-error@-2{{use of undeclared identifier 'undeclaredArg}} + // expected-error@-1{{use of undeclared identifier 'undeclaredArg}} opts[(__bridge id)undeclaredKey] = 0; // expected-error@-1{{use of undeclared identifier 'undeclaredKey'}} } diff --git a/clang/test/SemaObjC/undef-arg-super-method-call.m b/clang/test/SemaObjC/undef-arg-super-method-call.m index 11fd97f2c00d..b8cbe7f69f2f 100644 --- a/clang/test/SemaObjC/undef-arg-super-method-call.m +++ b/clang/test/SemaObjC/undef-arg-super-method-call.m @@ -11,12 +11,12 @@ @end @implementation DBGViewDebuggerSupport_iOS -+ (void)addViewLayerInfo:(id)aView; // expected-note {{'aView' declared here}} ++ (void)addViewLayerInfo:(id)aView; { - [super addViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'; did you mean 'aView'?}} + [super addViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'}} } -- (void)addInstViewLayerInfo:(id)aView; // expected-note {{'aView' declared here}} +- (void)addInstViewLayerInfo:(id)aView; { - [super addInstViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'; did you mean 'aView'?}} + [super addInstViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'}} } @end diff --git a/clang/test/SemaObjCXX/arc-type-conversion.mm b/clang/test/SemaObjCXX/arc-type-conversion.mm index 64cfd02ec18c..0d281bf3e5c4 100644 --- a/clang/test/SemaObjCXX/arc-type-conversion.mm +++ b/clang/test/SemaObjCXX/arc-type-conversion.mm @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s +@class NSString; +typedef unsigned __INTPTR_TYPE__ uintptr_t; + void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}} { void* voidp_val; @@ -72,6 +75,24 @@ void test_reinterpret_cast(__strong id *sip, __weak id *wip, (void)reinterpret_cast<__weak id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__weak id *' casts away qualifiers}} (void)reinterpret_cast<__weak id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__weak id *' casts away qualifiers}} (void)reinterpret_cast<__strong id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__strong id *' casts away qualifiers}} + + auto *ul = reinterpret_cast(sip); + (void)reinterpret_cast<__strong id *>(ul); + auto *wp = reinterpret_cast<__weak NSString *>(sip); + (void)reinterpret_cast<__strong id *>(wp); + (void)reinterpret_cast(csip); // expected-error {{reinterpret_cast from '__strong id const *' to 'unsigned long *' casts away qualifiers}} + (void)reinterpret_cast(csip); + const unsigned long *cul = nullptr; + (void)reinterpret_cast<__strong id *>(cul); // expected-error {{reinterpret_cast from 'const unsigned long *' to '__strong id *' casts away qualifiers}} + (void)reinterpret_cast(cul); + volatile __strong id *vsip = nullptr; + (void)reinterpret_cast(vsip); // expected-error {{reinterpret_cast from '__strong id volatile *' to 'unsigned long *' casts away qualifiers}} + (void)reinterpret_cast(vsip); + volatile unsigned long *vul = nullptr; + (void)reinterpret_cast<__strong id *>(vul); // expected-error {{reinterpret_cast from 'volatile unsigned long *' to '__strong id *' casts away qualifiers}} + (void)reinterpret_cast(vul); + auto uip = reinterpret_cast(sip); + (void)reinterpret_cast<__strong id *>(uip); // expected-error {{to '__strong id *' is disallowed with ARC}} } void test_cstyle_cast(__strong id *sip, __weak id *wip, @@ -194,8 +215,6 @@ typedef void (^Block)(); typedef void (^Block_strong)() __strong; typedef void (^Block_autoreleasing)() __autoreleasing; -@class NSString; - void ownership_transfer_in_cast(void *vp, Block *pblk) { __strong NSString **sip2 = static_cast(static_cast<__strong id *>(vp)); __strong NSString **&si2pref = static_cast(sip2); diff --git a/clang/test/SemaObjCXX/block-for-lambda-conversion.mm b/clang/test/SemaObjCXX/block-for-lambda-conversion.mm index 671e83dc2201..a3bcfab67719 100644 --- a/clang/test/SemaObjCXX/block-for-lambda-conversion.mm +++ b/clang/test/SemaObjCXX/block-for-lambda-conversion.mm @@ -8,19 +8,20 @@ enum NSEventMask { NSEventMaskLeftMouseDown = 1 }; -static const NSEventType NSFlagsChanged = NSEventTypeFlagsChanged; +static const NSEventType NSFlagsChanged = NSEventTypeFlagsChanged; // expected-note {{'NSFlagsChanged' declared here}} @interface NSObject @end @interface NSEvent : NSObject { } + (nullable id) -addMonitor:(NSEventMask)mask handler:(NSEvent *_Nullable (^)(NSEvent *))block; +addMonitor:(NSEventMask)mask handler:(NSEvent *_Nullable (^)(NSEvent *))block; // expected-note {{passing argument to parameter 'mask' here}} @end void test(id weakThis) { id m_flagsChangedEventMonitor = [NSEvent - addMonitor:NSFlagsChangedMask //expected-error {{use of undeclared identifier 'NSFlagsChangedMask'}} + addMonitor:NSFlagsChangedMask //expected-error {{use of undeclared identifier 'NSFlagsChangedMask'}} \ + expected-error {{cannot initialize a parameter of type 'NSEventMask' with an lvalue of type 'const NSEventType'}} handler:[weakThis](NSEvent *flagsChangedEvent) { return flagsChangedEvent; }]; diff --git a/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp index c6dbe4db2be6..0cf27666dd03 100644 --- a/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp @@ -119,8 +119,7 @@ struct HasInt { template void TestInst() { - // expected-error@+2{{no member named 'Invalid' in 'HasInt'}} - // expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}} + // expected-error@+1{{no member named 'Invalid' in 'HasInt'}} #pragma acc serial num_gangs(HasInt::Invalid) while(1); @@ -137,8 +136,7 @@ void TestInst() { #pragma acc parallel num_gangs(T::Invalid, 1) while(1); - // expected-error@+2{{no member named 'Invalid' in 'HasInt'}} - // expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}} + // expected-error@+1{{no member named 'Invalid' in 'HasInt'}} #pragma acc serial num_gangs(1, HasInt::Invalid) while(1); diff --git a/clang/test/SemaOpenCL/atomic-ops.cl b/clang/test/SemaOpenCL/atomic-ops.cl index 7a273546db77..babebba31e82 100644 --- a/clang/test/SemaOpenCL/atomic-ops.cl +++ b/clang/test/SemaOpenCL/atomic-ops.cl @@ -167,7 +167,7 @@ void syncscope_checks(atomic_int *Ap, int scope) { (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_all_devices); #if __OPENCL_C_VERSION__ < CL_VERSION_3_0 // expected-error@-2{{use of undeclared identifier 'memory_scope_all_devices'}} - // expected-note@* {{'memory_scope_all_svm_devices' declared here}} + // expected-note@opencl-c-base.h:*{{'memory_scope_all_svm_devices' declared here}} #endif (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_sub_group); (void)__opencl_atomic_load(Ap, memory_order_relaxed, scope); diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl new file mode 100644 index 000000000000..b69fcb5f445b --- /dev/null +++ b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl @@ -0,0 +1,6 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx1250 -verify -S -o - %s + +void test_setprio_inc_wg(short a) { + __builtin_amdgcn_s_setprio_inc_wg(a); // expected-error {{'__builtin_amdgcn_s_setprio_inc_wg' must be a constant integer}} +} diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250.cl b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250.cl new file mode 100644 index 000000000000..c5440ed1a75a --- /dev/null +++ b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250.cl @@ -0,0 +1,6 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx1200 -verify -S -o - %s + +void test() { + __builtin_amdgcn_s_setprio_inc_wg(1); // expected-error {{'__builtin_amdgcn_s_setprio_inc_wg' needs target feature setprio-inc-wg-inst}} +} diff --git a/clang/test/SemaOpenCL/clang-builtin-version.cl b/clang/test/SemaOpenCL/clang-builtin-version.cl index ec6eecee3106..21cbf2d8f28d 100644 --- a/clang/test/SemaOpenCL/clang-builtin-version.cl +++ b/clang/test/SemaOpenCL/clang-builtin-version.cl @@ -17,12 +17,8 @@ kernel void dse_builtins(void) { }); #if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0) && !defined(__opencl_c_device_enqueue) // expected-error@-10{{support disabled - compile with -fblocks or for OpenCL C 2.0 or OpenCL C 3.0 with __opencl_c_device_enqueue feature}} -// FIXME: the typo correction for the undeclared identifiers finds alternative -// suggestions, but instantiating the typo correction causes us to -// re-instantiate the argument to the call, which triggers the support -// diagnostic a second time. -// expected-error@-12 2{{support disabled - compile with -fblocks or for OpenCL C 2.0 or OpenCL C 3.0 with __opencl_c_device_enqueue feature}} -// expected-error@-10 2{{support disabled - compile with -fblocks or for OpenCL C 2.0 or OpenCL C 3.0 with __opencl_c_device_enqueue feature}} +// expected-error@-8 {{support disabled - compile with -fblocks or for OpenCL C 2.0 or OpenCL C 3.0 with __opencl_c_device_enqueue feature}} +// expected-error@-6 {{support disabled - compile with -fblocks or for OpenCL C 2.0 or OpenCL C 3.0 with __opencl_c_device_enqueue feature}} #endif } diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index e5d00491d3fb..bf505dec0ca1 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -853,3 +853,18 @@ template requires C auto TplClass::buggy() -> void {} } + +namespace GH139476 { + +namespace moo { + template + constexpr bool baa = true; + + template requires baa + void caw(); +} + +template requires moo::baa +void moo::caw() {} + +} diff --git a/clang/test/SemaTemplate/concepts-recovery-expr.cpp b/clang/test/SemaTemplate/concepts-recovery-expr.cpp index b338f3bc271b..6bed1790051f 100644 --- a/clang/test/SemaTemplate/concepts-recovery-expr.cpp +++ b/clang/test/SemaTemplate/concepts-recovery-expr.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++20 -verify %s -// expected-error@+1{{use of undeclared identifier 'b'}} -constexpr bool CausesRecoveryExpr = b; +// expected-error@+1 {{invalid operands to binary expression ('const char[5]' and 'float')}} +constexpr bool CausesRecoveryExpr = "test" + 1.0f; template concept ReferencesCRE = CausesRecoveryExpr; diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index a99df2390a55..62a4f95d79c7 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -814,11 +814,7 @@ static_assert(invalid also here ; // expected-error{{use of undeclared iden int foo() { bool b; - b = invalid not just in declarations; // expected-error{{expected ';' after expression}} - // expected-error@-1{{use of undeclared identifier 'invalid'}} - // expected-error@-2{{expected ';' after expression}} - // expected-error@-3{{use of undeclared identifier 'just'}} - // expected-error@-4{{unknown type name 'in'}} + b = invalid not just in declarations; // expected-error{{use of undeclared identifier 'invalid'}} return b; } } // namespace GH48182 diff --git a/clang/test/SemaTemplate/instantiate-static-var.cpp b/clang/test/SemaTemplate/instantiate-static-var.cpp index 63d8366b617c..6602670af901 100644 --- a/clang/test/SemaTemplate/instantiate-static-var.cpp +++ b/clang/test/SemaTemplate/instantiate-static-var.cpp @@ -1,11 +1,13 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -std=c++98 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11 -std=c++11 %s template class X { public: - static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} + static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} \ + // cxx11-note {{division by zero}} \ + // cxx98-note {{subexpression not valid}} }; int array1[X::value == 5? 1 : -1]; diff --git a/clang/test/SemaTemplate/typo-variadic.cpp b/clang/test/SemaTemplate/typo-variadic.cpp index c9b777aebbe9..48306fb9ce80 100644 --- a/clang/test/SemaTemplate/typo-variadic.cpp +++ b/clang/test/SemaTemplate/typo-variadic.cpp @@ -1,2 +1,2 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify -int x = m(s...); // expected-error{{pack expansion does not}} expected-error{{undeclared identifier}} +int x = m(s...); // expected-error{{undeclared identifier}} diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index b22d3aaf3183..c0efbb7588cc 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -244,17 +244,17 @@ static bool fillRanges(MemoryBuffer *Code, DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts); SourceManager Sources(Diagnostics, Files); - FileID ID = createInMemoryFile("", *Code, Sources, Files, - InMemoryFileSystem.get()); + const auto ID = createInMemoryFile("", *Code, Sources, Files, + InMemoryFileSystem.get()); if (!LineRanges.empty()) { if (!Offsets.empty() || !Lengths.empty()) { errs() << "error: cannot use -lines with -offset/-length\n"; return true; } - for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) { + for (const auto &LineRange : LineRanges) { unsigned FromLine, ToLine; - if (parseLineRange(LineRanges[i], FromLine, ToLine)) { + if (parseLineRange(LineRange, FromLine, ToLine)) { errs() << "error: invalid : pair\n"; return true; } @@ -266,12 +266,12 @@ static bool fillRanges(MemoryBuffer *Code, errs() << "error: start line should not exceed end line\n"; return true; } - SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1); - SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX); + const auto Start = Sources.translateLineCol(ID, FromLine, 1); + const auto End = Sources.translateLineCol(ID, ToLine, UINT_MAX); if (Start.isInvalid() || End.isInvalid()) return true; - unsigned Offset = Sources.getFileOffset(Start); - unsigned Length = Sources.getFileOffset(End) - Offset; + const auto Offset = Sources.getFileOffset(Start); + const auto Length = Sources.getFileOffset(End) - Offset; Ranges.push_back(tooling::Range(Offset, Length)); } return false; @@ -279,33 +279,33 @@ static bool fillRanges(MemoryBuffer *Code, if (Offsets.empty()) Offsets.push_back(0); - if (Offsets.size() != Lengths.size() && - !(Offsets.size() == 1 && Lengths.empty())) { - errs() << "error: number of -offset and -length arguments must match.\n"; + const bool EmptyLengths = Lengths.empty(); + unsigned Length = 0; + if (Offsets.size() == 1 && EmptyLengths) { + Length = Sources.getFileOffset(Sources.getLocForEndOfFile(ID)) - Offsets[0]; + } else if (Offsets.size() != Lengths.size()) { + errs() << "error: number of -offset and -length arguments must match\n"; return true; } - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - if (Offsets[i] >= Code->getBufferSize()) { - errs() << "error: offset " << Offsets[i] << " is outside the file\n"; + for (unsigned I = 0, E = Offsets.size(), CodeSize = Code->getBufferSize(); + I < E; ++I) { + const auto Offset = Offsets[I]; + if (Offset >= CodeSize) { + errs() << "error: offset " << Offset << " is outside the file\n"; return true; } - SourceLocation Start = - Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]); - SourceLocation End; - if (i < Lengths.size()) { - if (Offsets[i] + Lengths[i] > Code->getBufferSize()) { - errs() << "error: invalid length " << Lengths[i] - << ", offset + length (" << Offsets[i] + Lengths[i] - << ") is outside the file.\n"; - return true; - } - End = Start.getLocWithOffset(Lengths[i]); - } else { - End = Sources.getLocForEndOfFile(ID); + if (!EmptyLengths) + Length = Lengths[I]; + if (Length == 0) { + errs() << "error: length should be at least 1\n"; + return true; } - unsigned Offset = Sources.getFileOffset(Start); - unsigned Length = Sources.getFileOffset(End) - Offset; - Ranges.push_back(tooling::Range(Offset, Length)); + if (Offset + Length > CodeSize) { + errs() << "error: invalid length " << Length << ", offset + length (" + << Offset + Length << ") is outside the file\n"; + return true; + } + Ranges.push_back(tooling::Range(Offset, Length - 1)); } return false; } diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 95b6f74af1f1..0f1fa8b329fd 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -268,7 +268,8 @@ Expected findProgram(StringRef Name, ArrayRef Paths) { bool linkerSupportsLTO(const ArgList &Args) { llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); return Triple.isNVPTX() || Triple.isAMDGPU() || - Args.getLastArgValue(OPT_linker_path_EQ).ends_with("lld"); + (!Triple.isGPU() && + Args.getLastArgValue(OPT_linker_path_EQ).ends_with("lld")); } /// Returns the hashed value for a constant string. @@ -310,22 +311,21 @@ Error relocateOffloadSection(const ArgList &Args, StringRef Output) { // Remove the old .llvm.offloading section to prevent further linking. ObjcopyArgs.emplace_back("--remove-section"); ObjcopyArgs.emplace_back(".llvm.offloading"); - for (StringRef Prefix : {"omp", "cuda", "hip"}) { - auto Section = (Prefix + "_offloading_entries").str(); - // Rename the offloading entires to make them private to this link unit. - ObjcopyArgs.emplace_back("--rename-section"); - ObjcopyArgs.emplace_back( - Args.MakeArgString(Section + "=" + Section + Suffix)); + StringRef Prefix = "llvm"; + auto Section = (Prefix + "_offload_entries").str(); + // Rename the offloading entires to make them private to this link unit. + ObjcopyArgs.emplace_back("--rename-section"); + ObjcopyArgs.emplace_back( + Args.MakeArgString(Section + "=" + Section + Suffix)); - // Rename the __start_ / __stop_ symbols appropriately to iterate over the - // newly renamed section containing the offloading entries. - ObjcopyArgs.emplace_back("--redefine-sym"); - ObjcopyArgs.emplace_back(Args.MakeArgString("__start_" + Section + "=" + - "__start_" + Section + Suffix)); - ObjcopyArgs.emplace_back("--redefine-sym"); - ObjcopyArgs.emplace_back(Args.MakeArgString("__stop_" + Section + "=" + - "__stop_" + Section + Suffix)); - } + // Rename the __start_ / __stop_ symbols appropriately to iterate over the + // newly renamed section containing the offloading entries. + ObjcopyArgs.emplace_back("--redefine-sym"); + ObjcopyArgs.emplace_back(Args.MakeArgString("__start_" + Section + "=" + + "__start_" + Section + Suffix)); + ObjcopyArgs.emplace_back("--redefine-sym"); + ObjcopyArgs.emplace_back(Args.MakeArgString("__stop_" + Section + "=" + + "__stop_" + Section + Suffix)); if (Error Err = executeCommands(*ObjcopyPath, ObjcopyArgs)) return Err; diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 921ba7aadd67..ce0770a51d65 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -85,6 +85,7 @@ static ScanningOutputFormat Format = ScanningOutputFormat::Make; static ScanningOptimizations OptimizeArgs; static std::string ModuleFilesDir; static bool EagerLoadModules; +static bool CacheNegativeStats = true; static unsigned NumThreads = 0; static std::string CompilationDB; static std::optional ModuleName; @@ -191,6 +192,8 @@ static void ParseArgs(int argc, char **argv) { EagerLoadModules = Args.hasArg(OPT_eager_load_pcm); + CacheNegativeStats = !Args.hasArg(OPT_no_cache_negative_stats); + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_j)) { StringRef S{A->getValue()}; if (!llvm::to_integer(S, NumThreads, 0)) { @@ -1080,8 +1083,9 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { }); }; - DependencyScanningService Service(ScanMode, Format, OptimizeArgs, - EagerLoadModules, /*TraceVFS=*/Verbose); + DependencyScanningService Service( + ScanMode, Format, OptimizeArgs, EagerLoadModules, /*TraceVFS=*/Verbose, + llvm::sys::toTimeT(std::chrono::system_clock::now()), CacheNegativeStats); llvm::Timer T; T.startTimer(); diff --git a/clang/tools/clang-scan-deps/Opts.td b/clang/tools/clang-scan-deps/Opts.td index 9cccbb3aaf0c..582ae60851e1 100644 --- a/clang/tools/clang-scan-deps/Opts.td +++ b/clang/tools/clang-scan-deps/Opts.td @@ -22,6 +22,7 @@ defm module_files_dir : Eq<"module-files-dir", def optimize_args_EQ : CommaJoined<["-", "--"], "optimize-args=">, HelpText<"Which command-line arguments of modules to optimize">; def eager_load_pcm : F<"eager-load-pcm", "Load PCM files eagerly (instead of lazily on import)">; +def no_cache_negative_stats : F<"no-cache-negative-stats", "Don't cache stat failures">; def j : Arg<"j", "Number of worker threads to use (default: use all concurrent threads)">; diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 635d03a88d10..a6301daa672c 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -598,7 +598,6 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::FunctionParmPackExprClass: case Stmt::UnresolvedLookupExprClass: - case Stmt::TypoExprClass: // A typo could actually be a DeclRef or a MemberRef K = CXCursor_DeclRefExpr; break; diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 873c6c492d18..a1285e4bc9bf 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -3754,6 +3754,13 @@ TEST_F(TokenAnnotatorTest, BraceKind) { ASSERT_EQ(Tokens.size(), 9u) << Tokens; EXPECT_BRACE_KIND(Tokens[4], BK_BracedInit); EXPECT_BRACE_KIND(Tokens[6], BK_BracedInit); + + Tokens = annotate("auto f1{&T::operator()};"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_BRACE_KIND(Tokens[2], BK_BracedInit); + // Not TT_FunctionDeclarationName. + EXPECT_TOKEN(Tokens[6], tok::kw_operator, TT_Unknown); + EXPECT_BRACE_KIND(Tokens[9], BK_BracedInit); } TEST_F(TokenAnnotatorTest, UnderstandsElaboratedTypeSpecifier) { diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index a7b258d5e537..459a3864887e 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -9,9 +9,12 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/VirtualFileSystem.h" #include "gtest/gtest.h" @@ -97,4 +100,52 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) { ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n"); } +TEST(CompilerInstance, MultipleInputsCleansFileIDs) { + auto VFS = makeIntrusiveRefCnt(); + VFS->addFile("a.cc", /*ModificationTime=*/{}, + MemoryBuffer::getMemBuffer(R"cpp( + #include "a.h" + )cpp")); + // Paddings of `void foo();` in the sources below are "important". We're + // testing against source locations from previous compilations colliding. + // Hence the `unused` variable in `b.h` needs to be within `#pragma clang + // diagnostic` block from `a.h`. + VFS->addFile("a.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp( + #include "b.h" + #pragma clang diagnostic push + #pragma clang diagnostic warning "-Wunused" + void foo(); + #pragma clang diagnostic pop + )cpp")); + VFS->addFile("b.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp( + void foo(); void foo(); void foo(); void foo(); + inline void foo() { int unused = 2; } + )cpp")); + + DiagnosticOptions DiagOpts; + IntrusiveRefCntPtr Diags = + CompilerInstance::createDiagnostics(*VFS, DiagOpts); + + CreateInvocationOptions CIOpts; + CIOpts.Diags = Diags; + + const char *Args[] = {"clang", "-xc++", "a.cc"}; + std::shared_ptr CInvok = + createInvocation(Args, std::move(CIOpts)); + ASSERT_TRUE(CInvok) << "could not create compiler invocation"; + + CompilerInstance Instance(std::move(CInvok)); + Instance.setDiagnostics(Diags.get()); + Instance.createFileManager(VFS); + + // Run once for `a.cc` and then for `a.h`. This makes sure we get the same + // file ID for `b.h` in the second run as `a.h` from first run. + const auto &OrigInputKind = Instance.getFrontendOpts().Inputs[0].getKind(); + Instance.getFrontendOpts().Inputs.emplace_back("a.h", OrigInputKind); + + SyntaxOnlyAction Act; + EXPECT_TRUE(Instance.ExecuteAction(Act)) << "Failed to execute action"; + EXPECT_FALSE(Diags->hasErrorOccurred()); + EXPECT_EQ(Diags->getNumWarnings(), 0u); +} } // anonymous namespace diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 377c066f031d..61f74929c1e9 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -789,6 +789,97 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Out.data()); } +TEST(MinimizeSourceToDependencyDirectivesTest, + WhitespaceAfterLineContinuationSlashLineComment) { + SmallVector Out; + + ASSERT_FALSE(minimizeSourceToDependencyDirectives("// some comment \\ \n" + "module A;\n", + Out)); + EXPECT_STREQ("", Out.data()); +} + +TEST(MinimizeSourceToDependencyDirectivesTest, + WhitespaceAfterLineContinuationSlashAllDirectives) { + SmallVector Out; + SmallVector Tokens; + SmallVector Directives; + + StringRef Input = "#define \\ \n" + "A\n" + "#undef\t\\ \n" + "A\n" + "#endif \\\t\t\n" + "\n" + "#if \\ \t\n" + "A\n" + "#ifdef\t\\ \n" + "A\n" + "#ifndef \\ \t\n" + "A\n" + "#elifdef \\ \n" + "A\n" + "#elifndef \\ \n" + "A\n" + "#elif \\\t\t \n" + "A\n" + "#else \\\t \t\n" + "\n" + "#include \\ \n" + "\n" + "#include_next \\ \n" + "\n" + "#__include_macros\\ \n" + "\n" + "#import \\ \t\n" + "\n" + "@import \\\t \n" + "A;\n" + "#pragma clang \\ \n" + "module \\ \n" + "import A\n" + "#pragma \\ \n" + "push_macro(A)\n" + "#pragma \\\t \n" + "pop_macro(A)\n" + "#pragma \\ \n" + "include_alias(,\\ \n" + ")\n" + "export \\ \n" + "module m;\n" + "import\t\\\t \n" + "m;\n" + "#pragma\t\\ \n" + "clang\t\\ \t\n" + "system_header\n"; + ASSERT_FALSE( + minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives)); + + EXPECT_EQ(pp_define, Directives[0].Kind); + EXPECT_EQ(pp_undef, Directives[1].Kind); + EXPECT_EQ(pp_endif, Directives[2].Kind); + EXPECT_EQ(pp_if, Directives[3].Kind); + EXPECT_EQ(pp_ifdef, Directives[4].Kind); + EXPECT_EQ(pp_ifndef, Directives[5].Kind); + EXPECT_EQ(pp_elifdef, Directives[6].Kind); + EXPECT_EQ(pp_elifndef, Directives[7].Kind); + EXPECT_EQ(pp_elif, Directives[8].Kind); + EXPECT_EQ(pp_else, Directives[9].Kind); + EXPECT_EQ(pp_include, Directives[10].Kind); + EXPECT_EQ(pp_include_next, Directives[11].Kind); + EXPECT_EQ(pp___include_macros, Directives[12].Kind); + EXPECT_EQ(pp_import, Directives[13].Kind); + EXPECT_EQ(decl_at_import, Directives[14].Kind); + EXPECT_EQ(pp_pragma_import, Directives[15].Kind); + EXPECT_EQ(pp_pragma_push_macro, Directives[16].Kind); + EXPECT_EQ(pp_pragma_pop_macro, Directives[17].Kind); + EXPECT_EQ(pp_pragma_include_alias, Directives[18].Kind); + EXPECT_EQ(cxx_export_module_decl, Directives[19].Kind); + EXPECT_EQ(cxx_import_decl, Directives[20].Kind); + EXPECT_EQ(pp_pragma_system_header, Directives[21].Kind); + EXPECT_EQ(pp_eof, Directives[22].Kind); +} + TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) { SmallVector Out; diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index 381755d4d1b6..33c8abbec35a 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -49,7 +49,8 @@ protected: } std::unique_ptr CreatePP(StringRef Source, - TrivialModuleLoader &ModLoader) { + TrivialModuleLoader &ModLoader, + StringRef PreDefines = {}) { std::unique_ptr Buf = llvm::MemoryBuffer::getMemBuffer(Source); SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); @@ -61,6 +62,8 @@ protected: PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/nullptr, /*OwnsHeaderSearch =*/false); + if (!PreDefines.empty()) + PP->setPredefines(PreDefines.str()); PP->Initialize(*Target); PP->EnterMainSourceFile(); return PP; @@ -769,4 +772,46 @@ TEST(LexerPreambleTest, PreambleBounds) { } } +TEST_F(LexerTest, CheckFirstPPToken) { + { + TrivialModuleLoader ModLoader; + auto PP = CreatePP("// This is a comment\n" + "int a;", + ModLoader); + Token Tok; + PP->Lex(Tok); + EXPECT_TRUE(Tok.is(tok::kw_int)); + EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::kw_int)); + } + { + TrivialModuleLoader ModLoader; + auto PP = CreatePP("// This is a comment\n" + "#define FOO int\n" + "FOO a;", + ModLoader); + Token Tok; + PP->Lex(Tok); + EXPECT_TRUE(Tok.is(tok::kw_int)); + EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::hash)); + } + + { + TrivialModuleLoader ModLoader; + auto PP = CreatePP("// This is a comment\n" + "FOO a;", + ModLoader, "#define FOO int\n"); + Token Tok; + PP->Lex(Tok); + EXPECT_TRUE(Tok.is(tok::kw_int)); + EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken()); + EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::identifier)); + EXPECT_TRUE( + PP->getMainFileFirstPPToken().getIdentifierInfo()->isStr("FOO")); + } +} } // anonymous namespace diff --git a/clang/unittests/Parse/CMakeLists.txt b/clang/unittests/Parse/CMakeLists.txt index 6859efed294c..2ed43a83b878 100644 --- a/clang/unittests/Parse/CMakeLists.txt +++ b/clang/unittests/Parse/CMakeLists.txt @@ -11,5 +11,6 @@ add_clang_unittest(ParseTests LLVMTestingSupport clangTesting LLVM_COMPONENTS + FrontendHLSL Support ) diff --git a/clang/unittests/Sema/ExternalSemaSourceTest.cpp b/clang/unittests/Sema/ExternalSemaSourceTest.cpp index 2b271d4bf782..cc9dd4175af5 100644 --- a/clang/unittests/Sema/ExternalSemaSourceTest.cpp +++ b/clang/unittests/Sema/ExternalSemaSourceTest.cpp @@ -268,20 +268,6 @@ TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) { ASSERT_EQ(1, Watcher.SeenCount); } -TEST(ExternalSemaSource, ExternalDelayedTypoCorrection) { - auto Installer = std::make_unique(); - auto Provider = makeIntrusiveRefCnt("aaa", "bbb"); - DiagnosticWatcher Watcher("aaa", "bbb"); - Installer->PushSource(Provider.get()); - Installer->PushWatcher(&Watcher); - std::vector Args(1, "-std=c++11"); - ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( - std::move(Installer), "namespace AAA { } void foo() { AAA::aaa(); }", - Args)); - ASSERT_LE(0, Provider->CallCount); - ASSERT_EQ(1, Watcher.SeenCount); -} - // We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise // solve the problem. TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) { diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp index 683d9070b1dc..d194b2877ad8 100644 --- a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp @@ -384,3 +384,55 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { EXPECT_TRUE(DiagConsumer.Finished); } } + +TEST(DependencyScanner, NoNegativeCache) { + StringRef CWD = "/root"; + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string HeaderPath = + std::string(llvm::formatv("{0}root{0}header.h", Sept)); + std::string Test0Path = + std::string(llvm::formatv("{0}root{0}test0.cpp", Sept)); + std::string Test1Path = + std::string(llvm::formatv("{0}root{0}test1.cpp", Sept)); + + VFS->addFile(Test0Path, 0, + llvm::MemoryBuffer::getMemBuffer( + "#if __has_include(\"header.h\")\n#endif")); + VFS->addFile(Test1Path, 0, + llvm::MemoryBuffer::getMemBuffer("#include \"header.h\"")); + + DependencyScanningService Service( + ScanningMode::DependencyDirectivesScan, ScanningOutputFormat::Make, + ScanningOptimizations::All, false, false, + llvm::sys::toTimeT(std::chrono::system_clock::now()), false); + DependencyScanningTool ScanTool(Service, VFS); + + std::vector CommandLine0 = {"clang", + "-target", + "x86_64-apple-macosx10.7", + "-c", + "test0.cpp", + "-o" + "test0.cpp.o"}; + std::vector CommandLine1 = {"clang", + "-target", + "x86_64-apple-macosx10.7", + "-c", + "test1.cpp", + "-o" + "test1.cpp.o"}; + + std::string Result; + ASSERT_THAT_ERROR( + ScanTool.getDependencyFile(CommandLine0, CWD).moveInto(Result), + llvm::Succeeded()); + + VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("")); + + ASSERT_THAT_ERROR( + ScanTool.getDependencyFile(CommandLine1, CWD).moveInto(Result), + llvm::Succeeded()); +} diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp index 7420743c97a2..a68ea72d3816 100644 --- a/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/VirtualFileSystem.h" #include "gtest/gtest.h" @@ -19,9 +20,10 @@ TEST(DependencyScanningWorkerFilesystem, CacheStatusFailures) { auto InstrumentingFS = llvm::makeIntrusiveRefCnt(InMemoryFS); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); - DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InstrumentingFS); + DependencyScanningWorkerFilesystem DepFS2(Service, InstrumentingFS); DepFS.status("/foo.c"); EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); @@ -45,9 +47,10 @@ TEST(DependencyScanningFilesystem, CacheGetRealPath) { auto InstrumentingFS = llvm::makeIntrusiveRefCnt(InMemoryFS); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); - DependencyScanningWorkerFilesystem DepFS2(SharedCache, InstrumentingFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InstrumentingFS); + DependencyScanningWorkerFilesystem DepFS2(Service, InstrumentingFS); { llvm::SmallString<128> Result; @@ -80,8 +83,9 @@ TEST(DependencyScanningFilesystem, RealPathAndStatusInvariants) { InMemoryFS->addFile("/foo.c", 0, llvm::MemoryBuffer::getMemBuffer("")); InMemoryFS->addFile("/bar.c", 0, llvm::MemoryBuffer::getMemBuffer("")); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InMemoryFS); // Success. { @@ -133,8 +137,9 @@ TEST(DependencyScanningFilesystem, CacheStatOnExists) { InMemoryFS->setCurrentWorkingDirectory("/"); InMemoryFS->addFile("/foo", 0, llvm::MemoryBuffer::getMemBuffer("")); InMemoryFS->addFile("/bar", 0, llvm::MemoryBuffer::getMemBuffer("")); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InstrumentingFS); DepFS.status("/foo"); DepFS.status("/foo"); @@ -156,8 +161,9 @@ TEST(DependencyScanningFilesystem, CacheStatFailures) { auto InstrumentingFS = llvm::makeIntrusiveRefCnt(InMemoryFS); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InstrumentingFS); DepFS.status("/dir"); DepFS.status("/dir"); @@ -183,8 +189,9 @@ TEST(DependencyScanningFilesystem, DiagnoseStaleStatFailures) { auto InMemoryFS = llvm::makeIntrusiveRefCnt(); InMemoryFS->setCurrentWorkingDirectory("/"); - DependencyScanningFilesystemSharedCache SharedCache; - DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryFS); + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningWorkerFilesystem DepFS(Service, InMemoryFS); bool Path1Exists = DepFS.exists("/path1.suffix"); EXPECT_EQ(Path1Exists, false); @@ -197,7 +204,7 @@ TEST(DependencyScanningFilesystem, DiagnoseStaleStatFailures) { EXPECT_EQ(Path1Exists, false); std::vector InvalidPaths = - SharedCache.getInvalidNegativeStatCachedPaths(*InMemoryFS); + Service.getSharedCache().getInvalidNegativeStatCachedPaths(*InMemoryFS); EXPECT_EQ(InvalidPaths.size(), 1u); ASSERT_STREQ("/path1.suffix", InvalidPaths[0].str().c_str()); diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index ef83e76c426d..73490927f8ee 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3739,7 +3739,8 @@ static void GenerateHasAttrSpellingStringSwitch( : '(' + itostr(Version) + ')'; if (Scope.empty() || Scope == Spelling.nameSpace()) { - if (TestStringMap.contains(Spelling.name())) + if (TestStringMap.contains(Spelling.name()) && + TestStringMap[Spelling.name()] != TestStr) TestStringMap[Spelling.name()] += " || " + TestStr; else TestStringMap[Spelling.name()] = TestStr; @@ -5410,7 +5411,7 @@ void EmitClangAttrDocs(const RecordKeeper &Records, raw_ostream &OS) { // Handle Undocumented category separately - no content merging if (Cat == "Undocumented" && UndocumentedCategory) { UndocumentedDocs.push_back( - DocumentationData(Doc, Attr, HeadingAndSpellings)); + DocumentationData(Doc, Attr, std::move(HeadingAndSpellings))); continue; } @@ -5486,14 +5487,12 @@ void EmitTestPragmaAttributeSupportedAttributes(const RecordKeeper &Records, } const Record *SubjectObj = I.second->getValueAsDef("Subjects"); OS << " ("; - bool PrintComma = false; + ListSeparator LS; for (const auto &Subject : enumerate(SubjectObj->getValueAsListOfDefs("Subjects"))) { if (!isSupportedPragmaClangAttributeSubject(*Subject.value())) continue; - if (PrintComma) - OS << ", "; - PrintComma = true; + OS << LS; PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = Support.SubjectsToRules.find(Subject.value())->getSecond(); if (RuleSet.isRule()) { diff --git a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index f15e30cd3f8f..161dd425fbc7 100644 --- a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -78,10 +78,10 @@ void clang::EmitClangCommentCommandInfo(const RecordKeeper &Records, static std::string MangleName(StringRef Str) { std::string Mangled; - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - switch (Str[i]) { + for (char C : Str) { + switch (C) { default: - Mangled += Str[i]; + Mangled += C; break; case '(': Mangled += "lparen"; @@ -122,9 +122,8 @@ void clang::EmitClangCommentCommandList(const RecordKeeper &Records, << "#endif\n"; ArrayRef Tags = Records.getAllDerivedDefinitions("Command"); - for (size_t i = 0, e = Tags.size(); i != e; ++i) { - const Record &Tag = *Tags[i]; - std::string MangledName = MangleName(Tag.getValueAsString("Name")); + for (const Record *Tag : Tags) { + std::string MangledName = MangleName(Tag->getValueAsString("Name")); OS << "COMMENT_COMMAND(" << MangledName << ")\n"; } diff --git a/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp index b8d8ac853a5c..e5eec5e7ca8d 100644 --- a/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp @@ -37,9 +37,9 @@ static bool translateCodePointToUTF8(unsigned CodePoint, raw_svector_ostream OS(CLiteral); OS << "\""; - for (size_t i = 0, e = UTF8.size(); i != e; ++i) { + for (char C : UTF8) { OS << "\\x"; - OS.write_hex(static_cast(UTF8[i])); + OS.write_hex(static_cast(C)); } OS << "\""; diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index e347b89a85d4..b28cb2c09ac5 100644 --- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -1794,8 +1794,8 @@ static std::string getDiagCategoryEnum(StringRef name) { if (name.empty()) return "DiagCat_None"; SmallString<256> enumName = StringRef("DiagCat_"); - for (StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) - enumName += isalnum(*I) ? *I : '_'; + for (char C : name) + enumName += isalnum(C) ? C : '_'; return std::string(enumName); } @@ -2225,13 +2225,10 @@ void clang::EmitClangDiagDocs(const RecordKeeper &Records, raw_ostream &OS) { else OS << "Also controls "; - bool First = true; sort(GroupInfo.SubGroups); - for (StringRef Name : GroupInfo.SubGroups) { - if (!First) OS << ", "; - OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; - First = false; - } + ListSeparator LS; + for (StringRef Name : GroupInfo.SubGroups) + OS << LS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; OS << ".\n\n"; } diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp index 5d6d90994cf3..9d0773e1aff8 100644 --- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp +++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp @@ -224,8 +224,7 @@ void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, auto Args = R->getValueAsListOfDefs("Args"); Enumerate(R, N, [&OS, &Args](ArrayRef TS, const Twine &ID) { OS << "bool emit" << ID << "("; - for (size_t I = 0, N = Args.size(); I < N; ++I) { - const auto *Arg = Args[I]; + for (const Record *Arg : Args) { bool AsRef = Arg->getValueAsBit("AsRef"); auto Name = Arg->getValueAsString("Name"); diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index dff57689e84b..a70e65e35d5e 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -292,6 +292,48 @@ C++23, informally referred to as C++26.

P1967R14 No + + + Reflection + P2996R13 + No + + + P3394R4 + No + + + P3293R3 + No + + + P3491R3 + No + + + P3096R12 + No + + + Attaching main to the global module + P3618R0 (DR) + No + + + Expansion Statements + P1306R5 + No + + + constexpr virtual inheritance + P3533R2 + No + + + Preprocessing is never undefined + P2843R3 + No + diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 075c4647abf6..5e832315f366 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -884,7 +884,11 @@ else () if(COMPILER_RT_DISABLE_AARCH64_FMV) list(APPEND BUILTIN_DEFS DISABLE_AARCH64_FMV) elseif(COMPILER_RT_BAREMETAL_BUILD) - list(APPEND BUILTIN_DEFS ENABLE_BAREMETAL_AARCH64_FMV) + foreach (arch ${BUILTIN_SUPPORTED_ARCH}) + if("${arch}" MATCHES "arm64|aarch64") + list(APPEND BUILTIN_DEFS ENABLE_BAREMETAL_AARCH64_FMV) + endif() + endforeach () endif() append_list_if(COMPILER_RT_HAS_ASM_LSE HAS_ASM_LSE BUILTIN_DEFS) diff --git a/compiler-rt/lib/builtins/README.txt b/compiler-rt/lib/builtins/README.txt index 19f26c92a0f9..2d213d95f333 100644 --- a/compiler-rt/lib/builtins/README.txt +++ b/compiler-rt/lib/builtins/README.txt @@ -272,11 +272,6 @@ switch32 switch8 switchu8 -// This function generates a custom trampoline function with the specific -// realFunc and localsPtr values. -void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, - const void* realFunc, void* localsPtr); - // There is no C interface to the *_vfp_d8_d15_regs functions. There are // called in the prolog and epilog of Thumb1 functions. When the C++ ABI use // SJLJ for exceptions, each function with a catch clause or destructors needs diff --git a/compiler-rt/lib/builtins/cpu_model/riscv.c b/compiler-rt/lib/builtins/cpu_model/riscv.c index 16d55fcfffe7..c02f6e9961ca 100644 --- a/compiler-rt/lib/builtins/cpu_model/riscv.c +++ b/compiler-rt/lib/builtins/cpu_model/riscv.c @@ -40,6 +40,8 @@ struct { #define I_BITMASK (1ULL << 8) #define M_GROUPID 0 #define M_BITMASK (1ULL << 12) +#define Q_GROUPID 0 +#define Q_BITMASK (1ULL << 16) #define V_GROUPID 0 #define V_BITMASK (1ULL << 21) #define ZACAS_GROUPID 0 diff --git a/compiler-rt/lib/builtins/trampoline_setup.c b/compiler-rt/lib/builtins/trampoline_setup.c index 830e25e4c030..844eb2794414 100644 --- a/compiler-rt/lib/builtins/trampoline_setup.c +++ b/compiler-rt/lib/builtins/trampoline_setup.c @@ -41,45 +41,3 @@ COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack, __clear_cache(trampOnStack, &trampOnStack[10]); } #endif // __powerpc__ && !defined(__powerpc64__) - -// The AArch64 compiler generates calls to __trampoline_setup() when creating -// trampoline functions on the stack for use with nested functions. -// This function creates a custom 36-byte trampoline function on the stack -// which loads x18 with a pointer to the outer function's locals -// and then jumps to the target nested function. -// Note: x18 is a reserved platform register on Windows and macOS. - -#if defined(__aarch64__) && defined(__ELF__) -COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack, - int trampSizeAllocated, - const void *realFunc, void *localsPtr) { - // This should never happen, but if compiler did not allocate - // enough space on stack for the trampoline, abort. - if (trampSizeAllocated < 36) - compilerrt_abort(); - - // create trampoline - // Load realFunc into x17. mov/movk 16 bits at a time. - trampOnStack[0] = - 0xd2800000u | ((((uint64_t)realFunc >> 0) & 0xffffu) << 5) | 0x11; - trampOnStack[1] = - 0xf2a00000u | ((((uint64_t)realFunc >> 16) & 0xffffu) << 5) | 0x11; - trampOnStack[2] = - 0xf2c00000u | ((((uint64_t)realFunc >> 32) & 0xffffu) << 5) | 0x11; - trampOnStack[3] = - 0xf2e00000u | ((((uint64_t)realFunc >> 48) & 0xffffu) << 5) | 0x11; - // Load localsPtr into x18 - trampOnStack[4] = - 0xd2800000u | ((((uint64_t)localsPtr >> 0) & 0xffffu) << 5) | 0x12; - trampOnStack[5] = - 0xf2a00000u | ((((uint64_t)localsPtr >> 16) & 0xffffu) << 5) | 0x12; - trampOnStack[6] = - 0xf2c00000u | ((((uint64_t)localsPtr >> 32) & 0xffffu) << 5) | 0x12; - trampOnStack[7] = - 0xf2e00000u | ((((uint64_t)localsPtr >> 48) & 0xffffu) << 5) | 0x12; - trampOnStack[8] = 0xd61f0220; // br x17 - - // Clear instruction cache. - __clear_cache(trampOnStack, &trampOnStack[9]); -} -#endif // defined(__aarch64__) && !defined(__APPLE__) && !defined(_WIN64) diff --git a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp index 93bf817a857b..c9210c78a063 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp @@ -265,8 +265,6 @@ int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, // we then request tags in [0,Size/2) and [Size/2, Size), and so on. // Function number => DFT. auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File))); - std::unordered_map> DFTMap; - std::unordered_set Cov; Command Cmd; Cmd.addArgument(DFTBinary); Cmd.addArgument(F.File); diff --git a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt index adfae3d63e64..c5885ccccd20 100644 --- a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt +++ b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt @@ -35,6 +35,27 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_RT_LIBCXXABI_PATH) list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++ -fno-exceptions) list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -nostdlib++ -fno-exceptions) + + # When we use -nostdlib++, we remove the default C++ runtime which normally + # provides the stack unwinding symbols (like __aeabi_unwind_cpp_pr0). + # We must now manually find and link a suitable unwinder library. + set(FUZZER_UNWINDER_LIBS) + if(COMPILER_RT_USE_LLVM_UNWINDER) + # Prefer LLVM's own libunwind. + list(APPEND FUZZER_UNWINDER_LIBS ${COMPILER_RT_UNWINDER_LINK_LIBS}) + elseif(COMPILER_RT_HAS_GCC_S_LIB) + # As a fallback, use the shared libgcc_s library. + list(APPEND FUZZER_UNWINDER_LIBS -lgcc_s) + elseif(COMPILER_RT_HAS_GCC_LIB) + # As a final fallback, use the static libgcc library. + list(APPEND FUZZER_UNWINDER_LIBS -lgcc) + elseif(NOT COMPILER_RT_USE_BUILTINS_LIBRARY) + # If no unwinder is found and we aren't using the builtins library + message(FATAL_ERROR "Fuzzer tests require a suitable unwinder, but none was found.") + endif() + # Add the detected unwinder library to our link flags. + list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS ${FUZZER_UNWINDER_LIBS}) + endif() if ("-fvisibility=hidden" IN_LIST LIBFUZZER_CFLAGS) diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index 493bf5f9efc5..a436d9c07ac6 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -220,6 +220,10 @@ void lsan_free(void *p) { Deallocate(p); } +void lsan_free_sized(void *p, uptr) { Deallocate(p); } + +void lsan_free_aligned_sized(void *p, uptr, uptr) { Deallocate(p); } + void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { return SetErrnoOnNull(Reallocate(stack, p, size, 1)); } diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h index 5eed0cbdb309..2342f11fb5d0 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.h +++ b/compiler-rt/lib/lsan/lsan_allocator.h @@ -127,6 +127,8 @@ void *lsan_aligned_alloc(uptr alignment, uptr size, const StackTrace &stack); void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack); void *lsan_malloc(uptr size, const StackTrace &stack); void lsan_free(void *p); +void lsan_free_sized(void *p, uptr size); +void lsan_free_aligned_sized(void *p, uptr alignment, uptr size); void *lsan_realloc(void *p, uptr size, const StackTrace &stack); void *lsan_reallocarray(void *p, uptr nmemb, uptr size, const StackTrace &stack); diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index a8252cddacf2..f9f83f6c0cc4 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -84,6 +84,35 @@ INTERCEPTOR(void, free, void *p) { lsan_free(p); } +# if SANITIZER_INTERCEPT_FREE_SIZED +INTERCEPTOR(void, free_sized, void *p, uptr size) { + if (UNLIKELY(!p)) + return; + if (DlsymAlloc::PointerIsMine(p)) + return DlsymAlloc::Free(p); + ENSURE_LSAN_INITED; + lsan_free_sized(p, size); +} +# define LSAN_MAYBE_INTERCEPT_FREE_SIZED INTERCEPT_FUNCTION(free_sized) +# else +# define LSAN_MAYBE_INTERCEPT_FREE_SIZED +# endif + +# if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED +INTERCEPTOR(void, free_aligned_sized, void *p, uptr alignment, uptr size) { + if (UNLIKELY(!p)) + return; + if (DlsymAlloc::PointerIsMine(p)) + return DlsymAlloc::Free(p); + ENSURE_LSAN_INITED; + lsan_free_aligned_sized(p, alignment, size); +} +# define LSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED \ + INTERCEPT_FUNCTION(free_aligned_sized) +# else +# define LSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED +# endif + INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { if (DlsymAlloc::Use()) return DlsymAlloc::Callocate(nmemb, size); @@ -117,6 +146,9 @@ INTERCEPTOR(void*, valloc, uptr size) { GET_STACK_TRACE_MALLOC; return lsan_valloc(size, stack); } +#else +# define LSAN_MAYBE_INTERCEPT_FREE_SIZED +# define LSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED #endif // !SANITIZER_APPLE #if SANITIZER_INTERCEPT_MEMALIGN @@ -547,6 +579,8 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(malloc); INTERCEPT_FUNCTION(free); + LSAN_MAYBE_INTERCEPT_FREE_SIZED; + LSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED; LSAN_MAYBE_INTERCEPT_CFREE; INTERCEPT_FUNCTION(calloc); INTERCEPT_FUNCTION(realloc); diff --git a/compiler-rt/lib/lsan/lsan_malloc_mac.cpp b/compiler-rt/lib/lsan/lsan_malloc_mac.cpp index 525c30272ccc..8a16c053da23 100644 --- a/compiler-rt/lib/lsan/lsan_malloc_mac.cpp +++ b/compiler-rt/lib/lsan/lsan_malloc_mac.cpp @@ -44,16 +44,19 @@ using namespace __lsan; void *p = lsan_valloc(size, stack) #define COMMON_MALLOC_FREE(ptr) \ lsan_free(ptr) -#define COMMON_MALLOC_SIZE(ptr) \ - uptr size = lsan_mz_size(ptr) -#define COMMON_MALLOC_FILL_STATS(zone, stats) -#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \ - (void)zone_name; \ - Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr); -#define COMMON_MALLOC_NAMESPACE __lsan -#define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0 -#define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0 +# define COMMON_MALLOC_FREE_SIZED(ptr, size) lsan_free_sized(ptr, size) +# define COMMON_MALLOC_FREE_ALIGNED_SIZED(ptr, alignment, size) \ + lsan_free_aligned_sized(ptr, alignment, size) +# define COMMON_MALLOC_SIZE(ptr) uptr size = lsan_mz_size(ptr) +# define COMMON_MALLOC_FILL_STATS(zone, stats) +# define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \ + (void)zone_name; \ + Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", \ + ptr); +# define COMMON_MALLOC_NAMESPACE __lsan +# define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0 +# define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0 -#include "sanitizer_common/sanitizer_malloc_mac.inc" +# include "sanitizer_common/sanitizer_malloc_mac.inc" #endif // SANITIZER_APPLE diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 76255cdb742a..bc28434d1d49 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -34,6 +34,7 @@ #include "sanitizer_common/sanitizer_glibc_version.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -215,6 +216,35 @@ INTERCEPTOR(void, free, void *ptr) { MsanDeallocate(&stack, ptr); } +#if SANITIZER_INTERCEPT_FREE_SIZED +INTERCEPTOR(void, free_sized, void *ptr, uptr size) { + if (UNLIKELY(!ptr)) + return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; + MsanDeallocate(&stack, ptr); +} +# define MSAN_MAYBE_INTERCEPT_FREE_SIZED INTERCEPT_FUNCTION(free_sized) +#else +# define MSAN_MAYBE_INTERCEPT_FREE_SIZED +#endif + +#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED +INTERCEPTOR(void, free_aligned_sized, void *ptr, uptr alignment, uptr size) { + if (UNLIKELY(!ptr)) + return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; + MsanDeallocate(&stack, ptr); +} +# define MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED \ + INTERCEPT_FUNCTION(free_aligned_sized) +#else +# define MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED +#endif + #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void, cfree, void *ptr) { if (UNLIKELY(!ptr)) @@ -1127,7 +1157,7 @@ static void SignalAction(int signo, void *si, void *uc) { SignalHandlerScope signal_handler_scope; ScopedThreadLocalStateBackup stlsb; UnpoisonParam(3); - __msan_unpoison(si, sizeof(__sanitizer_sigaction)); + __msan_unpoison(si, sizeof(__sanitizer_siginfo)); __msan_unpoison(uc, ucontext_t_sz(uc)); typedef void (*sigaction_cb)(int, void *, void *); @@ -1775,6 +1805,8 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(realloc); INTERCEPT_FUNCTION(reallocarray); INTERCEPT_FUNCTION(free); + MSAN_MAYBE_INTERCEPT_FREE_SIZED; + MSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED; MSAN_MAYBE_INTERCEPT_CFREE; MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE; MSAN_MAYBE_INTERCEPT_MALLINFO; diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp index c2d07400593d..2ee35555c24d 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp @@ -449,12 +449,6 @@ TEST_F(RtsanFileTest, FcntlSetFdDiesWhenRealtime) { close(fd); } -TEST(TestRtsanInterceptors, CloseDiesWhenRealtime) { - auto Func = []() { close(0); }; - ExpectRealtimeDeath(Func, "close"); - ExpectNonRealtimeSurvival(Func); -} - TEST(TestRtsanInterceptors, ChdirDiesWhenRealtime) { auto Func = []() { chdir("."); }; ExpectRealtimeDeath(Func, "chdir"); @@ -606,8 +600,10 @@ protected: } void TearDown() override { - if (file != nullptr) + const bool is_open = fcntl(fd, F_GETFD) != -1; + if (is_open && file != nullptr) fclose(file); + RtsanFileTest::TearDown(); } @@ -620,6 +616,16 @@ private: int fd = -1; }; +TEST_F(RtsanOpenedFileTest, CloseDiesWhenRealtime) { + auto Func = [this]() { close(GetOpenFd()); }; + ExpectRealtimeDeath(Func, "close"); +} + +TEST_F(RtsanOpenedFileTest, CloseSurvivesWhenNotRealtime) { + auto Func = [this]() { close(GetOpenFd()); }; + ExpectNonRealtimeSurvival(Func); +} + #if SANITIZER_INTERCEPT_FSEEK TEST_F(RtsanOpenedFileTest, FgetposDieWhenRealtime) { auto Func = [this]() { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index d9e7ded593fe..3f52cfcaeeca 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -166,7 +166,7 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, // Used to check if we can map shadow memory to a fixed location. bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); -// Releases memory pages entirely within the [beg, end] address range. Noop if +// Releases memory pages entirely within the [beg, end) address range. Noop if // the provided range does not contain at least one entire page. void ReleaseMemoryPagesToOS(uptr beg, uptr end); void IncreaseTotalMmap(uptr size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9272e2ab6cbd..2d6cf7fc3282 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -481,7 +481,8 @@ INTERCEPTOR(char*, textdomain, const char *domainname) { #endif #if SANITIZER_INTERCEPT_STRCMP || SANITIZER_INTERCEPT_MEMCMP -static inline int CharCmpX(unsigned char c1, unsigned char c2) { +[[maybe_unused]] static inline int CharCmpX(unsigned char c1, + unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; } #endif @@ -1350,7 +1351,8 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) { #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS static void unpoison_tm(void *ctx, __sanitizer_tm *tm) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); -#if !SANITIZER_SOLARIS +// AIX tm struct does not have tm_zone field. +# if !SANITIZER_SOLARIS && !SANITIZER_AIX if (tm->tm_zone) { // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone // can point to shared memory and tsan would report a data race. @@ -1735,10 +1737,12 @@ INTERCEPTOR(int, __vsprintf_chk, char *str, int flag, SIZE_T size_to, VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap) #endif +# if SANITIZER_INTERCEPT_VASPRINTF INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap) +# endif -#if SANITIZER_INTERCEPT_ISOC99_PRINTF +# if SANITIZER_INTERCEPT_ISOC99_PRINTF INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap) VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap) @@ -1787,10 +1791,12 @@ INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag, FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) #endif +# if SANITIZER_INTERCEPT_ASPRINTF INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format) +# endif -#if SANITIZER_INTERCEPT_ISOC99_PRINTF +# if SANITIZER_INTERCEPT_ISOC99_PRINTF INTERCEPTOR(int, __isoc99_printf, const char *format, ...) FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format) @@ -1811,17 +1817,24 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size, #endif // SANITIZER_INTERCEPT_PRINTF #if SANITIZER_INTERCEPT_PRINTF -#define INIT_PRINTF \ - COMMON_INTERCEPT_FUNCTION_LDBL(printf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \ - COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf); +# define INIT_PRINTF_COMMON \ + COMMON_INTERCEPT_FUNCTION_LDBL(printf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf); +# if !SANITIZER_AIX +// AIX does not have [v]asprintf. +# define INIT_PRINTF_EXTRA \ + COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); +# else +# define INIT_PRINTF_EXTRA +# endif +# define INIT_PRINTF INIT_PRINTF_COMMON INIT_PRINTF_EXTRA #else #define INIT_PRINTF #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index bc8f02826c61..08c2be47f535 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -79,7 +79,9 @@ static void ioctl_table_fill() { _(TIOCMSET, READ, sizeof(int)); _(TIOCNXCL, NONE, 0); _(TIOCOUTQ, WRITE, sizeof(int)); +# if !SANITIZER_AIX _(TIOCSCTTY, NONE, 0); +# endif _(TIOCSPGRP, READ, pid_t_sz); _(TIOCSWINSZ, READ, struct_winsize_sz); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc index 1565a494140f..0b6731c89950 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @@ -33,11 +33,13 @@ // Platform-specific options. #if SANITIZER_APPLE -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 +# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 #elif SANITIZER_WINDOWS64 -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 +# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 +#elif SANITIZER_AIX +# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 #else -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1 +# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1 #endif // SANITIZER_APPLE #ifndef COMMON_INTERCEPTOR_MEMSET_IMPL diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index 6959f785990f..05b7d2e28a61 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -130,7 +130,7 @@ bool LibraryNameIs(const char *full_name, const char *base_name); // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); -// Releases memory pages entirely within the [beg, end] address range. +// Releases memory pages entirely within the [beg, end) address range. // The pages no longer count toward RSS; reads are guaranteed to return 0. // Requires (but does not verify!) that pages are MAP_PRIVATE. inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc b/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc index 6343eb284afb..be27584f2053 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -144,6 +144,22 @@ INTERCEPTOR(void, free, void *ptr) { COMMON_MALLOC_FREE(ptr); } +#if SANITIZER_INTERCEPT_FREE_SIZED && defined(COMMON_MALLOC_FREE_SIZED) +INTERCEPTOR(void, free_sized, void *ptr, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_FREE_SIZED(ptr, size); +} +#endif + +#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED && \ + defined(COMMON_MALLOC_FREE_ALIGNED_SIZED) +INTERCEPTOR(void, free_aligned_sized, void *ptr, size_t alignment, + size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_FREE_ALIGNED_SIZED(ptr, alignment, size); +} +#endif + INTERCEPTOR(void *, realloc, void *ptr, size_t size) { COMMON_MALLOC_ENTER(); COMMON_MALLOC_REALLOC(ptr, size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 9f5f41cd8551..4c8d9a9b86be 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -14,7 +14,8 @@ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ - !(defined(__sun__) && defined(__svr4__)) && !defined(__HAIKU__) + !(defined(__sun__) && defined(__svr4__)) && !defined(__HAIKU__) && \ + !defined(__wasi__) # error "This operating system is not supported" #endif @@ -61,6 +62,12 @@ # define SANITIZER_HAIKU 0 #endif +#if defined(__wasi__) +# define SANITIZER_WASI 1 +#else +# define SANITIZER_WASI 0 +#endif + // - SANITIZER_APPLE: all Apple code // - TARGET_OS_OSX: macOS // - SANITIZER_IOS: devices (iOS and iOS-like) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 4bc55d7801db..29987decdff4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -141,6 +141,12 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SI_SOLARIS 0 #endif +#if SANITIZER_AIX +# define SI_NOT_AIX 0 +#else +# define SI_NOT_AIX 1 +#endif + #if SANITIZER_SOLARIS32 #define SI_SOLARIS32 1 #else @@ -161,20 +167,20 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) -#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX) #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA -#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX +#define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX) #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA -#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC +#define SANITIZER_INTERCEPT_STRCHRNUL (SI_POSIX_NOT_MAC && SI_NOT_AIX) #define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX #define SANITIZER_INTERCEPT_MEMSET 1 -#define SANITIZER_INTERCEPT_MEMMOVE 1 -#define SANITIZER_INTERCEPT_MEMCPY 1 +#define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX +#define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_BCMP \ SANITIZER_INTERCEPT_MEMCMP && \ @@ -233,9 +239,11 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC #ifndef SANITIZER_INTERCEPT_PRINTF -#define SANITIZER_INTERCEPT_PRINTF SI_POSIX -#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) -#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC +# define SANITIZER_INTERCEPT_ASPRINTF SI_NOT_AIX +# define SANITIZER_INTERCEPT_VASPRINTF SI_NOT_AIX +# define SANITIZER_INTERCEPT_PRINTF SI_POSIX +# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) +# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC #endif #define SANITIZER_INTERCEPT_SETPROCTITLE (SI_FREEBSD || SI_NETBSD) @@ -243,8 +251,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT___PRINTF_CHK \ (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC) -#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA -#define SANITIZER_INTERCEPT_FREXPF SI_POSIX +// AIX libc does not export FREXP and FREXPF. +#define SANITIZER_INTERCEPT_FREXP (SI_NOT_FUCHSIA && SI_NOT_AIX) +#define SANITIZER_INTERCEPT_FREXPF (SI_POSIX && SI_NOT_AIX) #define SANITIZER_INTERCEPT_FREXPL SI_POSIX #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX @@ -294,7 +303,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_ACCEPT4 \ (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD -#define SANITIZER_INTERCEPT_MODF SI_POSIX +#define SANITIZER_INTERCEPT_MODF (SI_POSIX && SI_NOT_AIX) #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX @@ -329,8 +338,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX #define SANITIZER_INTERCEPT_WCSNRTOMBS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_WCRTOMB \ - (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCRTOMB \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS || \ + !SI_NOT_AIX) #define SANITIZER_INTERCEPT_WCTOMB \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS @@ -370,7 +380,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_STATFS64 SI_GLIBC && SANITIZER_HAS_STATFS64 +#define SANITIZER_INTERCEPT_STATFS64 \ + ((SI_GLIBC || !SI_NOT_AIX) && SANITIZER_HAS_STATFS64) #define SANITIZER_INTERCEPT_STATVFS \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS64 SI_GLIBC @@ -419,10 +430,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX #define SANITIZER_INTERCEPT_SINCOS SI_LINUX || SI_SOLARIS -#define SANITIZER_INTERCEPT_REMQUO SI_POSIX -#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD) -#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX -#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_REMQUO (SI_POSIX && SI_NOT_AIX) +#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX) +#define SANITIZER_INTERCEPT_LGAMMA (SI_POSIX && SI_NOT_AIX) +#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX) #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS) #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC @@ -505,11 +516,13 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE (SI_LINUX || SI_FREEBSD) #define SI_STAT_LINUX (SI_LINUX && __GLIBC_PREREQ(2, 33)) -#define SANITIZER_INTERCEPT_STAT \ - (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS || \ - SI_STAT_LINUX) -#define SANITIZER_INTERCEPT_STAT64 SI_STAT_LINUX && SANITIZER_HAS_STAT64 -#define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX) +#define SANITIZER_INTERCEPT_STAT \ + (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS || \ + SI_STAT_LINUX || !SI_NOT_AIX) +#define SANITIZER_INTERCEPT_STAT64 \ + ((SI_STAT_LINUX || !SI_NOT_AIX) && SANITIZER_HAS_STAT64) +#define SANITIZER_INTERCEPT_LSTAT \ + (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX || !SI_NOT_AIX) #define SANITIZER_INTERCEPT___XSTAT \ ((!SANITIZER_INTERCEPT_STAT && SI_POSIX) || SI_STAT_LINUX) #define SANITIZER_INTERCEPT___XSTAT64 SI_GLIBC @@ -578,7 +591,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC #define SANITIZER_INTERCEPT_NETENT (SI_LINUX || SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_SETVBUF \ - (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC) + (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC || !SI_NOT_AIX) #define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD @@ -650,6 +663,17 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_GETSERVBYNAME_R SI_GLIBC #define SANITIZER_INTERCEPT_GETSERVBYPORT_R SI_GLIBC +// Until free_sized and free_aligned_sized are more generally available, +// we can only unconditionally intercept on ELF-based platforms where it +// is okay to have undefined weak symbols. +#ifdef __ELF__ +# define SANITIZER_INTERCEPT_FREE_SIZED 1 +# define SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED 1 +#else +# define SANITIZER_INTERCEPT_FREE_SIZED 0 +# define SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED 0 +#endif + // This macro gives a way for downstream users to override the above // interceptor macros irrespective of the platform they are on. They have // to do two things: diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h index 41e0613d6fc1..bda0f0468769 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h @@ -15,7 +15,7 @@ # define SANITIZER_REDEFINE_BUILTINS_H // The asm hack only works with GCC and Clang. -# if !defined(_WIN32) +# if !defined(_WIN32) && !defined(_AIX) asm(R"( .set memcpy, __sanitizer_internal_memcpy diff --git a/compiler-rt/lib/scudo/standalone/chunk.h b/compiler-rt/lib/scudo/standalone/chunk.h index a1b8e723d4cb..9da2dc57e71a 100644 --- a/compiler-rt/lib/scudo/standalone/chunk.h +++ b/compiler-rt/lib/scudo/standalone/chunk.h @@ -125,7 +125,7 @@ inline void loadHeader(u32 Cookie, const void *Ptr, *NewUnpackedHeader = bit_cast(NewPackedHeader); if (UNLIKELY(NewUnpackedHeader->Checksum != computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader))) - reportHeaderCorruption(NewUnpackedHeader, const_cast(Ptr)); + reportHeaderCorruption(NewUnpackedHeader, Ptr); } inline bool isValid(u32 Cookie, const void *Ptr, diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index 43655642843c..87acdec2a3ba 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -775,7 +775,7 @@ public: // Getting the alloc size of a chunk only makes sense if it's allocated. if (UNLIKELY(Header.State != Chunk::State::Allocated)) - reportInvalidChunkState(AllocatorAction::Sizing, const_cast(Ptr)); + reportInvalidChunkState(AllocatorAction::Sizing, Ptr); return getSize(Ptr, &Header); } diff --git a/compiler-rt/lib/scudo/standalone/report.cpp b/compiler-rt/lib/scudo/standalone/report.cpp index 14a4066d3720..b97a74b078c2 100644 --- a/compiler-rt/lib/scudo/standalone/report.cpp +++ b/compiler-rt/lib/scudo/standalone/report.cpp @@ -66,17 +66,16 @@ void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) { // The checksum of a chunk header is invalid. This could be caused by an // {over,under}write of the header, a pointer that is not an actual chunk. -void NORETURN reportHeaderCorruption(void *Header, void *Ptr) { +void NORETURN reportHeaderCorruption(void *Header, const void *Ptr) { ScopedErrorReport Report; Report.append("corrupted chunk header at address %p", Ptr); if (*static_cast(Header) == 0U) { // Header all zero, which could indicate that this might be a pointer that // has been double freed but the memory has been released to the kernel. Report.append(": chunk header is zero and might indicate memory corruption " - "or a double free\n", - Ptr); + "or a double free\n"); } else { - Report.append(": most likely due to memory corruption\n", Ptr); + Report.append(": most likely due to memory corruption\n"); } } @@ -131,13 +130,13 @@ static const char *stringifyAction(AllocatorAction Action) { // The chunk is not in a state congruent with the operation we want to perform. // This is usually the case with a double-free, a realloc of a freed pointer. -void NORETURN reportInvalidChunkState(AllocatorAction Action, void *Ptr) { +void NORETURN reportInvalidChunkState(AllocatorAction Action, const void *Ptr) { ScopedErrorReport Report; Report.append("invalid chunk state when %s address %p\n", stringifyAction(Action), Ptr); } -void NORETURN reportMisalignedPointer(AllocatorAction Action, void *Ptr) { +void NORETURN reportMisalignedPointer(AllocatorAction Action, const void *Ptr) { ScopedErrorReport Report; Report.append("misaligned pointer when %s address %p\n", stringifyAction(Action), Ptr); @@ -145,7 +144,7 @@ void NORETURN reportMisalignedPointer(AllocatorAction Action, void *Ptr) { // The deallocation function used is at odds with the one used to allocate the // chunk (eg: new[]/delete or malloc/delete, and so on). -void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, void *Ptr, +void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, const void *Ptr, u8 TypeA, u8 TypeB) { ScopedErrorReport Report; Report.append("allocation type mismatch when %s address %p (%d vs %d)\n", @@ -154,7 +153,7 @@ void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, void *Ptr, // The size specified to the delete operator does not match the one that was // passed to new when allocating the chunk. -void NORETURN reportDeleteSizeMismatch(void *Ptr, uptr Size, +void NORETURN reportDeleteSizeMismatch(const void *Ptr, uptr Size, uptr ExpectedSize) { ScopedErrorReport Report; Report.append( diff --git a/compiler-rt/lib/scudo/standalone/report.h b/compiler-rt/lib/scudo/standalone/report.h index c0214b51560e..c397dd3fc9c6 100644 --- a/compiler-rt/lib/scudo/standalone/report.h +++ b/compiler-rt/lib/scudo/standalone/report.h @@ -24,7 +24,7 @@ void NORETURN reportRawError(const char *Message); void NORETURN reportInvalidFlag(const char *FlagType, const char *Value); // Chunk header related errors. -void NORETURN reportHeaderCorruption(void *Header, void *Ptr); +void NORETURN reportHeaderCorruption(void *Header, const void *Ptr); // Sanity checks related error. void NORETURN reportSanityCheckError(const char *Field); @@ -41,11 +41,12 @@ enum class AllocatorAction : u8 { Reallocating, Sizing, }; -void NORETURN reportInvalidChunkState(AllocatorAction Action, void *Ptr); -void NORETURN reportMisalignedPointer(AllocatorAction Action, void *Ptr); -void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, void *Ptr, +void NORETURN reportInvalidChunkState(AllocatorAction Action, const void *Ptr); +void NORETURN reportMisalignedPointer(AllocatorAction Action, const void *Ptr); +void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, const void *Ptr, u8 TypeA, u8 TypeB); -void NORETURN reportDeleteSizeMismatch(void *Ptr, uptr Size, uptr ExpectedSize); +void NORETURN reportDeleteSizeMismatch(const void *Ptr, uptr Size, + uptr ExpectedSize); // C wrappers errors. void NORETURN reportAlignmentNotPowerOfTwo(uptr Alignment); diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h index 354f6da6a64a..ada594bc11fc 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform.h +++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -931,7 +931,7 @@ bool IsAppMem(uptr mem) { return SelectMapping(mem); } struct IsShadowMemImpl { template static bool Apply(uptr mem) { - return mem >= Mapping::kShadowBeg && mem <= Mapping::kShadowEnd; + return mem >= Mapping::kShadowBeg && mem < Mapping::kShadowEnd; } }; @@ -943,7 +943,7 @@ bool IsShadowMem(RawShadow *p) { struct IsMetaMemImpl { template static bool Apply(uptr mem) { - return mem >= Mapping::kMetaShadowBeg && mem <= Mapping::kMetaShadowEnd; + return mem >= Mapping::kMetaShadowBeg && mem < Mapping::kMetaShadowEnd; } }; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp index d8be21284b93..981f37b89e78 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -624,6 +624,7 @@ void MapShadow(uptr addr, uptr size) { static uptr mapped_meta_end = 0; uptr meta_begin = (uptr)MemToMeta(addr); uptr meta_end = (uptr)MemToMeta(addr + size); + // Windows wants 64K alignment. meta_begin = RoundDownTo(meta_begin, 64 << 10); meta_end = RoundUpTo(meta_end, 64 << 10); if (!data_mapped) { @@ -634,9 +635,6 @@ void MapShadow(uptr addr, uptr size) { Die(); } else { // Mapping continuous heap. - // Windows wants 64K alignment. - meta_begin = RoundDownTo(meta_begin, 64 << 10); - meta_end = RoundUpTo(meta_end, 64 << 10); CHECK_GT(meta_end, mapped_meta_end); if (meta_begin < mapped_meta_end) meta_begin = mapped_meta_end; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp index cf07686d968d..bd8deefefa1b 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_access.cpp @@ -523,9 +523,9 @@ SECOND: } void ShadowSet(RawShadow* p, RawShadow* end, RawShadow v) { - DCHECK_LE(p, end); + DCHECK_LT(p, end); DCHECK(IsShadowMem(p)); - DCHECK(IsShadowMem(end)); + DCHECK(IsShadowMem(end - 1)); UNUSED const uptr kAlign = kShadowCnt * kShadowSize; DCHECK_EQ(reinterpret_cast(p) % kAlign, 0); DCHECK_EQ(reinterpret_cast(end) % kAlign, 0); @@ -569,6 +569,7 @@ static void MemoryRangeSet(uptr addr, uptr size, RawShadow val) { RawShadow* mid1 = Min(end, reinterpret_cast(RoundUp( reinterpret_cast(begin) + kPageSize / 2, kPageSize))); + // begin must < mid1 ShadowSet(begin, mid1, val); // Reset middle part. RawShadow* mid2 = RoundDown(end, kPageSize); @@ -577,7 +578,10 @@ static void MemoryRangeSet(uptr addr, uptr size, RawShadow val) { Die(); } // Set the ending. - ShadowSet(mid2, end, val); + if (mid2 < end) + ShadowSet(mid2, end, val); + else + DCHECK_EQ(mid2, end); } void MemoryResetRange(ThreadState* thr, uptr pc, uptr addr, uptr size) { @@ -669,7 +673,7 @@ void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) { RawShadow* shadow_mem = MemToShadow(addr); DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_read=%d\n", thr->tid, (void*)pc, (void*)addr, (int)size, is_read); - + DCHECK_NE(size, 0); #if SANITIZER_DEBUG if (!IsAppMem(addr)) { Printf("Access to non app mem start: %p\n", (void*)addr); diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cpp b/compiler-rt/lib/tsan/rtl/tsan_sync.cpp index 09d41780d188..97335bc8ecf7 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_sync.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cpp @@ -247,11 +247,14 @@ void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) { CHECK_NE(src, dst); CHECK_NE(sz, 0); uptr diff = dst - src; - u32 *src_meta = MemToMeta(src); - u32 *dst_meta = MemToMeta(dst); - u32 *src_meta_end = MemToMeta(src + sz); - uptr inc = 1; - if (dst > src) { + u32 *src_meta, *dst_meta, *src_meta_end; + uptr inc; + if (dst < src) { + src_meta = MemToMeta(src); + dst_meta = MemToMeta(dst); + src_meta_end = MemToMeta(src + sz); + inc = 1; + } else { src_meta = MemToMeta(src + sz) - 1; dst_meta = MemToMeta(dst + sz) - 1; src_meta_end = MemToMeta(src) - 1; diff --git a/compiler-rt/test/builtins/Unit/trampoline_setup_test.c b/compiler-rt/test/builtins/Unit/trampoline_setup_test.c index d51d35acaa02..da115fe76427 100644 --- a/compiler-rt/test/builtins/Unit/trampoline_setup_test.c +++ b/compiler-rt/test/builtins/Unit/trampoline_setup_test.c @@ -7,7 +7,7 @@ /* * Tests nested functions - * The ppc and aarch64 compilers generates a call to __trampoline_setup + * The ppc compiler generates a call to __trampoline_setup * The i386 and x86_64 compilers generate a call to ___enable_execute_stack */ diff --git a/compiler-rt/test/fuzzer/uncaught-exception.test b/compiler-rt/test/fuzzer/uncaught-exception.test index b055c88f6d90..d1b98cfb7c74 100644 --- a/compiler-rt/test/fuzzer/uncaught-exception.test +++ b/compiler-rt/test/fuzzer/uncaught-exception.test @@ -4,7 +4,10 @@ REQUIRES: windows RUN: %cpp_compiler %S/UncaughtException.cpp -o %t-UncaughtException -RUN: not %run %t-UncaughtException 2>&1 | FileCheck %s +# Clang will fail the test with 'deadly signal', but other compilers may fail with different error messages. +# For example, msvc fails with 'uncaught C++ exception'. So the error we check depends on the compiler target. +RUN: not %run %t-UncaughtException 2>&1 | FileCheck %s --check-prefixes=CHECK-CRASH,%if target={{.*-windows-msvc.*}} %{CHECK-MSVC%} %else %{CHECK-ERROR%} -CHECK: ERROR: libFuzzer: deadly signal -CHECK: Test unit written to ./crash +CHECK-ERROR: ERROR: libFuzzer: deadly signal +CHECK-MSVC: ERROR: libFuzzer: uncaught C++ exception +CHECK-CRASH: Test unit written to ./crash diff --git a/compiler-rt/test/lit.common.configured.in b/compiler-rt/test/lit.common.configured.in index 8ca47a8df5ae..04d1a4df5a54 100644 --- a/compiler-rt/test/lit.common.configured.in +++ b/compiler-rt/test/lit.common.configured.in @@ -25,7 +25,6 @@ set_default("gold_executable", "@GOLD_EXECUTABLE@") set_default("clang", "@COMPILER_RT_RESOLVED_TEST_COMPILER@") set_default("compiler_id", "@COMPILER_RT_TEST_COMPILER_ID@") set_default("python_executable", "@Python3_EXECUTABLE@") -set_default("python_root_dir", "@Python3_ROOT_DIR@") set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@) set_default("compiler_rt_intercept_libdispatch", @COMPILER_RT_INTERCEPT_LIBDISPATCH_PYBOOL@) set_default("compiler_rt_output_dir", "@COMPILER_RT_RESOLVED_OUTPUT_DIR@") diff --git a/compiler-rt/test/msan/ifaddrs.cpp b/compiler-rt/test/msan/ifaddrs.cpp index 91730a01f2d8..e06775db3251 100644 --- a/compiler-rt/test/msan/ifaddrs.cpp +++ b/compiler-rt/test/msan/ifaddrs.cpp @@ -16,10 +16,10 @@ #include -#define CHECK_AND_PUSH(addr, size) \ - if (addr) { \ - assert(-1 == __msan_test_shadow(addr, sizeof(size))); \ - ranges.push_back(std::make_pair((void *)addr, (size_t)size)); \ +#define CHECK_AND_PUSH(addr, size) \ + if (addr) { \ + assert(-1 == __msan_test_shadow(addr, (size_t)(size))); \ + ranges.push_back(std::make_pair((void *)addr, (size_t)size)); \ } int main(int argc, char *argv[]) { @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) { assert(res == 0); assert(-1 == __msan_test_shadow(&ifas, sizeof(ifaddrs *))); - std::vector > ranges; + std::vector> ranges; ifaddrs *p = ifas; while (p) { CHECK_AND_PUSH(p, sizeof(ifaddrs)); diff --git a/compiler-rt/test/msan/qsort.cpp b/compiler-rt/test/msan/qsort.cpp index af287ed64357..93e6845e1ea7 100644 --- a/compiler-rt/test/msan/qsort.cpp +++ b/compiler-rt/test/msan/qsort.cpp @@ -52,7 +52,7 @@ int compar1(const void *a, const void *b) { // kind of random for (int i = 0; i < kSize2; ++i) p[i] = i * 2 + (i % 3 - 1) * 3; - qsort(p, kSize1, sizeof(long), compar2); + qsort(p, kSize2, sizeof(long), compar2); __msan_check_mem_is_initialized(p, sizeof(long) * kSize2); delete[] p; diff --git a/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp b/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp new file mode 100644 index 000000000000..a750befb47e5 --- /dev/null +++ b/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp @@ -0,0 +1,15 @@ +// RUN: rm -rf %t && split-file %s %t && cd %t +// RUN: %clangxx --coverage main.cpp -o t +// RUN: %run ./t +// RUN: llvm-cov gcov -t t-main. | FileCheck %s + +//--- main.cpp +#include + +int main(int argc, char *argv[]) { // CHECK: 2: [[#]]:int main + puts(""); // CHECK-NEXT: 2: [[#]]: +#line 3 + puts(""); // line 3 + return 0; // line 4 +} +// CHECK-NOT: {{^ +[0-9]+:}} diff --git a/compiler-rt/test/profile/Posix/gcov-file-change.cpp b/compiler-rt/test/profile/Posix/gcov-file-change.cpp index 9d3bc79591f2..0cef1c3512f8 100644 --- a/compiler-rt/test/profile/Posix/gcov-file-change.cpp +++ b/compiler-rt/test/profile/Posix/gcov-file-change.cpp @@ -16,8 +16,8 @@ inline auto *const inl_var_main = // CHECK: 1: [[#]]:inline auto void foo(int x) { // CHECK-NEXT: 1: [[#]]: if (x) { // CHECK-NEXT: 1: [[#]]: #include "a.inc" - } -} + } // CHECK: 1: [[#]]: +} // CHECK-NEXT: 1: [[#]]: // CHECK-NOT: {{^ +[0-9]+:}} int main(int argc, char *argv[]) { // CHECK: 1: [[#]]:int main @@ -32,10 +32,8 @@ int main(int argc, char *argv[]) { // CHECK: 1: [[#]]:int main //--- a.h /// Apple targets doesn't enable -mconstructor-aliases by default and the count may be 4. struct A { A() { } }; // CHECK: {{[24]}}: [[#]]:struct A -inline auto *const inl_var_a = - new A; -/// TODO a.inc:1 should have line execution. -// CHECK-NOT: {{^ +[0-9]+:}} +inline auto *const inl_var_a = // CHECK-NEXT: 1: [[#]]: + new A; // CHECK-NEXT: 1: [[#]]: //--- a.inc -puts(""); +puts(""); // CHECK: 1: [[#]]:puts diff --git a/compiler-rt/test/rtsan/fork_exec.cpp b/compiler-rt/test/rtsan/fork_exec.cpp index 3b2d2e5ca2f5..5890a0936a2f 100644 --- a/compiler-rt/test/rtsan/fork_exec.cpp +++ b/compiler-rt/test/rtsan/fork_exec.cpp @@ -45,7 +45,12 @@ int main() MAYBE_NONBLOCKING { } // CHECK-NOHALT: Intercepted call to {{.*}} `fork` {{.*}} -// CHECK-NOHALT: Intercepted call to {{.*}} `execve` {{.*}} + +// We should also get some other intercepted call. On some systems this +// is `execve`, on others, it's a lock to set up `execve`. In either +// case, just check that we get a second intercepted call, don't sweat +// the name. +// CHECK-NOHALT: Intercepted call to {{.*}} // usleep checks that rtsan is still enabled in the parent process // See note in our interceptors file for why we don't look for `wait` diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c new file mode 100644 index 000000000000..7710c6236819 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_aligned_sized.c @@ -0,0 +1,13 @@ +// RUN: %clang -std=c23 -O0 %s -o %t && %run %t +// UNSUPPORTED: asan, hwasan, rtsan, tsan, ubsan + +#include +#include + +extern void free_aligned_sized(void *p, size_t alignment, size_t size); + +int main() { + volatile void *p = aligned_alloc(128, 1024); + free_aligned_sized((void *)p, 128, 1024); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c new file mode 100644 index 000000000000..9eac562fecb0 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/free_sized.c @@ -0,0 +1,15 @@ +// RUN: %clang -std=c23 -O0 %s -o %t && %run %t +// UNSUPPORTED: asan, hwasan, rtsan, tsan, ubsan + +#include +#include + +extern void *aligned_alloc(size_t alignment, size_t size); + +extern void free_sized(void *p, size_t size); + +int main() { + volatile void *p = malloc(64); + free_sized((void *)p, 64); + return 0; +} diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h index 16258b3bbba9..e579f6012ce8 100644 --- a/flang-rt/include/flang-rt/runtime/environment.h +++ b/flang-rt/include/flang-rt/runtime/environment.h @@ -64,6 +64,9 @@ struct ExecutionEnvironment { bool defaultUTF8{false}; // DEFAULT_UTF8 bool checkPointerDeallocation{true}; // FORT_CHECK_POINTER_DEALLOCATION + enum InternalDebugging { WorkQueue = 1 }; + int internalDebugging{0}; // FLANG_RT_DEBUG + // CUDA related variables std::size_t cudaStackLimit{0}; // ACC_OFFLOAD_STACK_SIZE bool cudaDeviceIsManaged{false}; // NV_CUDAFOR_DEVICE_IS_MANAGED diff --git a/flang-rt/include/flang-rt/runtime/stat.h b/flang-rt/include/flang-rt/runtime/stat.h index 070d0bf8673f..dc372de53506 100644 --- a/flang-rt/include/flang-rt/runtime/stat.h +++ b/flang-rt/include/flang-rt/runtime/stat.h @@ -24,7 +24,7 @@ class Terminator; enum Stat { StatOk = 0, // required to be zero by Fortran - // Interoperable STAT= codes + // Interoperable STAT= codes (>= 11) StatBaseNull = CFI_ERROR_BASE_ADDR_NULL, StatBaseNotNull = CFI_ERROR_BASE_ADDR_NOT_NULL, StatInvalidElemLen = CFI_INVALID_ELEM_LEN, @@ -36,7 +36,7 @@ enum Stat { StatMemAllocation = CFI_ERROR_MEM_ALLOCATION, StatOutOfBounds = CFI_ERROR_OUT_OF_BOUNDS, - // Standard STAT= values + // Standard STAT= values (>= 101) StatFailedImage = FORTRAN_RUNTIME_STAT_FAILED_IMAGE, StatLocked = FORTRAN_RUNTIME_STAT_LOCKED, StatLockedOtherImage = FORTRAN_RUNTIME_STAT_LOCKED_OTHER_IMAGE, @@ -49,10 +49,14 @@ enum Stat { // Additional "processor-defined" STAT= values StatInvalidArgumentNumber = FORTRAN_RUNTIME_STAT_INVALID_ARG_NUMBER, StatMissingArgument = FORTRAN_RUNTIME_STAT_MISSING_ARG, - StatValueTooShort = FORTRAN_RUNTIME_STAT_VALUE_TOO_SHORT, + StatValueTooShort = FORTRAN_RUNTIME_STAT_VALUE_TOO_SHORT, // -1 StatMoveAllocSameAllocatable = FORTRAN_RUNTIME_STAT_MOVE_ALLOC_SAME_ALLOCATABLE, StatBadPointerDeallocation = FORTRAN_RUNTIME_STAT_BAD_POINTER_DEALLOCATION, + + // Dummy status for work queue continuation, declared here to perhaps + // avoid collisions + StatContinue = 201 }; RT_API_ATTRS const char *StatErrorString(int); diff --git a/flang-rt/include/flang-rt/runtime/type-info.h b/flang-rt/include/flang-rt/runtime/type-info.h index 5e79efde164f..80301a313282 100644 --- a/flang-rt/include/flang-rt/runtime/type-info.h +++ b/flang-rt/include/flang-rt/runtime/type-info.h @@ -154,12 +154,17 @@ public: RT_API_ATTRS bool IsArgDescriptor(int zeroBasedArg) const { return (isArgDescriptorSet_ >> zeroBasedArg) & 1; } - RT_API_ATTRS bool isTypeBound() const { return isTypeBound_; } + RT_API_ATTRS bool IsTypeBound() const { return isTypeBound_ != 0; } RT_API_ATTRS bool IsArgContiguous(int zeroBasedArg) const { return (isArgContiguousSet_ >> zeroBasedArg) & 1; } - template RT_API_ATTRS PROC GetProc() const { - return reinterpret_cast(proc_); + template + RT_API_ATTRS PROC GetProc(const Binding *bindings = nullptr) const { + if (bindings && isTypeBound_ > 0) { + return reinterpret_cast(bindings[isTypeBound_ - 1].proc); + } else { + return reinterpret_cast(proc_); + } } FILE *Dump(FILE *) const; @@ -193,6 +198,8 @@ private: // When false, the defined I/O subroutine must have been // called via a generic interface, not a generic TBP. std::uint8_t isArgDescriptorSet_{0}; + // When a special binding is type-bound, this is its binding's index (plus 1, + // so that 0 signifies that it's not type-bound). std::uint8_t isTypeBound_{0}; // True when a FINAL subroutine has a dummy argument that is an array that // is CONTIGUOUS or neither assumed-rank nor assumed-shape. @@ -240,6 +247,7 @@ public: RT_API_ATTRS bool noFinalizationNeeded() const { return noFinalizationNeeded_; } + RT_API_ATTRS bool noDefinedAssignment() const { return noDefinedAssignment_; } RT_API_ATTRS std::size_t LenParameters() const { return lenParameterKind().Elements(); @@ -322,6 +330,7 @@ private: bool noInitializationNeeded_{false}; bool noDestructionNeeded_{false}; bool noFinalizationNeeded_{false}; + bool noDefinedAssignment_{false}; }; } // namespace Fortran::runtime::typeInfo diff --git a/flang-rt/include/flang-rt/runtime/work-queue.h b/flang-rt/include/flang-rt/runtime/work-queue.h new file mode 100644 index 000000000000..0daa7bc4d338 --- /dev/null +++ b/flang-rt/include/flang-rt/runtime/work-queue.h @@ -0,0 +1,555 @@ +//===-- include/flang-rt/runtime/work-queue.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 +// +//===----------------------------------------------------------------------===// + +// Internal runtime utilities for work queues that replace the use of recursion +// for better GPU device support. +// +// A work queue comprises a list of tickets. Each ticket class has a Begin() +// member function, which is called once, and a Continue() member function +// that can be called zero or more times. A ticket's execution terminates +// when either of these member functions returns a status other than +// StatContinue. When that status is not StatOk, then the whole queue +// is shut down. +// +// By returning StatContinue from its Continue() member function, +// a ticket suspends its execution so that any nested tickets that it +// may have created can be run to completion. It is the reponsibility +// of each ticket class to maintain resumption information in its state +// and manage its own progress. Most ticket classes inherit from +// class ComponentsOverElements, which implements an outer loop over all +// components of a derived type, and an inner loop over all elements +// of a descriptor, possibly with multiple phases of execution per element. +// +// Tickets are created by WorkQueue::Begin...() member functions. +// There is one of these for each "top level" recursive function in the +// Fortran runtime support library that has been restructured into this +// ticket framework. +// +// When the work queue is running tickets, it always selects the last ticket +// on the list for execution -- "work stack" might have been a more accurate +// name for this framework. This ticket may, while doing its job, create +// new tickets, and since those are pushed after the active one, the first +// such nested ticket will be the next one executed to completion -- i.e., +// the order of nested WorkQueue::Begin...() calls is respected. +// Note that a ticket's Continue() member function won't be called again +// until all nested tickets have run to completion and it is once again +// the last ticket on the queue. +// +// Example for an assignment to a derived type: +// 1. Assign() is called, and its work queue is created. It calls +// WorkQueue::BeginAssign() and then WorkQueue::Run(). +// 2. Run calls AssignTicket::Begin(), which pushes a tickets via +// BeginFinalize() and returns StatContinue. +// 3. FinalizeTicket::Begin() and FinalizeTicket::Continue() are called +// until one of them returns StatOk, which ends the finalization ticket. +// 4. AssignTicket::Continue() is then called; it creates a DerivedAssignTicket +// and then returns StatOk, which ends the ticket. +// 5. At this point, only one ticket remains. DerivedAssignTicket::Begin() +// and ::Continue() are called until they are done (not StatContinue). +// Along the way, it may create nested AssignTickets for components, +// and suspend itself so that they may each run to completion. + +#ifndef FLANG_RT_RUNTIME_WORK_QUEUE_H_ +#define FLANG_RT_RUNTIME_WORK_QUEUE_H_ + +#include "flang-rt/runtime/connection.h" +#include "flang-rt/runtime/descriptor.h" +#include "flang-rt/runtime/stat.h" +#include "flang-rt/runtime/type-info.h" +#include "flang/Common/api-attrs.h" +#include "flang/Runtime/freestanding-tools.h" +#include + +namespace Fortran::runtime::io { +class IoStatementState; +struct NonTbpDefinedIoTable; +} // namespace Fortran::runtime::io + +namespace Fortran::runtime { +class Terminator; +class WorkQueue; + +// Ticket worker base classes + +template class ImmediateTicketRunner { +public: + RT_API_ATTRS explicit ImmediateTicketRunner(TICKET &ticket) + : ticket_{ticket} {} + RT_API_ATTRS int Run(WorkQueue &workQueue) { + int status{ticket_.Begin(workQueue)}; + while (status == StatContinue) { + status = ticket_.Continue(workQueue); + } + return status; + } + +private: + TICKET &ticket_; +}; + +// Base class for ticket workers that operate elementwise over descriptors +class Elementwise { +public: + RT_API_ATTRS Elementwise( + const Descriptor &instance, const Descriptor *from = nullptr) + : instance_{instance}, from_{from} { + instance_.GetLowerBounds(subscripts_); + if (from_) { + from_->GetLowerBounds(fromSubscripts_); + } + } + RT_API_ATTRS bool IsComplete() const { return elementAt_ >= elements_; } + RT_API_ATTRS void Advance() { + ++elementAt_; + instance_.IncrementSubscripts(subscripts_); + if (from_) { + from_->IncrementSubscripts(fromSubscripts_); + } + } + RT_API_ATTRS void SkipToEnd() { elementAt_ = elements_; } + RT_API_ATTRS void Reset() { + elementAt_ = 0; + instance_.GetLowerBounds(subscripts_); + if (from_) { + from_->GetLowerBounds(fromSubscripts_); + } + } + +protected: + const Descriptor &instance_, *from_{nullptr}; + std::size_t elements_{instance_.Elements()}; + std::size_t elementAt_{0}; + SubscriptValue subscripts_[common::maxRank]; + SubscriptValue fromSubscripts_[common::maxRank]; +}; + +// Base class for ticket workers that operate over derived type components. +class Componentwise { +public: + RT_API_ATTRS Componentwise(const typeInfo::DerivedType &); + RT_API_ATTRS bool IsComplete() const { return componentAt_ >= components_; } + RT_API_ATTRS void Advance() { + ++componentAt_; + GetComponent(); + } + RT_API_ATTRS void SkipToEnd() { + component_ = nullptr; + componentAt_ = components_; + } + RT_API_ATTRS void Reset() { + component_ = nullptr; + componentAt_ = 0; + GetComponent(); + } + RT_API_ATTRS void GetComponent(); + +protected: + const typeInfo::DerivedType &derived_; + std::size_t components_{0}, componentAt_{0}; + const typeInfo::Component *component_{nullptr}; + StaticDescriptor componentDescriptor_; +}; + +// Base class for ticket workers that operate over derived type components +// in an outer loop, and elements in an inner loop. +class ComponentsOverElements : public Componentwise, public Elementwise { +public: + RT_API_ATTRS ComponentsOverElements(const Descriptor &instance, + const typeInfo::DerivedType &derived, const Descriptor *from = nullptr) + : Componentwise{derived}, Elementwise{instance, from} { + if (Elementwise::IsComplete()) { + Componentwise::SkipToEnd(); + } + } + RT_API_ATTRS bool IsComplete() const { return Componentwise::IsComplete(); } + RT_API_ATTRS void Advance() { + SkipToNextElement(); + if (Elementwise::IsComplete()) { + Elementwise::Reset(); + Componentwise::Advance(); + } + } + RT_API_ATTRS void SkipToNextElement() { + phase_ = 0; + Elementwise::Advance(); + } + RT_API_ATTRS void SkipToNextComponent() { + phase_ = 0; + Elementwise::Reset(); + Componentwise::Advance(); + } + RT_API_ATTRS void Reset() { + phase_ = 0; + Elementwise::Reset(); + Componentwise::Reset(); + } + +protected: + int phase_{0}; +}; + +// Base class for ticket workers that operate over elements in an outer loop, +// type components in an inner loop. +class ElementsOverComponents : public Elementwise, public Componentwise { +public: + RT_API_ATTRS ElementsOverComponents(const Descriptor &instance, + const typeInfo::DerivedType &derived, const Descriptor *from = nullptr) + : Elementwise{instance, from}, Componentwise{derived} { + if (Componentwise::IsComplete()) { + Elementwise::SkipToEnd(); + } + } + RT_API_ATTRS bool IsComplete() const { return Elementwise::IsComplete(); } + RT_API_ATTRS void Advance() { + SkipToNextComponent(); + if (Componentwise::IsComplete()) { + Componentwise::Reset(); + Elementwise::Advance(); + } + } + RT_API_ATTRS void SkipToNextComponent() { + phase_ = 0; + Componentwise::Advance(); + } + RT_API_ATTRS void SkipToNextElement() { + phase_ = 0; + Componentwise::Reset(); + Elementwise::Advance(); + } + +protected: + int phase_{0}; +}; + +// Ticket worker classes + +// Implements derived type instance initialization +class InitializeTicket : public ImmediateTicketRunner, + private ComponentsOverElements { +public: + RT_API_ATTRS InitializeTicket( + const Descriptor &instance, const typeInfo::DerivedType &derived) + : ImmediateTicketRunner{*this}, + ComponentsOverElements{instance, derived} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); +}; + +// Initializes one derived type instance from the value of another +class InitializeCloneTicket + : public ImmediateTicketRunner, + private ComponentsOverElements { +public: + RT_API_ATTRS InitializeCloneTicket(const Descriptor &clone, + const Descriptor &original, const typeInfo::DerivedType &derived, + bool hasStat, const Descriptor *errMsg) + : ImmediateTicketRunner{*this}, + ComponentsOverElements{original, derived}, clone_{clone}, + hasStat_{hasStat}, errMsg_{errMsg} {} + RT_API_ATTRS int Begin(WorkQueue &) { return StatContinue; } + RT_API_ATTRS int Continue(WorkQueue &); + +private: + const Descriptor &clone_; + bool hasStat_{false}; + const Descriptor *errMsg_{nullptr}; + StaticDescriptor cloneComponentDescriptor_; +}; + +// Implements derived type instance finalization +class FinalizeTicket : public ImmediateTicketRunner, + private ComponentsOverElements { +public: + RT_API_ATTRS FinalizeTicket( + const Descriptor &instance, const typeInfo::DerivedType &derived) + : ImmediateTicketRunner{*this}, + ComponentsOverElements{instance, derived} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); + +private: + const typeInfo::DerivedType *finalizableParentType_{nullptr}; +}; + +// Implements derived type instance destruction +class DestroyTicket : public ImmediateTicketRunner, + private ComponentsOverElements { +public: + RT_API_ATTRS DestroyTicket(const Descriptor &instance, + const typeInfo::DerivedType &derived, bool finalize) + : ImmediateTicketRunner{*this}, + ComponentsOverElements{instance, derived}, finalize_{finalize} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); + +private: + bool finalize_{false}; +}; + +// Implements general intrinsic assignment +class AssignTicket : public ImmediateTicketRunner { +public: + RT_API_ATTRS AssignTicket(Descriptor &to, const Descriptor &from, int flags, + MemmoveFct memmoveFct, const typeInfo::DerivedType *declaredType) + : ImmediateTicketRunner{*this}, to_{to}, from_{&from}, + flags_{flags}, memmoveFct_{memmoveFct}, declaredType_{declaredType} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); + +private: + RT_API_ATTRS bool IsSimpleMemmove() const { + return !toDerived_ && to_.rank() == from_->rank() && to_.IsContiguous() && + from_->IsContiguous() && to_.ElementBytes() == from_->ElementBytes(); + } + RT_API_ATTRS Descriptor &GetTempDescriptor(); + + Descriptor &to_; + const Descriptor *from_{nullptr}; + int flags_{0}; // enum AssignFlags + MemmoveFct memmoveFct_{nullptr}; + StaticDescriptor tempDescriptor_; + const typeInfo::DerivedType *declaredType_{nullptr}; + const typeInfo::DerivedType *toDerived_{nullptr}; + Descriptor *toDeallocate_{nullptr}; + bool persist_{false}; + bool done_{false}; +}; + +// Implements derived type intrinsic assignment. +template +class DerivedAssignTicket + : public ImmediateTicketRunner>, + private std::conditional_t { +public: + using Base = std::conditional_t; + RT_API_ATTRS DerivedAssignTicket(const Descriptor &to, const Descriptor &from, + const typeInfo::DerivedType &derived, int flags, MemmoveFct memmoveFct, + Descriptor *deallocateAfter) + : ImmediateTicketRunner{*this}, + Base{to, derived, &from}, flags_{flags}, memmoveFct_{memmoveFct}, + deallocateAfter_{deallocateAfter} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); + +private: + static constexpr bool isComponentwise_{IS_COMPONENTWISE}; + bool toIsContiguous_{this->instance_.IsContiguous()}; + bool fromIsContiguous_{this->from_->IsContiguous()}; + int flags_{0}; + MemmoveFct memmoveFct_{nullptr}; + Descriptor *deallocateAfter_{nullptr}; + StaticDescriptor fromComponentDescriptor_; +}; + +namespace io::descr { + +template +class DescriptorIoTicket + : public ImmediateTicketRunner>, + private Elementwise { +public: + RT_API_ATTRS DescriptorIoTicket(io::IoStatementState &io, + const Descriptor &descriptor, const io::NonTbpDefinedIoTable *table, + bool &anyIoTookPlace) + : ImmediateTicketRunner(*this), + Elementwise{descriptor}, io_{io}, table_{table}, + anyIoTookPlace_{anyIoTookPlace} {} + RT_API_ATTRS int Begin(WorkQueue &); + RT_API_ATTRS int Continue(WorkQueue &); + RT_API_ATTRS bool &anyIoTookPlace() { return anyIoTookPlace_; } + +private: + io::IoStatementState &io_; + const io::NonTbpDefinedIoTable *table_{nullptr}; + bool &anyIoTookPlace_; + common::optional nonTbpSpecial_; + const typeInfo::DerivedType *derived_{nullptr}; + const typeInfo::SpecialBinding *special_{nullptr}; + StaticDescriptor elementDescriptor_; +}; + +template +class DerivedIoTicket : public ImmediateTicketRunner>, + private ElementsOverComponents { +public: + RT_API_ATTRS DerivedIoTicket(io::IoStatementState &io, + const Descriptor &descriptor, const typeInfo::DerivedType &derived, + const io::NonTbpDefinedIoTable *table, bool &anyIoTookPlace) + : ImmediateTicketRunner(*this), + ElementsOverComponents{descriptor, derived}, io_{io}, table_{table}, + anyIoTookPlace_{anyIoTookPlace} {} + RT_API_ATTRS int Begin(WorkQueue &) { return StatContinue; } + RT_API_ATTRS int Continue(WorkQueue &); + +private: + io::IoStatementState &io_; + const io::NonTbpDefinedIoTable *table_{nullptr}; + bool &anyIoTookPlace_; +}; + +} // namespace io::descr + +struct NullTicket { + RT_API_ATTRS int Begin(WorkQueue &) const { return StatOk; } + RT_API_ATTRS int Continue(WorkQueue &) const { return StatOk; } +}; + +struct Ticket { + RT_API_ATTRS int Continue(WorkQueue &); + bool begun{false}; + std::variant, + DerivedAssignTicket, + io::descr::DescriptorIoTicket, + io::descr::DescriptorIoTicket, + io::descr::DerivedIoTicket, + io::descr::DerivedIoTicket> + u; +}; + +class WorkQueue { +public: + RT_API_ATTRS explicit WorkQueue(Terminator &terminator) + : terminator_{terminator} { + for (int j{1}; j < numStatic_; ++j) { + static_[j].previous = &static_[j - 1]; + static_[j - 1].next = &static_[j]; + } + } + RT_API_ATTRS ~WorkQueue(); + RT_API_ATTRS Terminator &terminator() { return terminator_; }; + + // APIs for particular tasks. These can return StatOk if the work is + // completed immediately. + RT_API_ATTRS int BeginInitialize( + const Descriptor &descriptor, const typeInfo::DerivedType &derived) { + if (runTicketsImmediately_) { + return InitializeTicket{descriptor, derived}.Run(*this); + } else { + StartTicket().u.emplace(descriptor, derived); + return StatContinue; + } + } + RT_API_ATTRS int BeginInitializeClone(const Descriptor &clone, + const Descriptor &original, const typeInfo::DerivedType &derived, + bool hasStat, const Descriptor *errMsg) { + if (runTicketsImmediately_) { + return InitializeCloneTicket{clone, original, derived, hasStat, errMsg} + .Run(*this); + } else { + StartTicket().u.emplace( + clone, original, derived, hasStat, errMsg); + return StatContinue; + } + } + RT_API_ATTRS int BeginFinalize( + const Descriptor &descriptor, const typeInfo::DerivedType &derived) { + if (runTicketsImmediately_) { + return FinalizeTicket{descriptor, derived}.Run(*this); + } else { + StartTicket().u.emplace(descriptor, derived); + return StatContinue; + } + } + RT_API_ATTRS int BeginDestroy(const Descriptor &descriptor, + const typeInfo::DerivedType &derived, bool finalize) { + if (runTicketsImmediately_) { + return DestroyTicket{descriptor, derived, finalize}.Run(*this); + } else { + StartTicket().u.emplace(descriptor, derived, finalize); + return StatContinue; + } + } + RT_API_ATTRS int BeginAssign(Descriptor &to, const Descriptor &from, + int flags, MemmoveFct memmoveFct, + const typeInfo::DerivedType *declaredType) { + if (runTicketsImmediately_) { + return AssignTicket{to, from, flags, memmoveFct, declaredType}.Run(*this); + } else { + StartTicket().u.emplace( + to, from, flags, memmoveFct, declaredType); + return StatContinue; + } + } + template + RT_API_ATTRS int BeginDerivedAssign(Descriptor &to, const Descriptor &from, + const typeInfo::DerivedType &derived, int flags, MemmoveFct memmoveFct, + Descriptor *deallocateAfter) { + if (runTicketsImmediately_) { + return DerivedAssignTicket{ + to, from, derived, flags, memmoveFct, deallocateAfter} + .Run(*this); + } else { + StartTicket().u.emplace>( + to, from, derived, flags, memmoveFct, deallocateAfter); + return StatContinue; + } + } + template + RT_API_ATTRS int BeginDescriptorIo(io::IoStatementState &io, + const Descriptor &descriptor, const io::NonTbpDefinedIoTable *table, + bool &anyIoTookPlace) { + if (runTicketsImmediately_) { + return io::descr::DescriptorIoTicket{ + io, descriptor, table, anyIoTookPlace} + .Run(*this); + } else { + StartTicket().u.emplace>( + io, descriptor, table, anyIoTookPlace); + return StatContinue; + } + } + template + RT_API_ATTRS int BeginDerivedIo(io::IoStatementState &io, + const Descriptor &descriptor, const typeInfo::DerivedType &derived, + const io::NonTbpDefinedIoTable *table, bool &anyIoTookPlace) { + if (runTicketsImmediately_) { + return io::descr::DerivedIoTicket{ + io, descriptor, derived, table, anyIoTookPlace} + .Run(*this); + } else { + StartTicket().u.emplace>( + io, descriptor, derived, table, anyIoTookPlace); + return StatContinue; + } + } + + RT_API_ATTRS int Run(); + +private: +#if RT_DEVICE_COMPILATION + // Always use the work queue on a GPU device to avoid recursion. + static constexpr bool runTicketsImmediately_{false}; +#else + // Avoid the work queue overhead on the host, unless it needs + // debugging, which is so much easier there. + static constexpr bool runTicketsImmediately_{true}; +#endif + + // Most uses of the work queue won't go very deep. + static constexpr int numStatic_{2}; + + struct TicketList { + bool isStatic{true}; + Ticket ticket; + TicketList *previous{nullptr}, *next{nullptr}; + }; + + RT_API_ATTRS Ticket &StartTicket(); + RT_API_ATTRS void Stop(); + + Terminator &terminator_; + TicketList *first_{nullptr}, *last_{nullptr}, *insertAfter_{nullptr}; + TicketList static_[numStatic_]; + TicketList *firstFree_{static_}; +}; + +} // namespace Fortran::runtime +#endif // FLANG_RT_RUNTIME_WORK_QUEUE_H_ diff --git a/flang-rt/lib/cuda/descriptor.cpp b/flang-rt/lib/cuda/descriptor.cpp index 7b768f91af29..aa75d4eff051 100644 --- a/flang-rt/lib/cuda/descriptor.cpp +++ b/flang-rt/lib/cuda/descriptor.cpp @@ -54,6 +54,14 @@ void RTDEF(CUFSyncGlobalDescriptor)( ((Descriptor *)devAddr, (Descriptor *)hostPtr, sourceFile, sourceLine); } +void RTDEF(CUFDescriptorCheckSection)( + const Descriptor *desc, const char *sourceFile, int sourceLine) { + if (desc && !desc->IsContiguous()) { + Terminator terminator{sourceFile, sourceLine}; + terminator.Crash("device array section argument is not contiguous"); + } +} + RT_EXT_API_GROUP_END } } // namespace Fortran::runtime::cuda diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt index a3f63b431564..332c0872e065 100644 --- a/flang-rt/lib/runtime/CMakeLists.txt +++ b/flang-rt/lib/runtime/CMakeLists.txt @@ -68,6 +68,7 @@ set(supported_sources type-info.cpp unit.cpp utf.cpp + work-queue.cpp ) # List of source not used for GPU offloading. @@ -131,6 +132,7 @@ set(gpu_sources type-code.cpp type-info.cpp utf.cpp + work-queue.cpp complex-powi.cpp reduce.cpp reduction.cpp diff --git a/flang-rt/lib/runtime/allocatable.cpp b/flang-rt/lib/runtime/allocatable.cpp index ef18da6ea078..f724f0a20884 100644 --- a/flang-rt/lib/runtime/allocatable.cpp +++ b/flang-rt/lib/runtime/allocatable.cpp @@ -165,6 +165,26 @@ int RTDEF(AllocatableAllocateSource)(Descriptor &alloc, alloc, /*asyncObject=*/nullptr, hasStat, errMsg, sourceFile, sourceLine)}; if (stat == StatOk) { Terminator terminator{sourceFile, sourceLine}; + if (alloc.rank() != source.rank() && source.rank() != 0) { + terminator.Crash("ALLOCATE object has rank %d while SOURCE= has rank %d", + alloc.rank(), source.rank()); + } + if (int rank{source.rank()}; rank > 0) { + SubscriptValue allocExtent[maxRank], sourceExtent[maxRank]; + alloc.GetShape(allocExtent); + source.GetShape(sourceExtent); + for (int j{0}; j < rank; ++j) { + if (allocExtent[j] != sourceExtent[j]) { + if (!hasStat) { + terminator.Crash("ALLOCATE object has extent %jd on dimension %d, " + "but SOURCE= has extent %jd", + static_cast(allocExtent[j]), j + 1, + static_cast(sourceExtent[j])); + } + return StatInvalidExtent; + } + } + } DoFromSourceAssign(alloc, source, terminator); } return stat; diff --git a/flang-rt/lib/runtime/assign.cpp b/flang-rt/lib/runtime/assign.cpp index bf67b5dc8b64..f936a4192a33 100644 --- a/flang-rt/lib/runtime/assign.cpp +++ b/flang-rt/lib/runtime/assign.cpp @@ -14,6 +14,7 @@ #include "flang-rt/runtime/terminator.h" #include "flang-rt/runtime/tools.h" #include "flang-rt/runtime/type-info.h" +#include "flang-rt/runtime/work-queue.h" namespace Fortran::runtime { @@ -62,9 +63,22 @@ static inline RT_API_ATTRS bool MustDeallocateLHS( // Distinct shape? Deallocate int rank{to.rank()}; for (int j{0}; j < rank; ++j) { - if (to.GetDimension(j).Extent() != from.GetDimension(j).Extent()) { + const auto &toDim{to.GetDimension(j)}; + const auto &fromDim{from.GetDimension(j)}; + if (toDim.Extent() != fromDim.Extent()) { return true; } + if ((flags & UpdateLHSBounds) && + toDim.LowerBound() != fromDim.LowerBound()) { + return true; + } + } + } + // Not reallocating; may have to update bounds + if (flags & UpdateLHSBounds) { + int rank{to.rank()}; + for (int j{0}; j < rank; ++j) { + to.GetDimension(j).SetLowerBound(from.GetDimension(j).LowerBound()); } } return false; @@ -102,11 +116,7 @@ static RT_API_ATTRS int AllocateAssignmentLHS( toDim.SetByteStride(stride); stride *= toDim.Extent(); } - int result{ReturnError(terminator, to.Allocate(kNoAsyncObject))}; - if (result == StatOk && derived && !derived->noInitializationNeeded()) { - result = ReturnError(terminator, Initialize(to, *derived, terminator)); - } - return result; + return ReturnError(terminator, to.Allocate(kNoAsyncObject)); } // least <= 0, most >= 0 @@ -169,24 +179,27 @@ static RT_API_ATTRS bool MayAlias(const Descriptor &x, const Descriptor &y) { } static RT_API_ATTRS void DoScalarDefinedAssignment(const Descriptor &to, - const Descriptor &from, const typeInfo::SpecialBinding &special) { + const Descriptor &from, const typeInfo::DerivedType &derived, + const typeInfo::SpecialBinding &special) { bool toIsDesc{special.IsArgDescriptor(0)}; bool fromIsDesc{special.IsArgDescriptor(1)}; + const auto *bindings{ + derived.binding().OffsetElement()}; if (toIsDesc) { if (fromIsDesc) { - auto *p{ - special.GetProc()}; + auto *p{special.GetProc( + bindings)}; p(to, from); } else { - auto *p{special.GetProc()}; + auto *p{special.GetProc(bindings)}; p(to, from.raw().base_addr); } } else { if (fromIsDesc) { - auto *p{special.GetProc()}; + auto *p{special.GetProc(bindings)}; p(to.raw().base_addr, from); } else { - auto *p{special.GetProc()}; + auto *p{special.GetProc(bindings)}; p(to.raw().base_addr, from.raw().base_addr); } } @@ -208,7 +221,7 @@ static RT_API_ATTRS void DoElementalDefinedAssignment(const Descriptor &to, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { toElementDesc.set_base_addr(to.Element(toAt)); fromElementDesc.set_base_addr(from.Element(fromAt)); - DoScalarDefinedAssignment(toElementDesc, fromElementDesc, special); + DoScalarDefinedAssignment(toElementDesc, fromElementDesc, derived, special); } } @@ -231,6 +244,8 @@ static RT_API_ATTRS void BlankPadCharacterAssignment(Descriptor &to, } } +RT_OFFLOAD_API_GROUP_BEGIN + // Common implementation of assignments, both intrinsic assignments and // those cases of polymorphic user-defined ASSIGNMENT(=) TBPs that could not // be resolved in semantics. Most assignment statements do not need any @@ -244,275 +259,461 @@ static RT_API_ATTRS void BlankPadCharacterAssignment(Descriptor &to, // dealing with array constructors. RT_API_ATTRS void Assign(Descriptor &to, const Descriptor &from, Terminator &terminator, int flags, MemmoveFct memmoveFct) { - bool mustDeallocateLHS{(flags & DeallocateLHS) || - MustDeallocateLHS(to, from, terminator, flags)}; - DescriptorAddendum *toAddendum{to.Addendum()}; - const typeInfo::DerivedType *toDerived{ - toAddendum ? toAddendum->derivedType() : nullptr}; - if (toDerived && (flags & NeedFinalization) && - toDerived->noFinalizationNeeded()) { - flags &= ~NeedFinalization; + WorkQueue workQueue{terminator}; + if (workQueue.BeginAssign(to, from, flags, memmoveFct, nullptr) == + StatContinue) { + workQueue.Run(); } - std::size_t toElementBytes{to.ElementBytes()}; - std::size_t fromElementBytes{from.ElementBytes()}; - // The following lambda definition violates the conding style, - // but cuda-11.8 nvcc hits an internal error with the brace initialization. - auto isSimpleMemmove = [&]() { - return !toDerived && to.rank() == from.rank() && to.IsContiguous() && - from.IsContiguous() && toElementBytes == fromElementBytes; - }; - StaticDescriptor deferredDeallocStatDesc; - Descriptor *deferDeallocation{nullptr}; - if (MayAlias(to, from)) { +} + +RT_API_ATTRS int AssignTicket::Begin(WorkQueue &workQueue) { + bool mustDeallocateLHS{(flags_ & DeallocateLHS) || + MustDeallocateLHS(to_, *from_, workQueue.terminator(), flags_)}; + DescriptorAddendum *toAddendum{to_.Addendum()}; + toDerived_ = toAddendum ? toAddendum->derivedType() : nullptr; + if (toDerived_ && (flags_ & NeedFinalization) && + toDerived_->noFinalizationNeeded()) { + flags_ &= ~NeedFinalization; + } + if (MayAlias(to_, *from_)) { if (mustDeallocateLHS) { - deferDeallocation = &deferredDeallocStatDesc.descriptor(); + // Convert the LHS into a temporary, then make it look deallocated. + toDeallocate_ = &tempDescriptor_.descriptor(); + persist_ = true; // tempDescriptor_ state must outlive child tickets std::memcpy( - reinterpret_cast(deferDeallocation), &to, to.SizeInBytes()); - to.set_base_addr(nullptr); - } else if (!isSimpleMemmove()) { + reinterpret_cast(toDeallocate_), &to_, to_.SizeInBytes()); + to_.set_base_addr(nullptr); + if (toDerived_ && (flags_ & NeedFinalization)) { + if (int status{workQueue.BeginFinalize(*toDeallocate_, *toDerived_)}; + status != StatOk && status != StatContinue) { + return status; + } + flags_ &= ~NeedFinalization; + } + } else if (!IsSimpleMemmove()) { // Handle LHS/RHS aliasing by copying RHS into a temp, then // recursively assigning from that temp. - auto descBytes{from.SizeInBytes()}; - StaticDescriptor staticDesc; - Descriptor &newFrom{staticDesc.descriptor()}; - std::memcpy(reinterpret_cast(&newFrom), &from, descBytes); + auto descBytes{from_->SizeInBytes()}; + Descriptor &newFrom{tempDescriptor_.descriptor()}; + persist_ = true; // tempDescriptor_ state must outlive child tickets + std::memcpy(reinterpret_cast(&newFrom), from_, descBytes); // Pretend the temporary descriptor is for an ALLOCATABLE // entity, otherwise, the Deallocate() below will not // free the descriptor memory. newFrom.raw().attribute = CFI_attribute_allocatable; - auto stat{ReturnError(terminator, newFrom.Allocate(kNoAsyncObject))}; - if (stat == StatOk) { - if (HasDynamicComponent(from)) { - // If 'from' has allocatable/automatic component, we cannot - // just make a shallow copy of the descriptor member. - // This will still leave data overlap in 'to' and 'newFrom'. - // For example: - // type t - // character, allocatable :: c(:) - // end type t - // type(t) :: x(3) - // x(2:3) = x(1:2) - // We have to make a deep copy into 'newFrom' in this case. - RTNAME(AssignTemporary) - (newFrom, from, terminator.sourceFileName(), terminator.sourceLine()); - } else { - ShallowCopy(newFrom, from, true, from.IsContiguous()); - } - Assign(to, newFrom, terminator, - flags & - (NeedFinalization | ComponentCanBeDefinedAssignment | - ExplicitLengthCharacterLHS | CanBeDefinedAssignment)); - newFrom.Deallocate(); + if (int stat{ReturnError( + workQueue.terminator(), newFrom.Allocate(kNoAsyncObject))}; + stat != StatOk) { + return stat; } - return; - } - } - if (to.IsAllocatable()) { - if (mustDeallocateLHS) { - if (deferDeallocation) { - if ((flags & NeedFinalization) && toDerived) { - Finalize(*deferDeallocation, *toDerived, &terminator); - flags &= ~NeedFinalization; - } - } else { - to.Destroy((flags & NeedFinalization) != 0, /*destroyPointers=*/false, - &terminator); - flags &= ~NeedFinalization; - } - } else if (to.rank() != from.rank() && !to.IsAllocated()) { - terminator.Crash("Assign: mismatched ranks (%d != %d) in assignment to " - "unallocated allocatable", - to.rank(), from.rank()); - } - if (!to.IsAllocated()) { - if (AllocateAssignmentLHS(to, from, terminator, flags) != StatOk) { - return; - } - flags &= ~NeedFinalization; - toElementBytes = to.ElementBytes(); // may have changed - toDerived = toAddendum ? toAddendum->derivedType() : nullptr; - } - } - if (toDerived && (flags & CanBeDefinedAssignment)) { - // Check for a user-defined assignment type-bound procedure; - // see 10.2.1.4-5. A user-defined assignment TBP defines all of - // the semantics, including allocatable (re)allocation and any - // finalization. - // - // Note that the aliasing and LHS (re)allocation handling above - // needs to run even with CanBeDefinedAssignment flag, when - // the Assign() is invoked recursively for component-per-component - // assignments. - if (to.rank() == 0) { - if (const auto *special{toDerived->FindSpecialBinding( - typeInfo::SpecialBinding::Which::ScalarAssignment)}) { - return DoScalarDefinedAssignment(to, from, *special); - } - } - if (const auto *special{toDerived->FindSpecialBinding( - typeInfo::SpecialBinding::Which::ElementalAssignment)}) { - return DoElementalDefinedAssignment(to, from, *toDerived, *special); - } - } - SubscriptValue toAt[maxRank]; - to.GetLowerBounds(toAt); - // Scalar expansion of the RHS is implied by using the same empty - // subscript values on each (seemingly) elemental reference into - // "from". - SubscriptValue fromAt[maxRank]; - from.GetLowerBounds(fromAt); - std::size_t toElements{to.Elements()}; - if (from.rank() > 0 && toElements != from.Elements()) { - terminator.Crash("Assign: mismatching element counts in array assignment " - "(to %zd, from %zd)", - toElements, from.Elements()); - } - if (to.type() != from.type()) { - terminator.Crash("Assign: mismatching types (to code %d != from code %d)", - to.type().raw(), from.type().raw()); - } - if (toElementBytes > fromElementBytes && !to.type().IsCharacter()) { - terminator.Crash("Assign: mismatching non-character element sizes (to %zd " - "bytes != from %zd bytes)", - toElementBytes, fromElementBytes); - } - if (const typeInfo::DerivedType * - updatedToDerived{toAddendum ? toAddendum->derivedType() : nullptr}) { - // Derived type intrinsic assignment, which is componentwise and elementwise - // for all components, including parent components (10.2.1.2-3). - // The target is first finalized if still necessary (7.5.6.3(1)) - if (flags & NeedFinalization) { - Finalize(to, *updatedToDerived, &terminator); - } else if (updatedToDerived && !updatedToDerived->noDestructionNeeded()) { - Destroy(to, /*finalize=*/false, *updatedToDerived, &terminator); - } - // Copy the data components (incl. the parent) first. - const Descriptor &componentDesc{updatedToDerived->component()}; - std::size_t numComponents{componentDesc.Elements()}; - for (std::size_t j{0}; j < toElements; - ++j, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - for (std::size_t k{0}; k < numComponents; ++k) { - const auto &comp{ - *componentDesc.ZeroBasedIndexedElement( - k)}; // TODO: exploit contiguity here - // Use PolymorphicLHS for components so that the right things happen - // when the components are polymorphic; when they're not, they're both - // not, and their declared types will match. - int nestedFlags{MaybeReallocate | PolymorphicLHS}; - if (flags & ComponentCanBeDefinedAssignment) { - nestedFlags |= - CanBeDefinedAssignment | ComponentCanBeDefinedAssignment; - } - switch (comp.genre()) { - case typeInfo::Component::Genre::Data: - if (comp.category() == TypeCategory::Derived) { - StaticDescriptor statDesc[2]; - Descriptor &toCompDesc{statDesc[0].descriptor()}; - Descriptor &fromCompDesc{statDesc[1].descriptor()}; - comp.CreatePointerDescriptor(toCompDesc, to, terminator, toAt); - comp.CreatePointerDescriptor( - fromCompDesc, from, terminator, fromAt); - Assign(toCompDesc, fromCompDesc, terminator, nestedFlags); - } else { // Component has intrinsic type; simply copy raw bytes - std::size_t componentByteSize{comp.SizeInBytes(to)}; - memmoveFct(to.Element(toAt) + comp.offset(), - from.Element(fromAt) + comp.offset(), - componentByteSize); - } - break; - case typeInfo::Component::Genre::Pointer: { - std::size_t componentByteSize{comp.SizeInBytes(to)}; - memmoveFct(to.Element(toAt) + comp.offset(), - from.Element(fromAt) + comp.offset(), - componentByteSize); - } break; - case typeInfo::Component::Genre::Allocatable: - case typeInfo::Component::Genre::Automatic: { - auto *toDesc{reinterpret_cast( - to.Element(toAt) + comp.offset())}; - const auto *fromDesc{reinterpret_cast( - from.Element(fromAt) + comp.offset())}; - // Allocatable components of the LHS are unconditionally - // deallocated before assignment (F'2018 10.2.1.3(13)(1)), - // unlike a "top-level" assignment to a variable, where - // deallocation is optional. - // - // Be careful not to destroy/reallocate the LHS, if there is - // overlap between LHS and RHS (it seems that partial overlap - // is not possible, though). - // Invoke Assign() recursively to deal with potential aliasing. - if (toDesc->IsAllocatable()) { - if (!fromDesc->IsAllocated()) { - // No aliasing. - // - // If to is not allocated, the Destroy() call is a no-op. - // This is just a shortcut, because the recursive Assign() - // below would initiate the destruction for to. - // No finalization is required. - toDesc->Destroy( - /*finalize=*/false, /*destroyPointers=*/false, &terminator); - continue; // F'2018 10.2.1.3(13)(2) + if (HasDynamicComponent(*from_)) { + // If 'from' has allocatable/automatic component, we cannot + // just make a shallow copy of the descriptor member. + // This will still leave data overlap in 'to' and 'newFrom'. + // For example: + // type t + // character, allocatable :: c(:) + // end type t + // type(t) :: x(3) + // x(2:3) = x(1:2) + // We have to make a deep copy into 'newFrom' in this case. + if (const DescriptorAddendum *addendum{newFrom.Addendum()}) { + if (const auto *derived{addendum->derivedType()}) { + if (!derived->noInitializationNeeded()) { + if (int status{workQueue.BeginInitialize(newFrom, *derived)}; + status != StatOk && status != StatContinue) { + return status; + } } } - // Force LHS deallocation with DeallocateLHS flag. - // The actual deallocation may be avoided, if the existing - // location can be reoccupied. - Assign(*toDesc, *fromDesc, terminator, nestedFlags | DeallocateLHS); - } break; } + static constexpr int nestedFlags{MaybeReallocate | PolymorphicLHS}; + if (int status{workQueue.BeginAssign( + newFrom, *from_, nestedFlags, memmoveFct_, nullptr)}; + status != StatOk && status != StatContinue) { + return status; + } + } else { + ShallowCopy(newFrom, *from_, true, from_->IsContiguous()); } - // Copy procedure pointer components - const Descriptor &procPtrDesc{updatedToDerived->procPtr()}; - std::size_t numProcPtrs{procPtrDesc.Elements()}; - for (std::size_t k{0}; k < numProcPtrs; ++k) { - const auto &procPtr{ - *procPtrDesc.ZeroBasedIndexedElement( - k)}; - memmoveFct(to.Element(toAt) + procPtr.offset, - from.Element(fromAt) + procPtr.offset, - sizeof(typeInfo::ProcedurePointer)); + from_ = &newFrom; // this is why from_ has to be a pointer + flags_ &= NeedFinalization | ComponentCanBeDefinedAssignment | + ExplicitLengthCharacterLHS | CanBeDefinedAssignment; + toDeallocate_ = &newFrom; + } + } + if (to_.IsAllocatable()) { + if (mustDeallocateLHS) { + if (!toDeallocate_ && to_.IsAllocated()) { + toDeallocate_ = &to_; + } + } else if (to_.rank() != from_->rank() && !to_.IsAllocated()) { + workQueue.terminator().Crash("Assign: mismatched ranks (%d != %d) in " + "assignment to unallocated allocatable", + to_.rank(), from_->rank()); + } + } else if (!to_.IsAllocated()) { + workQueue.terminator().Crash( + "Assign: left-hand side variable is neither allocated nor allocatable"); + } + if (toDerived_ && to_.IsAllocated()) { + // Schedule finalization or destruction of the LHS. + if (flags_ & NeedFinalization) { + if (int status{workQueue.BeginFinalize(to_, *toDerived_)}; + status != StatOk && status != StatContinue) { + return status; + } + } else if (!toDerived_->noDestructionNeeded()) { + if (int status{ + workQueue.BeginDestroy(to_, *toDerived_, /*finalize=*/false)}; + status != StatOk && status != StatContinue) { + return status; } } - } else { // intrinsic type, intrinsic assignment - if (isSimpleMemmove()) { - memmoveFct(to.raw().base_addr, from.raw().base_addr, - toElements * toElementBytes); - } else if (toElementBytes > fromElementBytes) { // blank padding - switch (to.type().raw()) { + } + return StatContinue; +} + +RT_API_ATTRS int AssignTicket::Continue(WorkQueue &workQueue) { + if (done_) { + // All child tickets are complete; can release this ticket's state. + if (toDeallocate_) { + toDeallocate_->Deallocate(); + } + return StatOk; + } + // All necessary finalization or destruction that was initiated by Begin() + // has been completed. Deallocation may be pending, and if it's for the LHS, + // do it now so that the LHS gets reallocated. + if (toDeallocate_ == &to_) { + toDeallocate_ = nullptr; + to_.Deallocate(); + } + // Allocate the LHS if needed + if (!to_.IsAllocated()) { + if (int stat{ + AllocateAssignmentLHS(to_, *from_, workQueue.terminator(), flags_)}; + stat != StatOk) { + return stat; + } + const auto *addendum{to_.Addendum()}; + toDerived_ = addendum ? addendum->derivedType() : nullptr; + if (toDerived_) { + if (!toDerived_->noInitializationNeeded()) { + if (int status{workQueue.BeginInitialize(to_, *toDerived_)}; + status != StatOk) { + return status; + } + } + } + } + // Check for a user-defined assignment type-bound procedure; + // see 10.2.1.4-5. + // Note that the aliasing and LHS (re)allocation handling above + // needs to run even with CanBeDefinedAssignment flag, since + // Assign() can be invoked recursively for component-wise assignments. + // The declared type (if known) must be used for generic resolution + // of ASSIGNMENT(=) to a binding, but that binding can be overridden. + if (declaredType_ && (flags_ & CanBeDefinedAssignment)) { + if (to_.rank() == 0) { + if (const auto *special{declaredType_->FindSpecialBinding( + typeInfo::SpecialBinding::Which::ScalarAssignment)}) { + DoScalarDefinedAssignment(to_, *from_, *toDerived_, *special); + done_ = true; + return StatContinue; + } + } + if (const auto *special{declaredType_->FindSpecialBinding( + typeInfo::SpecialBinding::Which::ElementalAssignment)}) { + DoElementalDefinedAssignment(to_, *from_, *toDerived_, *special); + done_ = true; + return StatContinue; + } + } + // Intrinsic assignment + std::size_t toElements{to_.Elements()}; + if (from_->rank() > 0 && toElements != from_->Elements()) { + workQueue.terminator().Crash("Assign: mismatching element counts in array " + "assignment (to %zd, from %zd)", + toElements, from_->Elements()); + } + if (to_.type() != from_->type()) { + workQueue.terminator().Crash( + "Assign: mismatching types (to code %d != from code %d)", + to_.type().raw(), from_->type().raw()); + } + std::size_t toElementBytes{to_.ElementBytes()}; + std::size_t fromElementBytes{from_->ElementBytes()}; + if (toElementBytes > fromElementBytes && !to_.type().IsCharacter()) { + workQueue.terminator().Crash("Assign: mismatching non-character element " + "sizes (to %zd bytes != from %zd bytes)", + toElementBytes, fromElementBytes); + } + if (toDerived_) { + if (toDerived_->noDefinedAssignment()) { // componentwise + if (int status{workQueue.BeginDerivedAssign( + to_, *from_, *toDerived_, flags_, memmoveFct_, toDeallocate_)}; + status != StatOk && status != StatContinue) { + return status; + } + } else { // elementwise + if (int status{workQueue.BeginDerivedAssign( + to_, *from_, *toDerived_, flags_, memmoveFct_, toDeallocate_)}; + status != StatOk && status != StatContinue) { + return status; + } + } + toDeallocate_ = nullptr; + } else if (IsSimpleMemmove()) { + memmoveFct_(to_.raw().base_addr, from_->raw().base_addr, + toElements * toElementBytes); + } else { + // Scalar expansion of the RHS is implied by using the same empty + // subscript values on each (seemingly) elemental reference into + // "from". + SubscriptValue toAt[maxRank]; + to_.GetLowerBounds(toAt); + SubscriptValue fromAt[maxRank]; + from_->GetLowerBounds(fromAt); + if (toElementBytes > fromElementBytes) { // blank padding + switch (to_.type().raw()) { case CFI_type_signed_char: case CFI_type_char: - BlankPadCharacterAssignment(to, from, toAt, fromAt, toElements, + BlankPadCharacterAssignment(to_, *from_, toAt, fromAt, toElements, toElementBytes, fromElementBytes); break; case CFI_type_char16_t: - BlankPadCharacterAssignment(to, from, toAt, fromAt, + BlankPadCharacterAssignment(to_, *from_, toAt, fromAt, toElements, toElementBytes, fromElementBytes); break; case CFI_type_char32_t: - BlankPadCharacterAssignment(to, from, toAt, fromAt, + BlankPadCharacterAssignment(to_, *from_, toAt, fromAt, toElements, toElementBytes, fromElementBytes); break; default: - terminator.Crash("unexpected type code %d in blank padded Assign()", - to.type().raw()); + workQueue.terminator().Crash( + "unexpected type code %d in blank padded Assign()", + to_.type().raw()); } } else { // elemental copies, possibly with character truncation for (std::size_t n{toElements}; n-- > 0; - to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { - memmoveFct(to.Element(toAt), from.Element(fromAt), + to_.IncrementSubscripts(toAt), from_->IncrementSubscripts(fromAt)) { + memmoveFct_(to_.Element(toAt), from_->Element(fromAt), toElementBytes); } } } - if (deferDeallocation) { - // deferDeallocation is used only when LHS is an allocatable. - // The finalization has already been run for it. - deferDeallocation->Destroy( - /*finalize=*/false, /*destroyPointers=*/false, &terminator); + if (persist_) { + done_ = true; + return StatContinue; + } else { + if (toDeallocate_) { + toDeallocate_->Deallocate(); + toDeallocate_ = nullptr; + } + return StatOk; } } -RT_OFFLOAD_API_GROUP_BEGIN +template +RT_API_ATTRS int DerivedAssignTicket::Begin( + WorkQueue &workQueue) { + if (toIsContiguous_ && fromIsContiguous_ && + this->derived_.noDestructionNeeded() && + this->derived_.noDefinedAssignment() && + this->instance_.rank() == this->from_->rank()) { + if (std::size_t elementBytes{this->instance_.ElementBytes()}; + elementBytes == this->from_->ElementBytes()) { + // Fastest path. Both LHS and RHS are contiguous, RHS is not a scalar + // to be expanded, the types have the same size, and there are no + // allocatable components or defined ASSIGNMENT(=) at any level. + memmoveFct_(this->instance_.template OffsetElement(), + this->from_->template OffsetElement(), + this->instance_.Elements() * elementBytes); + return StatOk; + } + } + // Use PolymorphicLHS for components so that the right things happen + // when the components are polymorphic; when they're not, they're both + // not, and their declared types will match. + int nestedFlags{MaybeReallocate | PolymorphicLHS}; + if (flags_ & ComponentCanBeDefinedAssignment) { + nestedFlags |= CanBeDefinedAssignment | ComponentCanBeDefinedAssignment; + } + flags_ = nestedFlags; + // Copy procedure pointer components + const Descriptor &procPtrDesc{this->derived_.procPtr()}; + bool noDataComponents{this->IsComplete()}; + if (std::size_t numProcPtrs{procPtrDesc.Elements()}) { + for (std::size_t k{0}; k < numProcPtrs; ++k) { + const auto &procPtr{ + *procPtrDesc.ZeroBasedIndexedElement(k)}; + // Loop only over elements + if (k > 0) { + Elementwise::Reset(); + } + for (; !Elementwise::IsComplete(); Elementwise::Advance()) { + memmoveFct_(this->instance_.template ElementComponent( + this->subscripts_, procPtr.offset), + this->from_->template ElementComponent( + this->fromSubscripts_, procPtr.offset), + sizeof(typeInfo::ProcedurePointer)); + } + } + if (noDataComponents) { + return StatOk; + } + Elementwise::Reset(); + } + if (noDataComponents) { + return StatOk; + } + return StatContinue; +} +template RT_API_ATTRS int DerivedAssignTicket::Begin(WorkQueue &); +template RT_API_ATTRS int DerivedAssignTicket::Begin(WorkQueue &); + +template +RT_API_ATTRS int DerivedAssignTicket::Continue( + WorkQueue &workQueue) { + while (!this->IsComplete()) { + // Copy the data components (incl. the parent) first. + switch (this->component_->genre()) { + case typeInfo::Component::Genre::Data: + if (this->component_->category() == TypeCategory::Derived) { + Descriptor &toCompDesc{this->componentDescriptor_.descriptor()}; + Descriptor &fromCompDesc{this->fromComponentDescriptor_.descriptor()}; + this->component_->CreatePointerDescriptor(toCompDesc, this->instance_, + workQueue.terminator(), this->subscripts_); + this->component_->CreatePointerDescriptor(fromCompDesc, *this->from_, + workQueue.terminator(), this->fromSubscripts_); + const auto *componentDerived{this->component_->derivedType()}; + this->Advance(); + if (int status{workQueue.BeginAssign(toCompDesc, fromCompDesc, flags_, + memmoveFct_, componentDerived)}; + status != StatOk) { + return status; + } + } else { // Component has intrinsic type; simply copy raw bytes + std::size_t componentByteSize{ + this->component_->SizeInBytes(this->instance_)}; + if (IS_COMPONENTWISE && toIsContiguous_ && fromIsContiguous_) { + std::size_t offset{this->component_->offset()}; + char *to{this->instance_.template OffsetElement(offset)}; + const char *from{ + this->from_->template OffsetElement(offset)}; + std::size_t toElementStride{this->instance_.ElementBytes()}; + std::size_t fromElementStride{ + this->from_->rank() == 0 ? 0 : this->from_->ElementBytes()}; + if (toElementStride == fromElementStride && + toElementStride == componentByteSize) { + memmoveFct_(to, from, this->elements_ * componentByteSize); + } else { + for (std::size_t n{this->elements_}; n--; + to += toElementStride, from += fromElementStride) { + memmoveFct_(to, from, componentByteSize); + } + } + this->Componentwise::Advance(); + } else { + memmoveFct_( + this->instance_.template Element(this->subscripts_) + + this->component_->offset(), + this->from_->template Element(this->fromSubscripts_) + + this->component_->offset(), + componentByteSize); + this->Advance(); + } + } + break; + case typeInfo::Component::Genre::Pointer: { + std::size_t componentByteSize{ + this->component_->SizeInBytes(this->instance_)}; + if (IS_COMPONENTWISE && toIsContiguous_ && fromIsContiguous_) { + std::size_t offset{this->component_->offset()}; + char *to{this->instance_.template OffsetElement(offset)}; + const char *from{ + this->from_->template OffsetElement(offset)}; + std::size_t toElementStride{this->instance_.ElementBytes()}; + std::size_t fromElementStride{ + this->from_->rank() == 0 ? 0 : this->from_->ElementBytes()}; + if (toElementStride == fromElementStride && + toElementStride == componentByteSize) { + memmoveFct_(to, from, this->elements_ * componentByteSize); + } else { + for (std::size_t n{this->elements_}; n--; + to += toElementStride, from += fromElementStride) { + memmoveFct_(to, from, componentByteSize); + } + } + this->Componentwise::Advance(); + } else { + memmoveFct_(this->instance_.template Element(this->subscripts_) + + this->component_->offset(), + this->from_->template Element(this->fromSubscripts_) + + this->component_->offset(), + componentByteSize); + this->Advance(); + } + } break; + case typeInfo::Component::Genre::Allocatable: + case typeInfo::Component::Genre::Automatic: { + auto *toDesc{reinterpret_cast( + this->instance_.template Element(this->subscripts_) + + this->component_->offset())}; + const auto *fromDesc{reinterpret_cast( + this->from_->template Element(this->fromSubscripts_) + + this->component_->offset())}; + const auto *componentDerived{this->component_->derivedType()}; + if (toDesc->IsAllocatable() && !fromDesc->IsAllocated()) { + if (toDesc->IsAllocated()) { + if (this->phase_ == 0) { + this->phase_++; + if (componentDerived && !componentDerived->noDestructionNeeded()) { + if (int status{workQueue.BeginDestroy( + *toDesc, *componentDerived, /*finalize=*/false)}; + status != StatOk) { + return status; + } + } + } + toDesc->Deallocate(); + } + this->Advance(); + } else { + // Allocatable components of the LHS are unconditionally + // deallocated before assignment (F'2018 10.2.1.3(13)(1)), + // unlike a "top-level" assignment to a variable, where + // deallocation is optional. + int nestedFlags{flags_}; + if (!componentDerived || + (componentDerived->noFinalizationNeeded() && + componentDerived->noInitializationNeeded() && + componentDerived->noDestructionNeeded())) { + // The actual deallocation might be avoidable when the existing + // location can be reoccupied. + nestedFlags |= MaybeReallocate | UpdateLHSBounds; + } else { + // Force LHS deallocation with DeallocateLHS flag. + nestedFlags |= DeallocateLHS; + } + this->Advance(); + if (int status{workQueue.BeginAssign(*toDesc, *fromDesc, nestedFlags, + memmoveFct_, componentDerived)}; + status != StatOk) { + return status; + } + } + } break; + } + } + if (deallocateAfter_) { + deallocateAfter_->Deallocate(); + } + return StatOk; +} +template RT_API_ATTRS int DerivedAssignTicket::Continue(WorkQueue &); +template RT_API_ATTRS int DerivedAssignTicket::Continue(WorkQueue &); RT_API_ATTRS void DoFromSourceAssign(Descriptor &alloc, const Descriptor &source, Terminator &terminator, MemmoveFct memmoveFct) { @@ -582,7 +783,6 @@ void RTDEF(AssignTemporary)(Descriptor &to, const Descriptor &from, } } } - Assign(to, from, terminator, MaybeReallocate | PolymorphicLHS); } @@ -599,7 +799,6 @@ void RTDEF(CopyInAssign)(Descriptor &temp, const Descriptor &var, void RTDEF(CopyOutAssign)( Descriptor *var, Descriptor &temp, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; - // Copyout from the temporary must not cause any finalizations // for LHS. The variable must be properly initialized already. if (var) { diff --git a/flang-rt/lib/runtime/derived.cpp b/flang-rt/lib/runtime/derived.cpp index 35037036f63e..4e36b1e2edfc 100644 --- a/flang-rt/lib/runtime/derived.cpp +++ b/flang-rt/lib/runtime/derived.cpp @@ -12,6 +12,7 @@ #include "flang-rt/runtime/terminator.h" #include "flang-rt/runtime/tools.h" #include "flang-rt/runtime/type-info.h" +#include "flang-rt/runtime/work-queue.h" namespace Fortran::runtime { @@ -30,180 +31,192 @@ static RT_API_ATTRS void GetComponentExtents(SubscriptValue (&extents)[maxRank], } RT_API_ATTRS int Initialize(const Descriptor &instance, - const typeInfo::DerivedType &derived, Terminator &terminator, bool hasStat, - const Descriptor *errMsg) { - const Descriptor &componentDesc{derived.component()}; - std::size_t elements{instance.Elements()}; - int stat{StatOk}; - // Initialize data components in each element; the per-element iterations - // constitute the inner loops, not the outer ones - std::size_t myComponents{componentDesc.Elements()}; - for (std::size_t k{0}; k < myComponents; ++k) { - const auto &comp{ - *componentDesc.ZeroBasedIndexedElement(k)}; - SubscriptValue at[maxRank]; - instance.GetLowerBounds(at); - if (comp.genre() == typeInfo::Component::Genre::Allocatable || - comp.genre() == typeInfo::Component::Genre::Automatic) { - for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) { - Descriptor &allocDesc{ - *instance.ElementComponent(at, comp.offset())}; - comp.EstablishDescriptor(allocDesc, instance, terminator); - allocDesc.raw().attribute = CFI_attribute_allocatable; - if (comp.genre() == typeInfo::Component::Genre::Automatic) { - stat = ReturnError( - terminator, allocDesc.Allocate(kNoAsyncObject), errMsg, hasStat); - if (stat == StatOk) { - if (const DescriptorAddendum * addendum{allocDesc.Addendum()}) { - if (const auto *derived{addendum->derivedType()}) { - if (!derived->noInitializationNeeded()) { - stat = Initialize( - allocDesc, *derived, terminator, hasStat, errMsg); - } - } - } - } - if (stat != StatOk) { - break; - } - } + const typeInfo::DerivedType &derived, Terminator &terminator, bool, + const Descriptor *) { + WorkQueue workQueue{terminator}; + int status{workQueue.BeginInitialize(instance, derived)}; + return status == StatContinue ? workQueue.Run() : status; +} + +RT_API_ATTRS int InitializeTicket::Begin(WorkQueue &) { + // Initialize procedure pointer components in each element + const Descriptor &procPtrDesc{derived_.procPtr()}; + if (std::size_t numProcPtrs{procPtrDesc.Elements()}) { + for (std::size_t k{0}; k < numProcPtrs; ++k) { + const auto &comp{ + *procPtrDesc.ZeroBasedIndexedElement(k)}; + // Loop only over elements + if (k > 0) { + Elementwise::Reset(); } - } else if (const void *init{comp.initialization()}) { + for (; !Elementwise::IsComplete(); Elementwise::Advance()) { + auto &pptr{*instance_.ElementComponent( + subscripts_, comp.offset)}; + pptr = comp.procInitialization; + } + } + if (IsComplete()) { + return StatOk; + } + Elementwise::Reset(); + } + return StatContinue; +} + +RT_API_ATTRS int InitializeTicket::Continue(WorkQueue &workQueue) { + while (!IsComplete()) { + if (component_->genre() == typeInfo::Component::Genre::Allocatable) { + // Establish allocatable descriptors + for (; !Elementwise::IsComplete(); Elementwise::Advance()) { + Descriptor &allocDesc{*instance_.ElementComponent( + subscripts_, component_->offset())}; + component_->EstablishDescriptor( + allocDesc, instance_, workQueue.terminator()); + allocDesc.raw().attribute = CFI_attribute_allocatable; + } + SkipToNextComponent(); + } else if (const void *init{component_->initialization()}) { // Explicit initialization of data pointers and // non-allocatable non-automatic components - std::size_t bytes{comp.SizeInBytes(instance)}; - for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) { - char *ptr{instance.ElementComponent(at, comp.offset())}; + std::size_t bytes{component_->SizeInBytes(instance_)}; + for (; !Elementwise::IsComplete(); Elementwise::Advance()) { + char *ptr{instance_.ElementComponent( + subscripts_, component_->offset())}; std::memcpy(ptr, init, bytes); } - } else if (comp.genre() == typeInfo::Component::Genre::Pointer) { + SkipToNextComponent(); + } else if (component_->genre() == typeInfo::Component::Genre::Pointer) { // Data pointers without explicit initialization are established // so that they are valid right-hand side targets of pointer // assignment statements. - for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) { - Descriptor &ptrDesc{ - *instance.ElementComponent(at, comp.offset())}; - comp.EstablishDescriptor(ptrDesc, instance, terminator); + for (; !Elementwise::IsComplete(); Elementwise::Advance()) { + Descriptor &ptrDesc{*instance_.ElementComponent( + subscripts_, component_->offset())}; + component_->EstablishDescriptor( + ptrDesc, instance_, workQueue.terminator()); ptrDesc.raw().attribute = CFI_attribute_pointer; } - } else if (comp.genre() == typeInfo::Component::Genre::Data && - comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) { + SkipToNextComponent(); + } else if (component_->genre() == typeInfo::Component::Genre::Data && + component_->derivedType() && + !component_->derivedType()->noInitializationNeeded()) { // Default initialization of non-pointer non-allocatable/automatic - // data component. Handles parent component's elements. Recursive. + // data component. Handles parent component's elements. SubscriptValue extents[maxRank]; - GetComponentExtents(extents, comp, instance); - StaticDescriptor staticDescriptor; - Descriptor &compDesc{staticDescriptor.descriptor()}; - const typeInfo::DerivedType &compType{*comp.derivedType()}; - for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) { - compDesc.Establish(compType, - instance.ElementComponent(at, comp.offset()), comp.rank(), - extents); - stat = Initialize(compDesc, compType, terminator, hasStat, errMsg); - if (stat != StatOk) { - break; - } + GetComponentExtents(extents, *component_, instance_); + Descriptor &compDesc{componentDescriptor_.descriptor()}; + const typeInfo::DerivedType &compType{*component_->derivedType()}; + compDesc.Establish(compType, + instance_.ElementComponent(subscripts_, component_->offset()), + component_->rank(), extents); + Advance(); + if (int status{workQueue.BeginInitialize(compDesc, compType)}; + status != StatOk) { + return status; } + } else { + SkipToNextComponent(); } } - // Initialize procedure pointer components in each element - const Descriptor &procPtrDesc{derived.procPtr()}; - std::size_t myProcPtrs{procPtrDesc.Elements()}; - for (std::size_t k{0}; k < myProcPtrs; ++k) { - const auto &comp{ - *procPtrDesc.ZeroBasedIndexedElement(k)}; - SubscriptValue at[maxRank]; - instance.GetLowerBounds(at); - for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) { - auto &pptr{*instance.ElementComponent( - at, comp.offset)}; - pptr = comp.procInitialization; - } - } - return stat; + return StatOk; } RT_API_ATTRS int InitializeClone(const Descriptor &clone, - const Descriptor &orig, const typeInfo::DerivedType &derived, + const Descriptor &original, const typeInfo::DerivedType &derived, Terminator &terminator, bool hasStat, const Descriptor *errMsg) { - const Descriptor &componentDesc{derived.component()}; - std::size_t elements{orig.Elements()}; - int stat{StatOk}; - - // Skip pointers and unallocated variables. - if (orig.IsPointer() || !orig.IsAllocated()) { - return stat; + if (original.IsPointer() || !original.IsAllocated()) { + return StatOk; // nothing to do + } else { + WorkQueue workQueue{terminator}; + int status{workQueue.BeginInitializeClone( + clone, original, derived, hasStat, errMsg)}; + return status == StatContinue ? workQueue.Run() : status; } - // Initialize each data component. - std::size_t components{componentDesc.Elements()}; - for (std::size_t i{0}; i < components; ++i) { - const typeInfo::Component &comp{ - *componentDesc.ZeroBasedIndexedElement(i)}; - SubscriptValue at[maxRank]; - orig.GetLowerBounds(at); - // Allocate allocatable components that are also allocated in the original - // object. - if (comp.genre() == typeInfo::Component::Genre::Allocatable) { - // Initialize each element. - for (std::size_t j{0}; j < elements; ++j, orig.IncrementSubscripts(at)) { - Descriptor &origDesc{ - *orig.ElementComponent(at, comp.offset())}; - Descriptor &cloneDesc{ - *clone.ElementComponent(at, comp.offset())}; - if (origDesc.IsAllocated()) { +} + +RT_API_ATTRS int InitializeCloneTicket::Continue(WorkQueue &workQueue) { + while (!IsComplete()) { + if (component_->genre() == typeInfo::Component::Genre::Allocatable) { + Descriptor &origDesc{*instance_.ElementComponent( + subscripts_, component_->offset())}; + if (origDesc.IsAllocated()) { + Descriptor &cloneDesc{*clone_.ElementComponent( + subscripts_, component_->offset())}; + if (phase_ == 0) { + ++phase_; cloneDesc.ApplyMold(origDesc, origDesc.rank()); - stat = ReturnError( - terminator, cloneDesc.Allocate(kNoAsyncObject), errMsg, hasStat); - if (stat == StatOk) { - if (const DescriptorAddendum * addendum{cloneDesc.Addendum()}) { - if (const typeInfo::DerivedType * - derived{addendum->derivedType()}) { - if (!derived->noInitializationNeeded()) { - // Perform default initialization for the allocated element. - stat = Initialize( - cloneDesc, *derived, terminator, hasStat, errMsg); - } - // Initialize derived type's allocatables. - if (stat == StatOk) { - stat = InitializeClone(cloneDesc, origDesc, *derived, - terminator, hasStat, errMsg); + if (int stat{ReturnError(workQueue.terminator(), + cloneDesc.Allocate(kNoAsyncObject), errMsg_, hasStat_)}; + stat != StatOk) { + return stat; + } + if (const DescriptorAddendum *addendum{cloneDesc.Addendum()}) { + if (const typeInfo::DerivedType *derived{addendum->derivedType()}) { + if (!derived->noInitializationNeeded()) { + // Perform default initialization for the allocated element. + if (int status{workQueue.BeginInitialize(cloneDesc, *derived)}; + status != StatOk) { + return status; } } } } } - if (stat != StatOk) { - break; + if (phase_ == 1) { + ++phase_; + if (const DescriptorAddendum *addendum{cloneDesc.Addendum()}) { + if (const typeInfo::DerivedType *derived{addendum->derivedType()}) { + // Initialize derived type's allocatables. + if (int status{workQueue.BeginInitializeClone( + cloneDesc, origDesc, *derived, hasStat_, errMsg_)}; + status != StatOk) { + return status; + } + } + } } } - } else if (comp.genre() == typeInfo::Component::Genre::Data && - comp.derivedType()) { - // Handle nested derived types. - const typeInfo::DerivedType &compType{*comp.derivedType()}; - SubscriptValue extents[maxRank]; - GetComponentExtents(extents, comp, orig); - // Data components don't have descriptors, allocate them. - StaticDescriptor origStaticDesc; - StaticDescriptor cloneStaticDesc; - Descriptor &origDesc{origStaticDesc.descriptor()}; - Descriptor &cloneDesc{cloneStaticDesc.descriptor()}; - // Initialize each element. - for (std::size_t j{0}; j < elements; ++j, orig.IncrementSubscripts(at)) { + Advance(); + } else if (component_->genre() == typeInfo::Component::Genre::Data) { + if (component_->derivedType()) { + // Handle nested derived types. + const typeInfo::DerivedType &compType{*component_->derivedType()}; + SubscriptValue extents[maxRank]; + GetComponentExtents(extents, *component_, instance_); + Descriptor &origDesc{componentDescriptor_.descriptor()}; + Descriptor &cloneDesc{cloneComponentDescriptor_.descriptor()}; origDesc.Establish(compType, - orig.ElementComponent(at, comp.offset()), comp.rank(), - extents); + instance_.ElementComponent(subscripts_, component_->offset()), + component_->rank(), extents); cloneDesc.Establish(compType, - clone.ElementComponent(at, comp.offset()), comp.rank(), - extents); - stat = InitializeClone( - cloneDesc, origDesc, compType, terminator, hasStat, errMsg); - if (stat != StatOk) { - break; + clone_.ElementComponent(subscripts_, component_->offset()), + component_->rank(), extents); + Advance(); + if (int status{workQueue.BeginInitializeClone( + cloneDesc, origDesc, compType, hasStat_, errMsg_)}; + status != StatOk) { + return status; } + } else { + SkipToNextComponent(); } + } else { + SkipToNextComponent(); + } + } + return StatOk; +} + +// Fortran 2018 subclause 7.5.6.2 +RT_API_ATTRS void Finalize(const Descriptor &descriptor, + const typeInfo::DerivedType &derived, Terminator *terminator) { + if (!derived.noFinalizationNeeded() && descriptor.IsAllocated()) { + Terminator stubTerminator{"Finalize() in Fortran runtime", 0}; + WorkQueue workQueue{terminator ? *terminator : stubTerminator}; + if (workQueue.BeginFinalize(descriptor, derived) == StatContinue) { + workQueue.Run(); } } - return stat; } static RT_API_ATTRS const typeInfo::SpecialBinding *FindFinal( @@ -221,7 +234,7 @@ static RT_API_ATTRS const typeInfo::SpecialBinding *FindFinal( } static RT_API_ATTRS void CallFinalSubroutine(const Descriptor &descriptor, - const typeInfo::DerivedType &derived, Terminator *terminator) { + const typeInfo::DerivedType &derived, Terminator &terminator) { if (const auto *special{FindFinal(derived, descriptor.rank())}) { if (special->which() == typeInfo::SpecialBinding::Which::ElementalFinal) { std::size_t elements{descriptor.Elements()}; @@ -258,9 +271,7 @@ static RT_API_ATTRS void CallFinalSubroutine(const Descriptor &descriptor, copy = descriptor; copy.set_base_addr(nullptr); copy.raw().attribute = CFI_attribute_allocatable; - Terminator stubTerminator{"CallFinalProcedure() in Fortran runtime", 0}; - RUNTIME_CHECK(terminator ? *terminator : stubTerminator, - copy.Allocate(kNoAsyncObject) == CFI_SUCCESS); + RUNTIME_CHECK(terminator, copy.Allocate(kNoAsyncObject) == CFI_SUCCESS); ShallowCopyDiscontiguousToContiguous(copy, descriptor); argDescriptor = © } @@ -284,87 +295,94 @@ static RT_API_ATTRS void CallFinalSubroutine(const Descriptor &descriptor, } } -// Fortran 2018 subclause 7.5.6.2 -RT_API_ATTRS void Finalize(const Descriptor &descriptor, - const typeInfo::DerivedType &derived, Terminator *terminator) { - if (derived.noFinalizationNeeded() || !descriptor.IsAllocated()) { - return; - } - CallFinalSubroutine(descriptor, derived, terminator); - const auto *parentType{derived.GetParentType()}; - bool recurse{parentType && !parentType->noFinalizationNeeded()}; +RT_API_ATTRS int FinalizeTicket::Begin(WorkQueue &workQueue) { + CallFinalSubroutine(instance_, derived_, workQueue.terminator()); // If there's a finalizable parent component, handle it last, as required // by the Fortran standard (7.5.6.2), and do so recursively with the same // descriptor so that the rank is preserved. - const Descriptor &componentDesc{derived.component()}; - std::size_t myComponents{componentDesc.Elements()}; - std::size_t elements{descriptor.Elements()}; - for (auto k{recurse ? std::size_t{1} - /* skip first component, it's the parent */ - : 0}; - k < myComponents; ++k) { - const auto &comp{ - *componentDesc.ZeroBasedIndexedElement(k)}; - SubscriptValue at[maxRank]; - descriptor.GetLowerBounds(at); - if (comp.genre() == typeInfo::Component::Genre::Allocatable && - comp.category() == TypeCategory::Derived) { + finalizableParentType_ = derived_.GetParentType(); + if (finalizableParentType_) { + if (finalizableParentType_->noFinalizationNeeded()) { + finalizableParentType_ = nullptr; + } else { + SkipToNextComponent(); + } + } + return StatContinue; +} + +RT_API_ATTRS int FinalizeTicket::Continue(WorkQueue &workQueue) { + while (!IsComplete()) { + if (component_->genre() == typeInfo::Component::Genre::Allocatable && + component_->category() == TypeCategory::Derived) { // Component may be polymorphic or unlimited polymorphic. Need to use the // dynamic type to check whether finalization is needed. - for (std::size_t j{0}; j++ < elements; - descriptor.IncrementSubscripts(at)) { - const Descriptor &compDesc{ - *descriptor.ElementComponent(at, comp.offset())}; - if (compDesc.IsAllocated()) { - if (const DescriptorAddendum * addendum{compDesc.Addendum()}) { - if (const typeInfo::DerivedType * - compDynamicType{addendum->derivedType()}) { - if (!compDynamicType->noFinalizationNeeded()) { - Finalize(compDesc, *compDynamicType, terminator); + const Descriptor &compDesc{*instance_.ElementComponent( + subscripts_, component_->offset())}; + Advance(); + if (compDesc.IsAllocated()) { + if (const DescriptorAddendum *addendum{compDesc.Addendum()}) { + if (const typeInfo::DerivedType *compDynamicType{ + addendum->derivedType()}) { + if (!compDynamicType->noFinalizationNeeded()) { + if (int status{ + workQueue.BeginFinalize(compDesc, *compDynamicType)}; + status != StatOk) { + return status; } } } } } - } else if (comp.genre() == typeInfo::Component::Genre::Allocatable || - comp.genre() == typeInfo::Component::Genre::Automatic) { - if (const typeInfo::DerivedType * compType{comp.derivedType()}) { - if (!compType->noFinalizationNeeded()) { - for (std::size_t j{0}; j++ < elements; - descriptor.IncrementSubscripts(at)) { - const Descriptor &compDesc{ - *descriptor.ElementComponent(at, comp.offset())}; - if (compDesc.IsAllocated()) { - Finalize(compDesc, *compType, terminator); - } + } else if (component_->genre() == typeInfo::Component::Genre::Allocatable || + component_->genre() == typeInfo::Component::Genre::Automatic) { + if (const typeInfo::DerivedType *compType{component_->derivedType()}; + compType && !compType->noFinalizationNeeded()) { + const Descriptor &compDesc{*instance_.ElementComponent( + subscripts_, component_->offset())}; + Advance(); + if (compDesc.IsAllocated()) { + if (int status{workQueue.BeginFinalize(compDesc, *compType)}; + status != StatOk) { + return status; } } + } else { + SkipToNextComponent(); } - } else if (comp.genre() == typeInfo::Component::Genre::Data && - comp.derivedType() && !comp.derivedType()->noFinalizationNeeded()) { + } else if (component_->genre() == typeInfo::Component::Genre::Data && + component_->derivedType() && + !component_->derivedType()->noFinalizationNeeded()) { SubscriptValue extents[maxRank]; - GetComponentExtents(extents, comp, descriptor); - StaticDescriptor staticDescriptor; - Descriptor &compDesc{staticDescriptor.descriptor()}; - const typeInfo::DerivedType &compType{*comp.derivedType()}; - for (std::size_t j{0}; j++ < elements; - descriptor.IncrementSubscripts(at)) { - compDesc.Establish(compType, - descriptor.ElementComponent(at, comp.offset()), comp.rank(), - extents); - Finalize(compDesc, compType, terminator); + GetComponentExtents(extents, *component_, instance_); + Descriptor &compDesc{componentDescriptor_.descriptor()}; + const typeInfo::DerivedType &compType{*component_->derivedType()}; + compDesc.Establish(compType, + instance_.ElementComponent(subscripts_, component_->offset()), + component_->rank(), extents); + Advance(); + if (int status{workQueue.BeginFinalize(compDesc, compType)}; + status != StatOk) { + return status; } + } else { + SkipToNextComponent(); } } - if (recurse) { - StaticDescriptor statDesc; - Descriptor &tmpDesc{statDesc.descriptor()}; - tmpDesc = descriptor; + // Last, do the parent component, if any and finalizable. + if (finalizableParentType_) { + Descriptor &tmpDesc{componentDescriptor_.descriptor()}; + tmpDesc = instance_; tmpDesc.raw().attribute = CFI_attribute_pointer; - tmpDesc.Addendum()->set_derivedType(parentType); - tmpDesc.raw().elem_len = parentType->sizeInBytes(); - Finalize(tmpDesc, *parentType, terminator); + tmpDesc.Addendum()->set_derivedType(finalizableParentType_); + tmpDesc.raw().elem_len = finalizableParentType_->sizeInBytes(); + const auto &parentType{*finalizableParentType_}; + finalizableParentType_ = nullptr; + // Don't return StatOk here if the nested FInalize is still running; + // it needs this->componentDescriptor_. + return workQueue.BeginFinalize(tmpDesc, parentType); } + return StatOk; } // The order of finalization follows Fortran 2018 7.5.6.2, with @@ -373,53 +391,73 @@ RT_API_ATTRS void Finalize(const Descriptor &descriptor, // preceding any deallocation. RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize, const typeInfo::DerivedType &derived, Terminator *terminator) { - if (derived.noDestructionNeeded() || !descriptor.IsAllocated()) { - return; - } - if (finalize && !derived.noFinalizationNeeded()) { - Finalize(descriptor, derived, terminator); - } - // Deallocate all direct and indirect allocatable and automatic components. - // Contrary to finalization, the order of deallocation does not matter. - const Descriptor &componentDesc{derived.component()}; - std::size_t myComponents{componentDesc.Elements()}; - std::size_t elements{descriptor.Elements()}; - SubscriptValue at[maxRank]; - descriptor.GetLowerBounds(at); - for (std::size_t k{0}; k < myComponents; ++k) { - const auto &comp{ - *componentDesc.ZeroBasedIndexedElement(k)}; - const bool destroyComp{ - comp.derivedType() && !comp.derivedType()->noDestructionNeeded()}; - if (comp.genre() == typeInfo::Component::Genre::Allocatable || - comp.genre() == typeInfo::Component::Genre::Automatic) { - for (std::size_t j{0}; j < elements; ++j) { - Descriptor *d{ - descriptor.ElementComponent(at, comp.offset())}; - if (destroyComp) { - Destroy(*d, /*finalize=*/false, *comp.derivedType(), terminator); - } - d->Deallocate(); - descriptor.IncrementSubscripts(at); - } - } else if (destroyComp && - comp.genre() == typeInfo::Component::Genre::Data) { - SubscriptValue extents[maxRank]; - GetComponentExtents(extents, comp, descriptor); - StaticDescriptor staticDescriptor; - Descriptor &compDesc{staticDescriptor.descriptor()}; - const typeInfo::DerivedType &compType{*comp.derivedType()}; - for (std::size_t j{0}; j++ < elements; - descriptor.IncrementSubscripts(at)) { - compDesc.Establish(compType, - descriptor.ElementComponent(at, comp.offset()), comp.rank(), - extents); - Destroy(compDesc, /*finalize=*/false, *comp.derivedType(), terminator); - } + if (descriptor.IsAllocated() && !derived.noDestructionNeeded()) { + Terminator stubTerminator{"Destroy() in Fortran runtime", 0}; + WorkQueue workQueue{terminator ? *terminator : stubTerminator}; + if (workQueue.BeginDestroy(descriptor, derived, finalize) == StatContinue) { + workQueue.Run(); } } } +RT_API_ATTRS int DestroyTicket::Begin(WorkQueue &workQueue) { + if (finalize_ && !derived_.noFinalizationNeeded()) { + if (int status{workQueue.BeginFinalize(instance_, derived_)}; + status != StatOk && status != StatContinue) { + return status; + } + } + return StatContinue; +} + +RT_API_ATTRS int DestroyTicket::Continue(WorkQueue &workQueue) { + // Deallocate all direct and indirect allocatable and automatic components. + // Contrary to finalization, the order of deallocation does not matter. + while (!IsComplete()) { + const auto *componentDerived{component_->derivedType()}; + if (component_->genre() == typeInfo::Component::Genre::Allocatable || + component_->genre() == typeInfo::Component::Genre::Automatic) { + Descriptor *d{instance_.ElementComponent( + subscripts_, component_->offset())}; + if (d->IsAllocated()) { + if (phase_ == 0) { + ++phase_; + if (componentDerived && !componentDerived->noDestructionNeeded()) { + if (int status{workQueue.BeginDestroy( + *d, *componentDerived, /*finalize=*/false)}; + status != StatOk) { + return status; + } + } + } + d->Deallocate(); + } + Advance(); + } else if (component_->genre() == typeInfo::Component::Genre::Data) { + if (!componentDerived || componentDerived->noDestructionNeeded()) { + SkipToNextComponent(); + } else { + SubscriptValue extents[maxRank]; + GetComponentExtents(extents, *component_, instance_); + Descriptor &compDesc{componentDescriptor_.descriptor()}; + const typeInfo::DerivedType &compType{*componentDerived}; + compDesc.Establish(compType, + instance_.ElementComponent(subscripts_, component_->offset()), + component_->rank(), extents); + Advance(); + if (int status{workQueue.BeginDestroy( + compDesc, *componentDerived, /*finalize=*/false)}; + status != StatOk) { + return status; + } + } + } else { + SkipToNextComponent(); + } + } + return StatOk; +} + RT_API_ATTRS bool HasDynamicComponent(const Descriptor &descriptor) { if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { if (const auto *derived = addendum->derivedType()) { diff --git a/flang-rt/lib/runtime/descriptor-io.cpp b/flang-rt/lib/runtime/descriptor-io.cpp index 3db1455af52f..e7b99e6fc3a2 100644 --- a/flang-rt/lib/runtime/descriptor-io.cpp +++ b/flang-rt/lib/runtime/descriptor-io.cpp @@ -7,15 +7,44 @@ //===----------------------------------------------------------------------===// #include "descriptor-io.h" +#include "edit-input.h" +#include "edit-output.h" +#include "unit.h" +#include "flang-rt/runtime/descriptor.h" +#include "flang-rt/runtime/io-stmt.h" +#include "flang-rt/runtime/namelist.h" +#include "flang-rt/runtime/terminator.h" +#include "flang-rt/runtime/type-info.h" +#include "flang-rt/runtime/work-queue.h" +#include "flang/Common/optional.h" #include "flang/Common/restorer.h" +#include "flang/Common/uint128.h" +#include "flang/Runtime/cpp-type.h" #include "flang/Runtime/freestanding-tools.h" +// Implementation of I/O data list item transfers based on descriptors. +// (All I/O items come through here so that the code is exercised for test; +// some scalar I/O data transfer APIs could be changed to bypass their use +// of descriptors in the future for better efficiency.) + namespace Fortran::runtime::io::descr { RT_OFFLOAD_API_GROUP_BEGIN +template +inline RT_API_ATTRS A &ExtractElement(IoStatementState &io, + const Descriptor &descriptor, const SubscriptValue subscripts[]) { + A *p{descriptor.Element(subscripts)}; + if (!p) { + io.GetIoErrorHandler().Crash("Bad address for I/O item -- null base " + "address or subscripts out of range"); + } + return *p; +} + // Defined formatted I/O (maybe) -Fortran::common::optional DefinedFormattedIo(IoStatementState &io, - const Descriptor &descriptor, const typeInfo::DerivedType &derived, +static RT_API_ATTRS Fortran::common::optional DefinedFormattedIo( + IoStatementState &io, const Descriptor &descriptor, + const typeInfo::DerivedType &derived, const typeInfo::SpecialBinding &special, const SubscriptValue subscripts[]) { Fortran::common::optional peek{ @@ -65,10 +94,13 @@ Fortran::common::optional DefinedFormattedIo(IoStatementState &io, // I/O subroutine reads counts towards READ(SIZE=). startPos = io.InquirePos(); } + const auto *bindings{ + derived.binding().OffsetElement()}; if (special.IsArgDescriptor(0)) { // "dtv" argument is "class(t)", pass a descriptor auto *p{special.GetProc()}; + const Descriptor &, int &, char *, std::size_t, std::size_t)>( + bindings)}; StaticDescriptor<1, true, 10 /*?*/> elementStatDesc; Descriptor &elementDesc{elementStatDesc.descriptor()}; elementDesc.Establish( @@ -79,7 +111,8 @@ Fortran::common::optional DefinedFormattedIo(IoStatementState &io, } else { // "dtv" argument is "type(t)", pass a raw pointer auto *p{special.GetProc()}; + const Descriptor &, int &, char *, std::size_t, std::size_t)>( + bindings)}; p(descriptor.Element(subscripts), unit, ioType, vListDesc, ioStat, ioMsg, ioTypeLen, sizeof ioMsg); } @@ -104,8 +137,8 @@ Fortran::common::optional DefinedFormattedIo(IoStatementState &io, } // Defined unformatted I/O -bool DefinedUnformattedIo(IoStatementState &io, const Descriptor &descriptor, - const typeInfo::DerivedType &derived, +static RT_API_ATTRS bool DefinedUnformattedIo(IoStatementState &io, + const Descriptor &descriptor, const typeInfo::DerivedType &derived, const typeInfo::SpecialBinding &special) { // Unformatted I/O must have an external unit (or child thereof). IoErrorHandler &handler{io.GetIoErrorHandler()}; @@ -121,10 +154,12 @@ bool DefinedUnformattedIo(IoStatementState &io, const Descriptor &descriptor, std::size_t numElements{descriptor.Elements()}; SubscriptValue subscripts[maxRank]; descriptor.GetLowerBounds(subscripts); + const auto *bindings{ + derived.binding().OffsetElement()}; if (special.IsArgDescriptor(0)) { // "dtv" argument is "class(t)", pass a descriptor auto *p{special.GetProc()}; + const Descriptor &, int &, int &, char *, std::size_t)>(bindings)}; StaticDescriptor<1, true, 10 /*?*/> elementStatDesc; Descriptor &elementDesc{elementStatDesc.descriptor()}; elementDesc.Establish(derived, nullptr, 0, nullptr, CFI_attribute_pointer); @@ -137,8 +172,9 @@ bool DefinedUnformattedIo(IoStatementState &io, const Descriptor &descriptor, } } else { // "dtv" argument is "type(t)", pass a raw pointer - auto *p{special.GetProc()}; + auto *p{special + .GetProc( + bindings)}; for (; numElements-- > 0; descriptor.IncrementSubscripts(subscripts)) { p(descriptor.Element(subscripts), unit, ioStat, ioMsg, sizeof ioMsg); @@ -152,5 +188,619 @@ bool DefinedUnformattedIo(IoStatementState &io, const Descriptor &descriptor, return handler.GetIoStat() == IostatOk; } +// Per-category descriptor-based I/O templates + +// TODO (perhaps as a nontrivial but small starter project): implement +// automatic repetition counts, like "10*3.14159", for list-directed and +// NAMELIST array output. + +template +inline RT_API_ATTRS bool FormattedIntegerIO(IoStatementState &io, + const Descriptor &descriptor, [[maybe_unused]] bool isSigned) { + std::size_t numElements{descriptor.Elements()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + using IntType = CppTypeFor; + bool anyInput{false}; + for (std::size_t j{0}; j < numElements; ++j) { + if (auto edit{io.GetNextDataEdit()}) { + IntType &x{ExtractElement(io, descriptor, subscripts)}; + if constexpr (DIR == Direction::Output) { + if (!EditIntegerOutput(io, *edit, x, isSigned)) { + return false; + } + } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { + if (EditIntegerInput( + io, *edit, reinterpret_cast(&x), KIND, isSigned)) { + anyInput = true; + } else { + return anyInput && edit->IsNamelist(); + } + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedIntegerIO: subscripts out of bounds"); + } + } else { + return false; + } + } + return true; +} + +template +inline RT_API_ATTRS bool FormattedRealIO( + IoStatementState &io, const Descriptor &descriptor) { + std::size_t numElements{descriptor.Elements()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + using RawType = typename RealOutputEditing::BinaryFloatingPoint; + bool anyInput{false}; + for (std::size_t j{0}; j < numElements; ++j) { + if (auto edit{io.GetNextDataEdit()}) { + RawType &x{ExtractElement(io, descriptor, subscripts)}; + if constexpr (DIR == Direction::Output) { + if (!RealOutputEditing{io, x}.Edit(*edit)) { + return false; + } + } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { + if (EditRealInput(io, *edit, reinterpret_cast(&x))) { + anyInput = true; + } else { + return anyInput && edit->IsNamelist(); + } + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedRealIO: subscripts out of bounds"); + } + } else { + return false; + } + } + return true; +} + +template +inline RT_API_ATTRS bool FormattedComplexIO( + IoStatementState &io, const Descriptor &descriptor) { + std::size_t numElements{descriptor.Elements()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + bool isListOutput{ + io.get_if>() != nullptr}; + using RawType = typename RealOutputEditing::BinaryFloatingPoint; + bool anyInput{false}; + for (std::size_t j{0}; j < numElements; ++j) { + RawType *x{&ExtractElement(io, descriptor, subscripts)}; + if (isListOutput) { + DataEdit rEdit, iEdit; + rEdit.descriptor = DataEdit::ListDirectedRealPart; + iEdit.descriptor = DataEdit::ListDirectedImaginaryPart; + rEdit.modes = iEdit.modes = io.mutableModes(); + if (!RealOutputEditing{io, x[0]}.Edit(rEdit) || + !RealOutputEditing{io, x[1]}.Edit(iEdit)) { + return false; + } + } else { + for (int k{0}; k < 2; ++k, ++x) { + auto edit{io.GetNextDataEdit()}; + if (!edit) { + return false; + } else if constexpr (DIR == Direction::Output) { + if (!RealOutputEditing{io, *x}.Edit(*edit)) { + return false; + } + } else if (edit->descriptor == DataEdit::ListDirectedNullValue) { + break; + } else if (EditRealInput( + io, *edit, reinterpret_cast(x))) { + anyInput = true; + } else { + return anyInput && edit->IsNamelist(); + } + } + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedComplexIO: subscripts out of bounds"); + } + } + return true; +} + +template +inline RT_API_ATTRS bool FormattedCharacterIO( + IoStatementState &io, const Descriptor &descriptor) { + std::size_t numElements{descriptor.Elements()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + std::size_t length{descriptor.ElementBytes() / sizeof(A)}; + auto *listOutput{io.get_if>()}; + bool anyInput{false}; + for (std::size_t j{0}; j < numElements; ++j) { + A *x{&ExtractElement(io, descriptor, subscripts)}; + if (listOutput) { + if (!ListDirectedCharacterOutput(io, *listOutput, x, length)) { + return false; + } + } else if (auto edit{io.GetNextDataEdit()}) { + if constexpr (DIR == Direction::Output) { + if (!EditCharacterOutput(io, *edit, x, length)) { + return false; + } + } else { // input + if (edit->descriptor != DataEdit::ListDirectedNullValue) { + if (EditCharacterInput(io, *edit, x, length)) { + anyInput = true; + } else { + return anyInput && edit->IsNamelist(); + } + } + } + } else { + return false; + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedCharacterIO: subscripts out of bounds"); + } + } + return true; +} + +template +inline RT_API_ATTRS bool FormattedLogicalIO( + IoStatementState &io, const Descriptor &descriptor) { + std::size_t numElements{descriptor.Elements()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + auto *listOutput{io.get_if>()}; + using IntType = CppTypeFor; + bool anyInput{false}; + for (std::size_t j{0}; j < numElements; ++j) { + IntType &x{ExtractElement(io, descriptor, subscripts)}; + if (listOutput) { + if (!ListDirectedLogicalOutput(io, *listOutput, x != 0)) { + return false; + } + } else if (auto edit{io.GetNextDataEdit()}) { + if constexpr (DIR == Direction::Output) { + if (!EditLogicalOutput(io, *edit, x != 0)) { + return false; + } + } else { + if (edit->descriptor != DataEdit::ListDirectedNullValue) { + bool truth{}; + if (EditLogicalInput(io, *edit, truth)) { + x = truth; + anyInput = true; + } else { + return anyInput && edit->IsNamelist(); + } + } + } + } else { + return false; + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedLogicalIO: subscripts out of bounds"); + } + } + return true; +} + +template +RT_API_ATTRS int DerivedIoTicket::Continue(WorkQueue &workQueue) { + while (!IsComplete()) { + if (component_->genre() == typeInfo::Component::Genre::Data) { + // Create a descriptor for the component + Descriptor &compDesc{componentDescriptor_.descriptor()}; + component_->CreatePointerDescriptor( + compDesc, instance_, io_.GetIoErrorHandler(), subscripts_); + Advance(); + if (int status{workQueue.BeginDescriptorIo( + io_, compDesc, table_, anyIoTookPlace_)}; + status != StatOk) { + return status; + } + } else { + // Component is itself a descriptor + char *pointer{ + instance_.Element(subscripts_) + component_->offset()}; + const Descriptor &compDesc{ + *reinterpret_cast(pointer)}; + Advance(); + if (compDesc.IsAllocated()) { + if (int status{workQueue.BeginDescriptorIo( + io_, compDesc, table_, anyIoTookPlace_)}; + status != StatOk) { + return status; + } + } + } + } + return StatOk; +} + +template RT_API_ATTRS int DerivedIoTicket::Continue( + WorkQueue &); +template RT_API_ATTRS int DerivedIoTicket::Continue( + WorkQueue &); + +template +RT_API_ATTRS int DescriptorIoTicket::Begin(WorkQueue &workQueue) { + IoErrorHandler &handler{io_.GetIoErrorHandler()}; + if (handler.InError()) { + return handler.GetIoStat(); + } + if (!io_.get_if>()) { + handler.Crash("DescriptorIO() called for wrong I/O direction"); + return handler.GetIoStat(); + } + if constexpr (DIR == Direction::Input) { + if (!io_.BeginReadingRecord()) { + return StatOk; + } + } + if (!io_.get_if>()) { + // Unformatted I/O + IoErrorHandler &handler{io_.GetIoErrorHandler()}; + const DescriptorAddendum *addendum{instance_.Addendum()}; + if (const typeInfo::DerivedType *type{ + addendum ? addendum->derivedType() : nullptr}) { + // derived type unformatted I/O + if (table_) { + if (const auto *definedIo{table_->Find(*type, + DIR == Direction::Input + ? common::DefinedIo::ReadUnformatted + : common::DefinedIo::WriteUnformatted)}) { + if (definedIo->subroutine) { + typeInfo::SpecialBinding special{DIR == Direction::Input + ? typeInfo::SpecialBinding::Which::ReadUnformatted + : typeInfo::SpecialBinding::Which::WriteUnformatted, + definedIo->subroutine, definedIo->isDtvArgPolymorphic, false, + false}; + if (DefinedUnformattedIo(io_, instance_, *type, special)) { + anyIoTookPlace_ = true; + return StatOk; + } + } else { + int status{workQueue.BeginDerivedIo( + io_, instance_, *type, table_, anyIoTookPlace_)}; + return status == StatContinue ? StatOk : status; // done here + } + } + } + if (const typeInfo::SpecialBinding *special{ + type->FindSpecialBinding(DIR == Direction::Input + ? typeInfo::SpecialBinding::Which::ReadUnformatted + : typeInfo::SpecialBinding::Which::WriteUnformatted)}) { + if (!table_ || !table_->ignoreNonTbpEntries || special->IsTypeBound()) { + // defined derived type unformatted I/O + if (DefinedUnformattedIo(io_, instance_, *type, *special)) { + anyIoTookPlace_ = true; + return StatOk; + } else { + return IostatEnd; + } + } + } + // Default derived type unformatted I/O + // TODO: If no component at any level has defined READ or WRITE + // (as appropriate), the elements are contiguous, and no byte swapping + // is active, do a block transfer via the code below. + int status{workQueue.BeginDerivedIo( + io_, instance_, *type, table_, anyIoTookPlace_)}; + return status == StatContinue ? StatOk : status; // done here + } else { + // intrinsic type unformatted I/O + auto *externalUnf{io_.get_if>()}; + ChildUnformattedIoStatementState *childUnf{nullptr}; + InquireIOLengthState *inq{nullptr}; + bool swapEndianness{false}; + if (externalUnf) { + swapEndianness = externalUnf->unit().swapEndianness(); + } else { + childUnf = io_.get_if>(); + if (!childUnf) { + inq = DIR == Direction::Output ? io_.get_if() + : nullptr; + RUNTIME_CHECK(handler, inq != nullptr); + } + } + std::size_t elementBytes{instance_.ElementBytes()}; + std::size_t swappingBytes{elementBytes}; + if (auto maybeCatAndKind{instance_.type().GetCategoryAndKind()}) { + // Byte swapping units can be smaller than elements, namely + // for COMPLEX and CHARACTER. + if (maybeCatAndKind->first == TypeCategory::Character) { + // swap each character position independently + swappingBytes = maybeCatAndKind->second; // kind + } else if (maybeCatAndKind->first == TypeCategory::Complex) { + // swap real and imaginary components independently + swappingBytes /= 2; + } + } + using CharType = + std::conditional_t; + auto Transfer{[=](CharType &x, std::size_t totalBytes) -> bool { + if constexpr (DIR == Direction::Output) { + return externalUnf ? externalUnf->Emit(&x, totalBytes, swappingBytes) + : childUnf ? childUnf->Emit(&x, totalBytes, swappingBytes) + : inq->Emit(&x, totalBytes, swappingBytes); + } else { + return externalUnf + ? externalUnf->Receive(&x, totalBytes, swappingBytes) + : childUnf->Receive(&x, totalBytes, swappingBytes); + } + }}; + if (!swapEndianness && + instance_.IsContiguous()) { // contiguous unformatted I/O + char &x{ExtractElement(io_, instance_, subscripts_)}; + if (Transfer(x, elements_ * elementBytes)) { + anyIoTookPlace_ = true; + } else { + return IostatEnd; + } + } else { // non-contiguous or byte-swapped intrinsic type unformatted I/O + for (; !IsComplete(); Advance()) { + char &x{ExtractElement(io_, instance_, subscripts_)}; + if (Transfer(x, elementBytes)) { + anyIoTookPlace_ = true; + } else { + return IostatEnd; + } + } + } + } + // Unformatted I/O never needs to call Continue(). + return StatOk; + } + // Formatted I/O + if (auto catAndKind{instance_.type().GetCategoryAndKind()}) { + TypeCategory cat{catAndKind->first}; + int kind{catAndKind->second}; + bool any{false}; + switch (cat) { + case TypeCategory::Integer: + switch (kind) { + case 1: + any = FormattedIntegerIO<1, DIR>(io_, instance_, true); + break; + case 2: + any = FormattedIntegerIO<2, DIR>(io_, instance_, true); + break; + case 4: + any = FormattedIntegerIO<4, DIR>(io_, instance_, true); + break; + case 8: + any = FormattedIntegerIO<8, DIR>(io_, instance_, true); + break; + case 16: + any = FormattedIntegerIO<16, DIR>(io_, instance_, true); + break; + default: + handler.Crash( + "not yet implemented: INTEGER(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Unsigned: + switch (kind) { + case 1: + any = FormattedIntegerIO<1, DIR>(io_, instance_, false); + break; + case 2: + any = FormattedIntegerIO<2, DIR>(io_, instance_, false); + break; + case 4: + any = FormattedIntegerIO<4, DIR>(io_, instance_, false); + break; + case 8: + any = FormattedIntegerIO<8, DIR>(io_, instance_, false); + break; + case 16: + any = FormattedIntegerIO<16, DIR>(io_, instance_, false); + break; + default: + handler.Crash( + "not yet implemented: UNSIGNED(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Real: + switch (kind) { + case 2: + any = FormattedRealIO<2, DIR>(io_, instance_); + break; + case 3: + any = FormattedRealIO<3, DIR>(io_, instance_); + break; + case 4: + any = FormattedRealIO<4, DIR>(io_, instance_); + break; + case 8: + any = FormattedRealIO<8, DIR>(io_, instance_); + break; + case 10: + any = FormattedRealIO<10, DIR>(io_, instance_); + break; + // TODO: case double/double + case 16: + any = FormattedRealIO<16, DIR>(io_, instance_); + break; + default: + handler.Crash( + "not yet implemented: REAL(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Complex: + switch (kind) { + case 2: + any = FormattedComplexIO<2, DIR>(io_, instance_); + break; + case 3: + any = FormattedComplexIO<3, DIR>(io_, instance_); + break; + case 4: + any = FormattedComplexIO<4, DIR>(io_, instance_); + break; + case 8: + any = FormattedComplexIO<8, DIR>(io_, instance_); + break; + case 10: + any = FormattedComplexIO<10, DIR>(io_, instance_); + break; + // TODO: case double/double + case 16: + any = FormattedComplexIO<16, DIR>(io_, instance_); + break; + default: + handler.Crash( + "not yet implemented: COMPLEX(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Character: + switch (kind) { + case 1: + any = FormattedCharacterIO(io_, instance_); + break; + case 2: + any = FormattedCharacterIO(io_, instance_); + break; + case 4: + any = FormattedCharacterIO(io_, instance_); + break; + default: + handler.Crash( + "not yet implemented: CHARACTER(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Logical: + switch (kind) { + case 1: + any = FormattedLogicalIO<1, DIR>(io_, instance_); + break; + case 2: + any = FormattedLogicalIO<2, DIR>(io_, instance_); + break; + case 4: + any = FormattedLogicalIO<4, DIR>(io_, instance_); + break; + case 8: + any = FormattedLogicalIO<8, DIR>(io_, instance_); + break; + default: + handler.Crash( + "not yet implemented: LOGICAL(KIND=%d) in formatted IO", kind); + return IostatEnd; + } + break; + case TypeCategory::Derived: { + // Derived type information must be present for formatted I/O. + IoErrorHandler &handler{io_.GetIoErrorHandler()}; + const DescriptorAddendum *addendum{instance_.Addendum()}; + RUNTIME_CHECK(handler, addendum != nullptr); + derived_ = addendum->derivedType(); + RUNTIME_CHECK(handler, derived_ != nullptr); + if (table_) { + if (const auto *definedIo{table_->Find(*derived_, + DIR == Direction::Input ? common::DefinedIo::ReadFormatted + : common::DefinedIo::WriteFormatted)}) { + if (definedIo->subroutine) { + nonTbpSpecial_.emplace(DIR == Direction::Input + ? typeInfo::SpecialBinding::Which::ReadFormatted + : typeInfo::SpecialBinding::Which::WriteFormatted, + definedIo->subroutine, definedIo->isDtvArgPolymorphic, false, + false); + special_ = &*nonTbpSpecial_; + } + } + } + if (!special_) { + if (const typeInfo::SpecialBinding *binding{ + derived_->FindSpecialBinding(DIR == Direction::Input + ? typeInfo::SpecialBinding::Which::ReadFormatted + : typeInfo::SpecialBinding::Which::WriteFormatted)}) { + if (!table_ || !table_->ignoreNonTbpEntries || + binding->IsTypeBound()) { + special_ = binding; + } + } + } + return StatContinue; + } + } + if (any) { + anyIoTookPlace_ = true; + } else { + return IostatEnd; + } + } else { + handler.Crash("DescriptorIO: bad type code (%d) in descriptor", + static_cast(instance_.type().raw())); + return handler.GetIoStat(); + } + return StatOk; +} + +template RT_API_ATTRS int DescriptorIoTicket::Begin( + WorkQueue &); +template RT_API_ATTRS int DescriptorIoTicket::Begin( + WorkQueue &); + +template +RT_API_ATTRS int DescriptorIoTicket::Continue(WorkQueue &workQueue) { + // Only derived type formatted I/O gets here. + while (!IsComplete()) { + if (special_) { + if (auto defined{DefinedFormattedIo( + io_, instance_, *derived_, *special_, subscripts_)}) { + anyIoTookPlace_ |= *defined; + Advance(); + continue; + } + } + Descriptor &elementDesc{elementDescriptor_.descriptor()}; + elementDesc.Establish( + *derived_, nullptr, 0, nullptr, CFI_attribute_pointer); + elementDesc.set_base_addr(instance_.Element(subscripts_)); + Advance(); + if (int status{workQueue.BeginDerivedIo( + io_, elementDesc, *derived_, table_, anyIoTookPlace_)}; + status != StatOk) { + return status; + } + } + return StatOk; +} + +template RT_API_ATTRS int DescriptorIoTicket::Continue( + WorkQueue &); +template RT_API_ATTRS int DescriptorIoTicket::Continue( + WorkQueue &); + +template +RT_API_ATTRS bool DescriptorIO(IoStatementState &io, + const Descriptor &descriptor, const NonTbpDefinedIoTable *table) { + bool anyIoTookPlace{false}; + WorkQueue workQueue{io.GetIoErrorHandler()}; + if (workQueue.BeginDescriptorIo(io, descriptor, table, anyIoTookPlace) == + StatContinue) { + workQueue.Run(); + } + return anyIoTookPlace; +} + +template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); +template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); + RT_OFFLOAD_API_GROUP_END } // namespace Fortran::runtime::io::descr diff --git a/flang-rt/lib/runtime/descriptor-io.h b/flang-rt/lib/runtime/descriptor-io.h index eb60f106c920..88ad59bd24b5 100644 --- a/flang-rt/lib/runtime/descriptor-io.h +++ b/flang-rt/lib/runtime/descriptor-io.h @@ -9,619 +9,27 @@ #ifndef FLANG_RT_RUNTIME_DESCRIPTOR_IO_H_ #define FLANG_RT_RUNTIME_DESCRIPTOR_IO_H_ -// Implementation of I/O data list item transfers based on descriptors. -// (All I/O items come through here so that the code is exercised for test; -// some scalar I/O data transfer APIs could be changed to bypass their use -// of descriptors in the future for better efficiency.) +#include "flang-rt/runtime/connection.h" -#include "edit-input.h" -#include "edit-output.h" -#include "unit.h" -#include "flang-rt/runtime/descriptor.h" -#include "flang-rt/runtime/io-stmt.h" -#include "flang-rt/runtime/namelist.h" -#include "flang-rt/runtime/terminator.h" -#include "flang-rt/runtime/type-info.h" -#include "flang/Common/optional.h" -#include "flang/Common/uint128.h" -#include "flang/Runtime/cpp-type.h" +namespace Fortran::runtime { +class Descriptor; +} // namespace Fortran::runtime + +namespace Fortran::runtime::io { +class IoStatementState; +struct NonTbpDefinedIoTable; +} // namespace Fortran::runtime::io namespace Fortran::runtime::io::descr { -template -inline RT_API_ATTRS A &ExtractElement(IoStatementState &io, - const Descriptor &descriptor, const SubscriptValue subscripts[]) { - A *p{descriptor.Element(subscripts)}; - if (!p) { - io.GetIoErrorHandler().Crash("Bad address for I/O item -- null base " - "address or subscripts out of range"); - } - return *p; -} - -// Per-category descriptor-based I/O templates - -// TODO (perhaps as a nontrivial but small starter project): implement -// automatic repetition counts, like "10*3.14159", for list-directed and -// NAMELIST array output. - -template -inline RT_API_ATTRS bool FormattedIntegerIO(IoStatementState &io, - const Descriptor &descriptor, [[maybe_unused]] bool isSigned) { - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - using IntType = CppTypeFor; - bool anyInput{false}; - for (std::size_t j{0}; j < numElements; ++j) { - if (auto edit{io.GetNextDataEdit()}) { - IntType &x{ExtractElement(io, descriptor, subscripts)}; - if constexpr (DIR == Direction::Output) { - if (!EditIntegerOutput(io, *edit, x, isSigned)) { - return false; - } - } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { - if (EditIntegerInput( - io, *edit, reinterpret_cast(&x), KIND, isSigned)) { - anyInput = true; - } else { - return anyInput && edit->IsNamelist(); - } - } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedIntegerIO: subscripts out of bounds"); - } - } else { - return false; - } - } - return true; -} - -template -inline RT_API_ATTRS bool FormattedRealIO( - IoStatementState &io, const Descriptor &descriptor) { - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - using RawType = typename RealOutputEditing::BinaryFloatingPoint; - bool anyInput{false}; - for (std::size_t j{0}; j < numElements; ++j) { - if (auto edit{io.GetNextDataEdit()}) { - RawType &x{ExtractElement(io, descriptor, subscripts)}; - if constexpr (DIR == Direction::Output) { - if (!RealOutputEditing{io, x}.Edit(*edit)) { - return false; - } - } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { - if (EditRealInput(io, *edit, reinterpret_cast(&x))) { - anyInput = true; - } else { - return anyInput && edit->IsNamelist(); - } - } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedRealIO: subscripts out of bounds"); - } - } else { - return false; - } - } - return true; -} - -template -inline RT_API_ATTRS bool FormattedComplexIO( - IoStatementState &io, const Descriptor &descriptor) { - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - bool isListOutput{ - io.get_if>() != nullptr}; - using RawType = typename RealOutputEditing::BinaryFloatingPoint; - bool anyInput{false}; - for (std::size_t j{0}; j < numElements; ++j) { - RawType *x{&ExtractElement(io, descriptor, subscripts)}; - if (isListOutput) { - DataEdit rEdit, iEdit; - rEdit.descriptor = DataEdit::ListDirectedRealPart; - iEdit.descriptor = DataEdit::ListDirectedImaginaryPart; - rEdit.modes = iEdit.modes = io.mutableModes(); - if (!RealOutputEditing{io, x[0]}.Edit(rEdit) || - !RealOutputEditing{io, x[1]}.Edit(iEdit)) { - return false; - } - } else { - for (int k{0}; k < 2; ++k, ++x) { - auto edit{io.GetNextDataEdit()}; - if (!edit) { - return false; - } else if constexpr (DIR == Direction::Output) { - if (!RealOutputEditing{io, *x}.Edit(*edit)) { - return false; - } - } else if (edit->descriptor == DataEdit::ListDirectedNullValue) { - break; - } else if (EditRealInput( - io, *edit, reinterpret_cast(x))) { - anyInput = true; - } else { - return anyInput && edit->IsNamelist(); - } - } - } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedComplexIO: subscripts out of bounds"); - } - } - return true; -} - -template -inline RT_API_ATTRS bool FormattedCharacterIO( - IoStatementState &io, const Descriptor &descriptor) { - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - std::size_t length{descriptor.ElementBytes() / sizeof(A)}; - auto *listOutput{io.get_if>()}; - bool anyInput{false}; - for (std::size_t j{0}; j < numElements; ++j) { - A *x{&ExtractElement(io, descriptor, subscripts)}; - if (listOutput) { - if (!ListDirectedCharacterOutput(io, *listOutput, x, length)) { - return false; - } - } else if (auto edit{io.GetNextDataEdit()}) { - if constexpr (DIR == Direction::Output) { - if (!EditCharacterOutput(io, *edit, x, length)) { - return false; - } - } else { // input - if (edit->descriptor != DataEdit::ListDirectedNullValue) { - if (EditCharacterInput(io, *edit, x, length)) { - anyInput = true; - } else { - return anyInput && edit->IsNamelist(); - } - } - } - } else { - return false; - } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedCharacterIO: subscripts out of bounds"); - } - } - return true; -} - -template -inline RT_API_ATTRS bool FormattedLogicalIO( - IoStatementState &io, const Descriptor &descriptor) { - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - auto *listOutput{io.get_if>()}; - using IntType = CppTypeFor; - bool anyInput{false}; - for (std::size_t j{0}; j < numElements; ++j) { - IntType &x{ExtractElement(io, descriptor, subscripts)}; - if (listOutput) { - if (!ListDirectedLogicalOutput(io, *listOutput, x != 0)) { - return false; - } - } else if (auto edit{io.GetNextDataEdit()}) { - if constexpr (DIR == Direction::Output) { - if (!EditLogicalOutput(io, *edit, x != 0)) { - return false; - } - } else { - if (edit->descriptor != DataEdit::ListDirectedNullValue) { - bool truth{}; - if (EditLogicalInput(io, *edit, truth)) { - x = truth; - anyInput = true; - } else { - return anyInput && edit->IsNamelist(); - } - } - } - } else { - return false; - } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedLogicalIO: subscripts out of bounds"); - } - } - return true; -} template -static RT_API_ATTRS bool DescriptorIO(IoStatementState &, const Descriptor &, +RT_API_ATTRS bool DescriptorIO(IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable * = nullptr); -// For intrinsic (not defined) derived type I/O, formatted & unformatted -template -static RT_API_ATTRS bool DefaultComponentIO(IoStatementState &io, - const typeInfo::Component &component, const Descriptor &origDescriptor, - const SubscriptValue origSubscripts[], Terminator &terminator, - const NonTbpDefinedIoTable *table) { -#if !defined(RT_DEVICE_AVOID_RECURSION) - if (component.genre() == typeInfo::Component::Genre::Data) { - // Create a descriptor for the component - StaticDescriptor statDesc; - Descriptor &desc{statDesc.descriptor()}; - component.CreatePointerDescriptor( - desc, origDescriptor, terminator, origSubscripts); - return DescriptorIO(io, desc, table); - } else { - // Component is itself a descriptor - char *pointer{ - origDescriptor.Element(origSubscripts) + component.offset()}; - const Descriptor &compDesc{*reinterpret_cast(pointer)}; - return compDesc.IsAllocated() && DescriptorIO(io, compDesc, table); - } -#else - terminator.Crash("not yet implemented: component IO"); -#endif -} +extern template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); +extern template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); -template -static RT_API_ATTRS bool DefaultComponentwiseFormattedIO(IoStatementState &io, - const Descriptor &descriptor, const typeInfo::DerivedType &type, - const NonTbpDefinedIoTable *table, const SubscriptValue subscripts[]) { - IoErrorHandler &handler{io.GetIoErrorHandler()}; - const Descriptor &compArray{type.component()}; - RUNTIME_CHECK(handler, compArray.rank() == 1); - std::size_t numComponents{compArray.Elements()}; - SubscriptValue at[maxRank]; - compArray.GetLowerBounds(at); - for (std::size_t k{0}; k < numComponents; - ++k, compArray.IncrementSubscripts(at)) { - const typeInfo::Component &component{ - *compArray.Element(at)}; - if (!DefaultComponentIO( - io, component, descriptor, subscripts, handler, table)) { - // Return true for NAMELIST input if any component appeared. - auto *listInput{ - io.get_if>()}; - return DIR == Direction::Input && k > 0 && listInput && - listInput->inNamelistSequence(); - } - } - return true; -} - -template -static RT_API_ATTRS bool DefaultComponentwiseUnformattedIO(IoStatementState &io, - const Descriptor &descriptor, const typeInfo::DerivedType &type, - const NonTbpDefinedIoTable *table) { - IoErrorHandler &handler{io.GetIoErrorHandler()}; - const Descriptor &compArray{type.component()}; - RUNTIME_CHECK(handler, compArray.rank() == 1); - std::size_t numComponents{compArray.Elements()}; - std::size_t numElements{descriptor.Elements()}; - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - for (std::size_t j{0}; j < numElements; - ++j, descriptor.IncrementSubscripts(subscripts)) { - SubscriptValue at[maxRank]; - compArray.GetLowerBounds(at); - for (std::size_t k{0}; k < numComponents; - ++k, compArray.IncrementSubscripts(at)) { - const typeInfo::Component &component{ - *compArray.Element(at)}; - if (!DefaultComponentIO( - io, component, descriptor, subscripts, handler, table)) { - return false; - } - } - } - return true; -} - -RT_API_ATTRS Fortran::common::optional DefinedFormattedIo( - IoStatementState &, const Descriptor &, const typeInfo::DerivedType &, - const typeInfo::SpecialBinding &, const SubscriptValue[]); - -template -static RT_API_ATTRS bool FormattedDerivedTypeIO(IoStatementState &io, - const Descriptor &descriptor, const NonTbpDefinedIoTable *table) { - IoErrorHandler &handler{io.GetIoErrorHandler()}; - // Derived type information must be present for formatted I/O. - const DescriptorAddendum *addendum{descriptor.Addendum()}; - RUNTIME_CHECK(handler, addendum != nullptr); - const typeInfo::DerivedType *type{addendum->derivedType()}; - RUNTIME_CHECK(handler, type != nullptr); - Fortran::common::optional nonTbpSpecial; - const typeInfo::SpecialBinding *special{nullptr}; - if (table) { - if (const auto *definedIo{table->Find(*type, - DIR == Direction::Input ? common::DefinedIo::ReadFormatted - : common::DefinedIo::WriteFormatted)}) { - if (definedIo->subroutine) { - nonTbpSpecial.emplace(DIR == Direction::Input - ? typeInfo::SpecialBinding::Which::ReadFormatted - : typeInfo::SpecialBinding::Which::WriteFormatted, - definedIo->subroutine, definedIo->isDtvArgPolymorphic, false, - false); - special = &*nonTbpSpecial; - } - } - } - if (!special) { - if (const typeInfo::SpecialBinding * - binding{type->FindSpecialBinding(DIR == Direction::Input - ? typeInfo::SpecialBinding::Which::ReadFormatted - : typeInfo::SpecialBinding::Which::WriteFormatted)}) { - if (!table || !table->ignoreNonTbpEntries || binding->isTypeBound()) { - special = binding; - } - } - } - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - std::size_t numElements{descriptor.Elements()}; - for (std::size_t j{0}; j < numElements; - ++j, descriptor.IncrementSubscripts(subscripts)) { - Fortran::common::optional result; - if (special) { - result = DefinedFormattedIo(io, descriptor, *type, *special, subscripts); - } - if (!result) { - result = DefaultComponentwiseFormattedIO( - io, descriptor, *type, table, subscripts); - } - if (!result.value()) { - // Return true for NAMELIST input if we got anything. - auto *listInput{ - io.get_if>()}; - return DIR == Direction::Input && j > 0 && listInput && - listInput->inNamelistSequence(); - } - } - return true; -} - -RT_API_ATTRS bool DefinedUnformattedIo(IoStatementState &, const Descriptor &, - const typeInfo::DerivedType &, const typeInfo::SpecialBinding &); - -// Unformatted I/O -template -static RT_API_ATTRS bool UnformattedDescriptorIO(IoStatementState &io, - const Descriptor &descriptor, const NonTbpDefinedIoTable *table = nullptr) { - IoErrorHandler &handler{io.GetIoErrorHandler()}; - const DescriptorAddendum *addendum{descriptor.Addendum()}; - if (const typeInfo::DerivedType * - type{addendum ? addendum->derivedType() : nullptr}) { - // derived type unformatted I/O - if (table) { - if (const auto *definedIo{table->Find(*type, - DIR == Direction::Input ? common::DefinedIo::ReadUnformatted - : common::DefinedIo::WriteUnformatted)}) { - if (definedIo->subroutine) { - typeInfo::SpecialBinding special{DIR == Direction::Input - ? typeInfo::SpecialBinding::Which::ReadUnformatted - : typeInfo::SpecialBinding::Which::WriteUnformatted, - definedIo->subroutine, definedIo->isDtvArgPolymorphic, false, - false}; - if (Fortran::common::optional wasDefined{ - DefinedUnformattedIo(io, descriptor, *type, special)}) { - return *wasDefined; - } - } else { - return DefaultComponentwiseUnformattedIO( - io, descriptor, *type, table); - } - } - } - if (const typeInfo::SpecialBinding * - special{type->FindSpecialBinding(DIR == Direction::Input - ? typeInfo::SpecialBinding::Which::ReadUnformatted - : typeInfo::SpecialBinding::Which::WriteUnformatted)}) { - if (!table || !table->ignoreNonTbpEntries || special->isTypeBound()) { - // defined derived type unformatted I/O - return DefinedUnformattedIo(io, descriptor, *type, *special); - } - } - // Default derived type unformatted I/O - // TODO: If no component at any level has defined READ or WRITE - // (as appropriate), the elements are contiguous, and no byte swapping - // is active, do a block transfer via the code below. - return DefaultComponentwiseUnformattedIO(io, descriptor, *type, table); - } else { - // intrinsic type unformatted I/O - auto *externalUnf{io.get_if>()}; - auto *childUnf{io.get_if>()}; - auto *inq{ - DIR == Direction::Output ? io.get_if() : nullptr}; - RUNTIME_CHECK(handler, externalUnf || childUnf || inq); - std::size_t elementBytes{descriptor.ElementBytes()}; - std::size_t numElements{descriptor.Elements()}; - std::size_t swappingBytes{elementBytes}; - if (auto maybeCatAndKind{descriptor.type().GetCategoryAndKind()}) { - // Byte swapping units can be smaller than elements, namely - // for COMPLEX and CHARACTER. - if (maybeCatAndKind->first == TypeCategory::Character) { - // swap each character position independently - swappingBytes = maybeCatAndKind->second; // kind - } else if (maybeCatAndKind->first == TypeCategory::Complex) { - // swap real and imaginary components independently - swappingBytes /= 2; - } - } - SubscriptValue subscripts[maxRank]; - descriptor.GetLowerBounds(subscripts); - using CharType = - std::conditional_t; - auto Transfer{[=](CharType &x, std::size_t totalBytes) -> bool { - if constexpr (DIR == Direction::Output) { - return externalUnf ? externalUnf->Emit(&x, totalBytes, swappingBytes) - : childUnf ? childUnf->Emit(&x, totalBytes, swappingBytes) - : inq->Emit(&x, totalBytes, swappingBytes); - } else { - return externalUnf ? externalUnf->Receive(&x, totalBytes, swappingBytes) - : childUnf->Receive(&x, totalBytes, swappingBytes); - } - }}; - bool swapEndianness{externalUnf && externalUnf->unit().swapEndianness()}; - if (!swapEndianness && - descriptor.IsContiguous()) { // contiguous unformatted I/O - char &x{ExtractElement(io, descriptor, subscripts)}; - return Transfer(x, numElements * elementBytes); - } else { // non-contiguous or byte-swapped intrinsic type unformatted I/O - for (std::size_t j{0}; j < numElements; ++j) { - char &x{ExtractElement(io, descriptor, subscripts)}; - if (!Transfer(x, elementBytes)) { - return false; - } - if (!descriptor.IncrementSubscripts(subscripts) && - j + 1 < numElements) { - handler.Crash("DescriptorIO: subscripts out of bounds"); - } - } - return true; - } - } -} - -template -static RT_API_ATTRS bool DescriptorIO(IoStatementState &io, - const Descriptor &descriptor, const NonTbpDefinedIoTable *table) { - IoErrorHandler &handler{io.GetIoErrorHandler()}; - if (handler.InError()) { - return false; - } - if (!io.get_if>()) { - handler.Crash("DescriptorIO() called for wrong I/O direction"); - return false; - } - if constexpr (DIR == Direction::Input) { - if (!io.BeginReadingRecord()) { - return false; - } - } - if (!io.get_if>()) { - return UnformattedDescriptorIO(io, descriptor, table); - } - if (auto catAndKind{descriptor.type().GetCategoryAndKind()}) { - TypeCategory cat{catAndKind->first}; - int kind{catAndKind->second}; - switch (cat) { - case TypeCategory::Integer: - switch (kind) { - case 1: - return FormattedIntegerIO<1, DIR>(io, descriptor, true); - case 2: - return FormattedIntegerIO<2, DIR>(io, descriptor, true); - case 4: - return FormattedIntegerIO<4, DIR>(io, descriptor, true); - case 8: - return FormattedIntegerIO<8, DIR>(io, descriptor, true); - case 16: - return FormattedIntegerIO<16, DIR>(io, descriptor, true); - default: - handler.Crash( - "not yet implemented: INTEGER(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Unsigned: - switch (kind) { - case 1: - return FormattedIntegerIO<1, DIR>(io, descriptor, false); - case 2: - return FormattedIntegerIO<2, DIR>(io, descriptor, false); - case 4: - return FormattedIntegerIO<4, DIR>(io, descriptor, false); - case 8: - return FormattedIntegerIO<8, DIR>(io, descriptor, false); - case 16: - return FormattedIntegerIO<16, DIR>(io, descriptor, false); - default: - handler.Crash( - "not yet implemented: UNSIGNED(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Real: - switch (kind) { - case 2: - return FormattedRealIO<2, DIR>(io, descriptor); - case 3: - return FormattedRealIO<3, DIR>(io, descriptor); - case 4: - return FormattedRealIO<4, DIR>(io, descriptor); - case 8: - return FormattedRealIO<8, DIR>(io, descriptor); - case 10: - return FormattedRealIO<10, DIR>(io, descriptor); - // TODO: case double/double - case 16: - return FormattedRealIO<16, DIR>(io, descriptor); - default: - handler.Crash( - "not yet implemented: REAL(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Complex: - switch (kind) { - case 2: - return FormattedComplexIO<2, DIR>(io, descriptor); - case 3: - return FormattedComplexIO<3, DIR>(io, descriptor); - case 4: - return FormattedComplexIO<4, DIR>(io, descriptor); - case 8: - return FormattedComplexIO<8, DIR>(io, descriptor); - case 10: - return FormattedComplexIO<10, DIR>(io, descriptor); - // TODO: case double/double - case 16: - return FormattedComplexIO<16, DIR>(io, descriptor); - default: - handler.Crash( - "not yet implemented: COMPLEX(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Character: - switch (kind) { - case 1: - return FormattedCharacterIO(io, descriptor); - case 2: - return FormattedCharacterIO(io, descriptor); - case 4: - return FormattedCharacterIO(io, descriptor); - default: - handler.Crash( - "not yet implemented: CHARACTER(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Logical: - switch (kind) { - case 1: - return FormattedLogicalIO<1, DIR>(io, descriptor); - case 2: - return FormattedLogicalIO<2, DIR>(io, descriptor); - case 4: - return FormattedLogicalIO<4, DIR>(io, descriptor); - case 8: - return FormattedLogicalIO<8, DIR>(io, descriptor); - default: - handler.Crash( - "not yet implemented: LOGICAL(KIND=%d) in formatted IO", kind); - return false; - } - case TypeCategory::Derived: - return FormattedDerivedTypeIO(io, descriptor, table); - } - } - handler.Crash("DescriptorIO: bad type code (%d) in descriptor", - static_cast(descriptor.type().raw())); - return false; -} } // namespace Fortran::runtime::io::descr #endif // FLANG_RT_RUNTIME_DESCRIPTOR_IO_H_ diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp index 1d5304254ed0..0f0564403c0e 100644 --- a/flang-rt/lib/runtime/environment.cpp +++ b/flang-rt/lib/runtime/environment.cpp @@ -143,6 +143,10 @@ void ExecutionEnvironment::Configure(int ac, const char *av[], } } + if (auto *x{std::getenv("FLANG_RT_DEBUG")}) { + internalDebugging = std::strtol(x, nullptr, 10); + } + if (auto *x{std::getenv("ACC_OFFLOAD_STACK_SIZE")}) { char *end; auto n{std::strtoul(x, &end, 10)}; diff --git a/flang-rt/lib/runtime/namelist.cpp b/flang-rt/lib/runtime/namelist.cpp index b0cf2180fc6d..1bef387a9771 100644 --- a/flang-rt/lib/runtime/namelist.cpp +++ b/flang-rt/lib/runtime/namelist.cpp @@ -10,6 +10,7 @@ #include "descriptor-io.h" #include "flang-rt/runtime/emit-encoded.h" #include "flang-rt/runtime/io-stmt.h" +#include "flang-rt/runtime/type-info.h" #include "flang/Runtime/io-api.h" #include #include diff --git a/flang-rt/lib/runtime/tools.cpp b/flang-rt/lib/runtime/tools.cpp index b08195cd31e0..24d05f369fcb 100644 --- a/flang-rt/lib/runtime/tools.cpp +++ b/flang-rt/lib/runtime/tools.cpp @@ -205,7 +205,7 @@ RT_API_ATTRS void ShallowCopyInner(const Descriptor &to, const Descriptor &from, // Doing the recursion upwards instead of downwards puts the more common // cases earlier in the if-chain and has a tangible impact on performance. template struct ShallowCopyRankSpecialize { - static bool execute(const Descriptor &to, const Descriptor &from, + static RT_API_ATTRS bool execute(const Descriptor &to, const Descriptor &from, bool toIsContiguous, bool fromIsContiguous) { if (to.rank() == RANK && from.rank() == RANK) { ShallowCopyInner(to, from, toIsContiguous, fromIsContiguous); @@ -217,7 +217,7 @@ template struct ShallowCopyRankSpecialize { }; template struct ShallowCopyRankSpecialize { - static bool execute(const Descriptor &to, const Descriptor &from, + static RT_API_ATTRS bool execute(const Descriptor &to, const Descriptor &from, bool toIsContiguous, bool fromIsContiguous) { return false; } diff --git a/flang-rt/lib/runtime/type-info.cpp b/flang-rt/lib/runtime/type-info.cpp index 82182696d70c..d023c3392d55 100644 --- a/flang-rt/lib/runtime/type-info.cpp +++ b/flang-rt/lib/runtime/type-info.cpp @@ -140,11 +140,11 @@ RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor, const SubscriptValue *subscripts) const { RUNTIME_CHECK(terminator, genre_ == Genre::Data); EstablishDescriptor(descriptor, container, terminator); + std::size_t offset{offset_}; if (subscripts) { - descriptor.set_base_addr(container.Element(subscripts) + offset_); - } else { - descriptor.set_base_addr(container.OffsetElement() + offset_); + offset += container.SubscriptsToByteOffset(subscripts); } + descriptor.set_base_addr(container.OffsetElement() + offset); descriptor.raw().attribute = CFI_attribute_pointer; } @@ -279,6 +279,10 @@ FILE *Component::Dump(FILE *f) const { } std::fprintf(f, " category %d kind %d rank %d offset 0x%zx\n", category_, kind_, rank_, static_cast(offset_)); + const auto &dtDesc{derivedType_.descriptor()}; + if (dtDesc.raw().base_addr) { + std::fprintf(f, " derivedType_ %p\n", dtDesc.raw().base_addr); + } if (initialization_) { std::fprintf(f, " initialization @ %p:\n", reinterpret_cast(initialization_)); @@ -325,7 +329,7 @@ FILE *SpecialBinding::Dump(FILE *f) const { break; } std::fprintf(f, " isArgDescriptorSet: 0x%x\n", isArgDescriptorSet_); - std::fprintf(f, " isTypeBound: 0x%x\n", isTypeBound_); + std::fprintf(f, " isTypeBound: %d\n", isTypeBound_); std::fprintf(f, " isArgContiguousSet: 0x%x\n", isArgContiguousSet_); std::fprintf(f, " proc: %p\n", reinterpret_cast(proc_)); return f; diff --git a/flang-rt/lib/runtime/work-queue.cpp b/flang-rt/lib/runtime/work-queue.cpp new file mode 100644 index 000000000000..a508ecb63710 --- /dev/null +++ b/flang-rt/lib/runtime/work-queue.cpp @@ -0,0 +1,161 @@ +//===-- lib/runtime/work-queue.cpp ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang-rt/runtime/work-queue.h" +#include "flang-rt/runtime/environment.h" +#include "flang-rt/runtime/memory.h" +#include "flang-rt/runtime/type-info.h" +#include "flang/Common/visit.h" + +namespace Fortran::runtime { + +#if !defined(RT_DEVICE_COMPILATION) +// FLANG_RT_DEBUG code is disabled when false. +static constexpr bool enableDebugOutput{false}; +#endif + +RT_OFFLOAD_API_GROUP_BEGIN + +RT_API_ATTRS Componentwise::Componentwise(const typeInfo::DerivedType &derived) + : derived_{derived}, components_{derived_.component().Elements()} { + GetComponent(); +} + +RT_API_ATTRS void Componentwise::GetComponent() { + if (IsComplete()) { + component_ = nullptr; + } else { + const Descriptor &componentDesc{derived_.component()}; + component_ = componentDesc.ZeroBasedIndexedElement( + componentAt_); + } +} + +RT_API_ATTRS int Ticket::Continue(WorkQueue &workQueue) { + if (!begun) { + begun = true; + return common::visit( + [&workQueue]( + auto &specificTicket) { return specificTicket.Begin(workQueue); }, + u); + } else { + return common::visit( + [&workQueue](auto &specificTicket) { + return specificTicket.Continue(workQueue); + }, + u); + } +} + +RT_API_ATTRS WorkQueue::~WorkQueue() { + if (last_) { + if ((last_->next = firstFree_)) { + last_->next->previous = last_; + } + firstFree_ = first_; + first_ = last_ = nullptr; + } + while (firstFree_) { + TicketList *next{firstFree_->next}; + if (!firstFree_->isStatic) { + FreeMemory(firstFree_); + } + firstFree_ = next; + } +} + +RT_API_ATTRS Ticket &WorkQueue::StartTicket() { + if (!firstFree_) { + void *p{AllocateMemoryOrCrash(terminator_, sizeof(TicketList))}; + firstFree_ = new (p) TicketList; + firstFree_->isStatic = false; + } + TicketList *newTicket{firstFree_}; + if ((firstFree_ = newTicket->next)) { + firstFree_->previous = nullptr; + } + TicketList *after{insertAfter_ ? insertAfter_->next : nullptr}; + if ((newTicket->previous = insertAfter_ ? insertAfter_ : last_)) { + newTicket->previous->next = newTicket; + } else { + first_ = newTicket; + } + if ((newTicket->next = after)) { + after->previous = newTicket; + } else { + last_ = newTicket; + } + newTicket->ticket.begun = false; +#if !defined(RT_DEVICE_COMPILATION) + if (enableDebugOutput && + (executionEnvironment.internalDebugging & + ExecutionEnvironment::WorkQueue)) { + std::fprintf(stderr, "WQ: new ticket\n"); + } +#endif + return newTicket->ticket; +} + +RT_API_ATTRS int WorkQueue::Run() { + while (last_) { + TicketList *at{last_}; + insertAfter_ = last_; +#if !defined(RT_DEVICE_COMPILATION) + if (enableDebugOutput && + (executionEnvironment.internalDebugging & + ExecutionEnvironment::WorkQueue)) { + std::fprintf(stderr, "WQ: %zd %s\n", at->ticket.u.index(), + at->ticket.begun ? "Continue" : "Begin"); + } +#endif + int stat{at->ticket.Continue(*this)}; +#if !defined(RT_DEVICE_COMPILATION) + if (enableDebugOutput && + (executionEnvironment.internalDebugging & + ExecutionEnvironment::WorkQueue)) { + std::fprintf(stderr, "WQ: ... stat %d\n", stat); + } +#endif + insertAfter_ = nullptr; + if (stat == StatOk) { + if (at->previous) { + at->previous->next = at->next; + } else { + first_ = at->next; + } + if (at->next) { + at->next->previous = at->previous; + } else { + last_ = at->previous; + } + if ((at->next = firstFree_)) { + at->next->previous = at; + } + at->previous = nullptr; + firstFree_ = at; + } else if (stat != StatContinue) { + Stop(); + return stat; + } + } + return StatOk; +} + +RT_API_ATTRS void WorkQueue::Stop() { + if (last_) { + if ((last_->next = firstFree_)) { + last_->next->previous = last_; + } + firstFree_ = first_; + first_ = last_ = nullptr; + } +} + +RT_OFFLOAD_API_GROUP_END + +} // namespace Fortran::runtime diff --git a/flang-rt/unittests/Runtime/ExternalIOTest.cpp b/flang-rt/unittests/Runtime/ExternalIOTest.cpp index 3833e48be3dd..6c148b1de6f8 100644 --- a/flang-rt/unittests/Runtime/ExternalIOTest.cpp +++ b/flang-rt/unittests/Runtime/ExternalIOTest.cpp @@ -184,7 +184,7 @@ TEST(ExternalIOTests, TestSequentialFixedUnformatted) { io = IONAME(BeginInquireIoLength)(__FILE__, __LINE__); for (int j{1}; j <= 3; ++j) { ASSERT_TRUE(IONAME(OutputDescriptor)(io, desc)) - << "OutputDescriptor() for InquireIoLength"; + << "OutputDescriptor() for InquireIoLength " << j; } ASSERT_EQ(IONAME(GetIoLength)(io), 3 * recl) << "GetIoLength"; ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index 56a96f590f0a..068d134671db 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -421,7 +421,7 @@ endif() if (LLVM_COMPILER_IS_GCC_COMPATIBLE) if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing -fno-semantic-interposition") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-semantic-interposition") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-command-line-argument -Wstring-conversion \ -Wcovered-switch-default") diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 78d871c593e1..871749934810 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -858,6 +858,16 @@ print *, [(j,j=1,10)] warning since such values may have become defined by the time the nested expression's value is required. +* Intrinsic assignment of arrays is defined elementally, and intrinsic + assignment of derived type components is defined componentwise. + However, when intrinsic assignment takes place for an array of derived + type, the order of the loop nesting is not defined. + Some compilers will loop over the elements, assigning all of the components + of each element before proceeding to the next element. + This compiler loops over all of the components, and assigns all of + the elements for each component before proceeding to the next component. + A program using defined assignment might be able to detect the difference. + ## De Facto Standard Features * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 4dce1257a650..e04621f71f9a 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -490,26 +490,30 @@ template std::optional ExtractCoarrayRef(const A &x) { } } -struct ExtractSubstringHelper { - template static std::optional visit(T &&) { +template struct ExtractFromExprDesignatorHelper { + template static std::optional visit(T &&) { return std::nullopt; } - static std::optional visit(const Substring &e) { return e; } + static std::optional visit(const TARGET &t) { return t; } template - static std::optional visit(const Designator &e) { + static std::optional visit(const Designator &e) { return common::visit([](auto &&s) { return visit(s); }, e.u); } - template - static std::optional visit(const Expr &e) { + template static std::optional visit(const Expr &e) { return common::visit([](auto &&s) { return visit(s); }, e.u); } }; template std::optional ExtractSubstring(const A &x) { - return ExtractSubstringHelper::visit(x); + return ExtractFromExprDesignatorHelper::visit(x); +} + +template +std::optional ExtractComplexPart(const A &x) { + return ExtractFromExprDesignatorHelper::visit(x); } // If an expression is simply a whole symbol data designator, @@ -1385,6 +1389,154 @@ inline bool HasCUDAImplicitTransfer(const Expr &expr) { return (hasConstant || (hostSymbols > 0)) && deviceSymbols > 0; } +// Checks whether the symbol on the LHS is present in the RHS expression. +bool CheckForSymbolMatch(const Expr *lhs, const Expr *rhs); + +namespace operation { + +enum class Operator { + Unknown, + Add, + And, + Associated, + Call, + Constant, + Convert, + Div, + Eq, + Eqv, + False, + Ge, + Gt, + Identity, + Intrinsic, + Le, + Lt, + Max, + Min, + Mul, + Ne, + Neqv, + Not, + Or, + Pow, + Resize, // Convert within the same TypeCategory + Sub, + True, +}; + +std::string ToString(Operator op); + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + switch (op.derived().logicalOperator) { + case common::LogicalOperator::And: + return Operator::And; + case common::LogicalOperator::Or: + return Operator::Or; + case common::LogicalOperator::Eqv: + return Operator::Eqv; + case common::LogicalOperator::Neqv: + return Operator::Neqv; + case common::LogicalOperator::Not: + return Operator::Not; + } + return Operator::Unknown; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + switch (op.derived().opr) { + case common::RelationalOperator::LT: + return Operator::Lt; + case common::RelationalOperator::LE: + return Operator::Le; + case common::RelationalOperator::EQ: + return Operator::Eq; + case common::RelationalOperator::NE: + return Operator::Ne; + case common::RelationalOperator::GE: + return Operator::Ge; + case common::RelationalOperator::GT: + return Operator::Gt; + } + return Operator::Unknown; +} + +template +Operator OperationCode(const evaluate::Operation, Ts...> &op) { + return Operator::Add; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + return Operator::Sub; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + return Operator::Mul; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + return Operator::Div; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + return Operator::Pow; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + return Operator::Pow; +} + +template +Operator OperationCode( + const evaluate::Operation, Ts...> &op) { + if constexpr (C == T::category) { + return Operator::Resize; + } else { + return Operator::Convert; + } +} + +template Operator OperationCode(const evaluate::Constant &x) { + return Operator::Constant; +} + +template Operator OperationCode(const T &) { + return Operator::Unknown; +} + +Operator OperationCode(const evaluate::ProcedureDesignator &proc); + +} // namespace operation + +// Return information about the top-level operation (ignoring parentheses): +// the operation code and the list of arguments. +std::pair>> +GetTopLevelOperation(const Expr &expr); + +// Check if expr is same as x, or a sequence of Convert operations on x. +bool IsSameOrConvertOf(const Expr &expr, const Expr &x); + +// Strip away any top-level Convert operations (if any exist) and return +// the input value. A ComplexConstructor(x, 0) is also considered as a +// convert operation. +// If the input is not Operation, Designator, FunctionRef or Constant, +// it returns std::nullopt. +std::optional> GetConvertInput(const Expr &x); + } // namespace Fortran::evaluate namespace Fortran::semantics { diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index a69787283656..ae12aec51810 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -24,8 +24,15 @@ CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new ///< pass manager. + +/// Choose profile instrumenation kind or no instrumentation. +ENUM_CODEGENOPT(ProfileInstr, llvm::driver::ProfileInstrKind, 2, llvm::driver::ProfileInstrKind::ProfileNone) +/// Choose profile kind for PGO use compilation. +ENUM_CODEGENOPT(ProfileUse, llvm::driver::ProfileInstrKind, 2, llvm::driver::ProfileInstrKind::ProfileNone) + CODEGENOPT(InstrumentFunctions, 1, 0) ///< Set when -finstrument_functions is ///< enabled on the compile step. + CODEGENOPT(IsPIE, 1, 0) ///< PIE level is the same as PIC Level. CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. CODEGENOPT(PrepareForFullLTO , 1, 0) ///< Set when -flto is enabled on the diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h index e939f10f3c3e..bad17c8309eb 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -154,6 +154,44 @@ public: /// OpenMP is enabled. using DoConcurrentMappingKind = flangomp::DoConcurrentMappingKind; + /// Name of the profile file to use as output for -fprofile-instr-generate, + /// -fprofile-generate, and -fcs-profile-generate. + std::string InstrProfileOutput; + + /// Name of the profile file to use as input for -fmemory-profile-use. + std::string MemoryProfileUsePath; + + /// Name of the profile file to use as input for -fprofile-instr-use + std::string ProfileInstrumentUsePath; + + /// Name of the profile remapping file to apply to the profile data supplied + /// by -fprofile-sample-use or -fprofile-instr-use. + std::string ProfileRemappingFile; + + /// Check if Clang profile instrumenation is on. + bool hasProfileClangInstr() const { + return getProfileInstr() == llvm::driver::ProfileClangInstr; + } + + /// Check if IR level profile instrumentation is on. + bool hasProfileIRInstr() const { + return getProfileInstr() == llvm::driver::ProfileIRInstr; + } + + /// Check if CS IR level profile instrumentation is on. + bool hasProfileCSIRInstr() const { + return getProfileInstr() == llvm::driver::ProfileCSIRInstr; + } + /// Check if IR level profile use is on. + bool hasProfileIRUse() const { + return getProfileUse() == llvm::driver::ProfileIRInstr || + getProfileUse() == llvm::driver::ProfileCSIRInstr; + } + /// Check if CSIR profile use is on. + bool hasProfileCSIRUse() const { + return getProfileUse() == llvm::driver::ProfileCSIRInstr; + } + // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) #define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def index b062ea1a805a..d97abf4d864b 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -63,5 +63,8 @@ ENUM_LOWERINGOPT(StackRepackArrays, unsigned, 1, 0) /// in the leading dimension. ENUM_LOWERINGOPT(RepackArraysWhole, unsigned, 1, 0) +/// If true, CUDA Fortran runtime check is inserted. +ENUM_LOWERINGOPT(CUDARuntimeCheck, unsigned, 1, 0) + #undef LOWERINGOPT #undef ENUM_LOWERINGOPT diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h index 42d6546b7755..ac87fcd7c3b9 100644 --- a/flang/include/flang/Lower/PFTBuilder.h +++ b/flang/include/flang/Lower/PFTBuilder.h @@ -184,6 +184,11 @@ static constexpr bool isExecutableDirective{common::HasMember< A, std::tuple>}; +template +static constexpr bool isOpenMPDirective{ + common::HasMember>}; + template static constexpr bool isFunctionLike{common::HasMember< A, std::tuple>; }}); } + constexpr bool isOpenMPDirective() const { + return visit(common::visitors{[](auto &r) { + return pft::isOpenMPDirective>; + }}); + } /// Return the predicate: "This is a non-initial, non-terminal construct /// statement." For an IfConstruct, this is ElseIfStmt and ElseStmt. diff --git a/flang/include/flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h b/flang/include/flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h index 14d262bf22a7..bdeb7574012c 100644 --- a/flang/include/flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h @@ -26,6 +26,11 @@ namespace fir::runtime::cuda { void genSyncGlobalDescriptor(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value hostPtr); +/// Generate runtime call to check the section of a descriptor and raise an +/// error if it is not contiguous. +void genDescriptorCheckSection(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value desc); + } // namespace fir::runtime::cuda #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_CUDA_DESCRIPTOR_H_ diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 90e05ce3d5ca..8ac847dd7dd0 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -2323,9 +2323,13 @@ def fir_DoLoopOp : region_Op<"do_loop", [AttrSizedOperandSegments, }]; } -def fir_IfOp : region_Op<"if", [DeclareOpInterfaceMethods, RecursiveMemoryEffects, - NoRegionArguments]> { +def fir_IfOp + : region_Op< + "if", [DeclareOpInterfaceMethods< + RegionBranchOpInterface, ["getRegionInvocationBounds", + "getEntrySuccessorRegions"]>, + RecursiveMemoryEffects, NoRegionArguments, + WeightedRegionBranchOpInterface]> { let summary = "if-then-else conditional operation"; let description = [{ Used to conditionally execute operations. This operation is the FIR @@ -2342,7 +2346,8 @@ def fir_IfOp : region_Op<"if", [DeclareOpInterfaceMethods:$region_weights); let results = (outs Variadic:$results); let regions = (region @@ -2371,6 +2376,21 @@ def fir_IfOp : region_Op<"if", [DeclareOpInterfaceMethods &results, unsigned resultNum); + + /// Returns the display name string for the region_weights attribute. + static constexpr llvm::StringRef getWeightsAttrAssemblyName() { + return "weights"; + } + + /// Sets WeightedRegionBranchOpInterface weights to indicate + /// that either THEN or ELSE branch is unlikely. + /// By default, THEN branch is set to be unlikely. + void setUnlikelyIfWeights(bool unlikelyElse = false) { + if (unlikelyElse) + setWeights({1, 0}); + else + setWeights({0, 1}); + } }]; } diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index c6a5150a85a4..e3eed6aed807 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -565,6 +565,7 @@ public: NODE_ENUM(OmpDependenceType, Value) NODE(parser, OmpTaskDependenceType) NODE_ENUM(OmpTaskDependenceType, Value) + NODE(parser, OmpIndirectClause) NODE(parser, OmpIterationOffset) NODE(parser, OmpIteration) NODE(parser, OmpIterationVector) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 67405f88e09f..61f97b855b0e 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4300,6 +4300,12 @@ struct OmpHoldsClause { WRAPPER_CLASS_BOILERPLATE(OmpHoldsClause, common::Indirection); }; +// Ref: [5.2: 209] +struct OmpIndirectClause { + WRAPPER_CLASS_BOILERPLATE( + OmpIndirectClause, std::optional); +}; + // Ref: [5.2:72-73], in 4.5-5.1 it's scattered over individual directives // that allow the IF clause. // diff --git a/flang/include/flang/Runtime/CUDA/descriptor.h b/flang/include/flang/Runtime/CUDA/descriptor.h index 0ee7feca10e4..06e4a4649db1 100644 --- a/flang/include/flang/Runtime/CUDA/descriptor.h +++ b/flang/include/flang/Runtime/CUDA/descriptor.h @@ -37,6 +37,10 @@ void RTDECL(CUFDescriptorSync)(Descriptor *dst, const Descriptor *src, void RTDECL(CUFSyncGlobalDescriptor)( void *hostPtr, const char *sourceFile = nullptr, int sourceLine = 0); +/// Check descriptor passed to a kernel. +void RTDECL(CUFDescriptorCheckSection)( + const Descriptor *, const char *sourceFile = nullptr, int sourceLine = 0); + } // extern "C" } // namespace Fortran::runtime::cuda diff --git a/flang/include/flang/Runtime/assign.h b/flang/include/flang/Runtime/assign.h index bc80997a1bec..7d198bdcc9e8 100644 --- a/flang/include/flang/Runtime/assign.h +++ b/flang/include/flang/Runtime/assign.h @@ -38,7 +38,8 @@ enum AssignFlags { ComponentCanBeDefinedAssignment = 1 << 3, ExplicitLengthCharacterLHS = 1 << 4, PolymorphicLHS = 1 << 5, - DeallocateLHS = 1 << 6 + DeallocateLHS = 1 << 6, + UpdateLHSBounds = 1 << 7, }; #ifdef RT_DEVICE_COMPILATION diff --git a/flang/include/flang/Semantics/dump-expr.h b/flang/include/flang/Semantics/dump-expr.h index 2f445429a10b..9cc52b4da487 100644 --- a/flang/include/flang/Semantics/dump-expr.h +++ b/flang/include/flang/Semantics/dump-expr.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -38,6 +39,43 @@ public: } private: + template struct TypeOf { + static constexpr std::string_view get() { +#if defined(__GNUC__) +#define DUMP_EXPR_SHOW_TYPE + std::string_view v(__PRETTY_FUNCTION__); + // Extract the "xyz" from the "pretty function" string: + // "... [with T = xyz; std::string_view = ...]" + std::string_view front("with T = "); + std::string_view back("; std::string_view ="); + +#elif defined(_MSC_VER) +#define DUMP_EXPR_SHOW_TYPE + std::string_view v(__FUNCSIG__); + // Extract the "xyz" from the "pretty function" string: + // "...TypeOf::get(void)" + std::string_view front("TypeOf<"); + std::string_view back(">::get(void)"); + +#endif + +#if defined(DUMP_EXPR_SHOW_TYPE) +#undef DUMP_EXPR_SHOW_TYPE + if (auto fpos{v.find(front)}; fpos != v.npos) { + v.remove_prefix(fpos + front.size()); + if (auto bpos{v.find(back)}; bpos != v.npos) { + v.remove_suffix(v.size() - bpos); + return v; + } + } +#endif + + return ""; + } + + static constexpr std::string_view name{TypeOf::get()}; + }; + template void Show(const common::Indirection &x) { Show(x.value()); } @@ -76,7 +114,7 @@ private: void Show(const evaluate::NullPointer &); template void Show(const evaluate::Constant &x) { if constexpr (T::category == common::TypeCategory::Derived) { - Indent("derived constant"); + Indent("derived constant "s + std::string(TypeOf::name)); for (const auto &map : x.values()) { for (const auto &pair : map) { Show(pair.second.value()); @@ -84,7 +122,7 @@ private: } Outdent(); } else { - Print("constant"); + Print("constant "s + std::string(TypeOf::name)); } } void Show(const Symbol &symbol); @@ -102,7 +140,7 @@ private: void Show(const evaluate::Substring &x); void Show(const evaluate::ComplexPart &x); template void Show(const evaluate::Designator &x) { - Indent("designator"); + Indent("designator "s + std::string(TypeOf::name)); Show(x.u); Outdent(); } @@ -117,7 +155,7 @@ private: Outdent(); } template void Show(const evaluate::FunctionRef &x) { - Indent("function ref"); + Indent("function ref "s + std::string(TypeOf::name)); Show(x.proc()); Show(x.arguments()); Outdent(); @@ -127,14 +165,14 @@ private: } template void Show(const evaluate::ArrayConstructorValues &x) { - Indent("array constructor value"); + Indent("array constructor value "s + std::string(TypeOf::name)); for (auto &v : x) { Show(v); } Outdent(); } template void Show(const evaluate::ImpliedDo &x) { - Indent("implied do"); + Indent("implied do "s + std::string(TypeOf::name)); Show(x.lower()); Show(x.upper()); Show(x.stride()); @@ -148,20 +186,20 @@ private: void Show(const evaluate::StructureConstructor &x); template void Show(const evaluate::Operation &op) { - Indent("unary op"); + Indent("unary op "s + std::string(TypeOf::name)); Show(op.left()); Outdent(); } template void Show(const evaluate::Operation &op) { - Indent("binary op"); + Indent("binary op "s + std::string(TypeOf::name)); Show(op.left()); Show(op.right()); Outdent(); } void Show(const evaluate::Relational &x); template void Show(const evaluate::Expr &x) { - Indent("expr T"); + Indent("expr <" + std::string(TypeOf::name) + ">"); Show(x.u); Outdent(); } diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h index b13370512e5c..f3cfa9b99fb4 100644 --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -182,9 +182,12 @@ const Symbol *HasImpureFinal( const Symbol &, std::optional rank = std::nullopt); // Is this type finalizable or does it contain any polymorphic allocatable // ultimate components? -bool MayRequireFinalization(const DerivedTypeSpec &derived); +bool MayRequireFinalization(const DerivedTypeSpec &); // Does this type have an allocatable direct component? -bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived); +bool HasAllocatableDirectComponent(const DerivedTypeSpec &); +// Does this type have any defined assignment at any level (or any polymorphic +// allocatable)? +bool MayHaveDefinedAssignment(const DerivedTypeSpec &); bool IsInBlankCommon(const Symbol &); bool IsAssumedLengthCharacter(const Symbol &); @@ -753,154 +756,5 @@ std::string GetCommonBlockObjectName(const Symbol &, bool underscoring); // Check for ambiguous USE associations bool HadUseError(SemanticsContext &, SourceName at, const Symbol *); -// Checks whether the symbol on the LHS is present in the RHS expression. -bool CheckForSymbolMatch(const SomeExpr *lhs, const SomeExpr *rhs); - -namespace operation { - -enum class Operator { - Unknown, - Add, - And, - Associated, - Call, - Constant, - Convert, - Div, - Eq, - Eqv, - False, - Ge, - Gt, - Identity, - Intrinsic, - Le, - Lt, - Max, - Min, - Mul, - Ne, - Neqv, - Not, - Or, - Pow, - Resize, // Convert within the same TypeCategory - Sub, - True, -}; - -std::string ToString(Operator op); - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - switch (op.derived().logicalOperator) { - case common::LogicalOperator::And: - return Operator::And; - case common::LogicalOperator::Or: - return Operator::Or; - case common::LogicalOperator::Eqv: - return Operator::Eqv; - case common::LogicalOperator::Neqv: - return Operator::Neqv; - case common::LogicalOperator::Not: - return Operator::Not; - } - return Operator::Unknown; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - switch (op.derived().opr) { - case common::RelationalOperator::LT: - return Operator::Lt; - case common::RelationalOperator::LE: - return Operator::Le; - case common::RelationalOperator::EQ: - return Operator::Eq; - case common::RelationalOperator::NE: - return Operator::Ne; - case common::RelationalOperator::GE: - return Operator::Ge; - case common::RelationalOperator::GT: - return Operator::Gt; - } - return Operator::Unknown; -} - -template -Operator OperationCode(const evaluate::Operation, Ts...> &op) { - return Operator::Add; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - return Operator::Sub; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - return Operator::Mul; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - return Operator::Div; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - return Operator::Pow; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - return Operator::Pow; -} - -template -Operator OperationCode( - const evaluate::Operation, Ts...> &op) { - if constexpr (C == T::category) { - return Operator::Resize; - } else { - return Operator::Convert; - } -} - -template // -Operator OperationCode(const evaluate::Constant &x) { - return Operator::Constant; -} - -template // -Operator OperationCode(const T &) { - return Operator::Unknown; -} - -Operator OperationCode(const evaluate::ProcedureDesignator &proc); - -} // namespace operation - -/// Return information about the top-level operation (ignoring parentheses): -/// the operation code and the list of arguments. -std::pair> GetTopLevelOperation( - const SomeExpr &expr); - -/// Check if expr is same as x, or a sequence of Convert operations on x. -bool IsSameOrConvertOf(const SomeExpr &expr, const SomeExpr &x); - -/// Strip away any top-level Convert operations (if any exist) and return -/// the input value. A ComplexConstructor(x, 0) is also considered as a -/// convert operation. -/// If the input is not Operation, Designator, FunctionRef or Constant, -/// it returns std::nullopt. -MaybeExpr GetConvertInput(const SomeExpr &x); } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_TOOLS_H_ diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h index ea0845b7d605..39356daa3606 100644 --- a/flang/include/flang/Support/Fortran-features.h +++ b/flang/include/flang/Support/Fortran-features.h @@ -81,6 +81,9 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, using LanguageFeatures = EnumSet; using UsageWarnings = EnumSet; +using LanguageFeatureOrWarning = std::variant; +using LanguageControlFlag = + std::pair; class LanguageFeatureControl { public: @@ -94,6 +97,13 @@ public: void EnableWarning(UsageWarning w, bool yes = true) { warnUsage_.set(w, yes); } + void EnableWarning(LanguageFeatureOrWarning flag, bool yes = true) { + if (std::holds_alternative(flag)) { + EnableWarning(std::get(flag), yes); + } else { + EnableWarning(std::get(flag), yes); + } + } void WarnOnAllNonstandard(bool yes = true); bool IsWarnOnAllNonstandard() const { return warnAllLanguage_; } void WarnOnAllUsage(bool yes = true); @@ -116,9 +126,11 @@ public: bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); } bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(w); } // Cli options + // Find a warning by its Cli spelling, i.e. '[no-]warning-name'. + std::optional FindWarning(std::string_view input); // Take a string from the Cli and apply it to the LanguageFeatureControl. // Return true if the option was recognized (and hence applied). - bool ApplyCliOption(std::string input); + bool EnableWarning(std::string_view input); // The add and replace functions are not currently used but are provided // to allow a flexible many-to-one mapping from Cli spellings to enum values. // Taking a string by value because the functions own this string after the diff --git a/flang/include/flang/Support/OpenMP-features.h b/flang/include/flang/Support/OpenMP-features.h index 1dd7ea560cc9..349cd19c1224 100644 --- a/flang/include/flang/Support/OpenMP-features.h +++ b/flang/include/flang/Support/OpenMP-features.h @@ -42,6 +42,9 @@ void setOpenMPMacro(int version, FortranPredefinitions &predefinitions) { case 52: predefinitions.emplace_back("_OPENMP", "202111"); break; + case 60: + predefinitions.emplace_back("_OPENMP", "202411"); + break; case 11: default: predefinitions.emplace_back("_OPENMP", "199911"); diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp index 222c32a9c332..68838564f87b 100644 --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -13,6 +13,7 @@ #include "flang/Evaluate/traverse.h" #include "flang/Parser/message.h" #include "flang/Semantics/tools.h" +#include "llvm/ADT/StringSwitch.h" #include #include @@ -1595,6 +1596,316 @@ bool CheckForCoindexedObject(parser::ContextualMessages &messages, } } +bool CheckForSymbolMatch(const Expr *lhs, const Expr *rhs) { + if (lhs && rhs) { + if (SymbolVector lhsSymbols{GetSymbolVector(*lhs)}; !lhsSymbols.empty()) { + const Symbol &first{*lhsSymbols.front()}; + for (const Symbol &symbol : GetSymbolVector(*rhs)) { + if (first == symbol) { + return true; + } + } + } + } + return false; +} + +namespace operation { +template Expr AsSomeExpr(const T &x) { + return AsGenericExpr(common::Clone(x)); +} + +template +struct ArgumentExtractor + : public Traverse, + std::pair>>, false> { + using Arguments = std::vector>; + using Result = std::pair; + using Base = + Traverse, Result, false>; + static constexpr auto IgnoreResizes{IgnoreResizingConverts}; + static constexpr auto Logical{common::TypeCategory::Logical}; + ArgumentExtractor() : Base(*this) {} + + Result Default() const { return {}; } + + using Base::operator(); + + template + Result operator()(const Constant> &x) const { + if (const auto &val{x.GetScalarValue()}) { + return val->IsTrue() + ? std::make_pair(operation::Operator::True, Arguments{}) + : std::make_pair(operation::Operator::False, Arguments{}); + } + return Default(); + } + + template Result operator()(const FunctionRef &x) const { + Result result{operation::OperationCode(x.proc()), {}}; + for (size_t i{0}, e{x.arguments().size()}; i != e; ++i) { + if (auto *e{x.UnwrapArgExpr(i)}) { + result.second.push_back(*e); + } + } + return result; + } + + template + Result operator()(const Operation &x) const { + if constexpr (std::is_same_v>) { + // Ignore top-level parentheses. + return (*this)(x.template operand<0>()); + } + if constexpr (IgnoreResizes && std::is_same_v>) { + // Ignore conversions within the same category. + // Atomic operations on int(kind=1) may be implicitly widened + // to int(kind=4) for example. + return (*this)(x.template operand<0>()); + } else { + return std::make_pair(operation::OperationCode(x), + OperationArgs(x, std::index_sequence_for{})); + } + } + + template Result operator()(const Designator &x) const { + return {operation::Operator::Identity, {AsSomeExpr(x)}}; + } + + template Result operator()(const Constant &x) const { + return {operation::Operator::Identity, {AsSomeExpr(x)}}; + } + + template + Result Combine(Result &&result, Rs &&...results) const { + // There shouldn't be any combining needed, since we're stopping the + // traversal at the top-level operation, but implement one that picks + // the first non-empty result. + if constexpr (sizeof...(Rs) == 0) { + return std::move(result); + } else { + if (!result.second.empty()) { + return std::move(result); + } else { + return Combine(std::move(results)...); + } + } + } + +private: + template + Arguments OperationArgs( + const Operation &x, std::index_sequence) const { + return Arguments{Expr(x.template operand())...}; + } +}; +} // namespace operation + +std::string operation::ToString(operation::Operator op) { + switch (op) { + case Operator::Unknown: + return "??"; + case Operator::Add: + return "+"; + case Operator::And: + return "AND"; + case Operator::Associated: + return "ASSOCIATED"; + case Operator::Call: + return "function-call"; + case Operator::Constant: + return "constant"; + case Operator::Convert: + return "type-conversion"; + case Operator::Div: + return "/"; + case Operator::Eq: + return "=="; + case Operator::Eqv: + return "EQV"; + case Operator::False: + return ".FALSE."; + case Operator::Ge: + return ">="; + case Operator::Gt: + return ">"; + case Operator::Identity: + return "identity"; + case Operator::Intrinsic: + return "intrinsic"; + case Operator::Le: + return "<="; + case Operator::Lt: + return "<"; + case Operator::Max: + return "MAX"; + case Operator::Min: + return "MIN"; + case Operator::Mul: + return "*"; + case Operator::Ne: + return "/="; + case Operator::Neqv: + return "NEQV/EOR"; + case Operator::Not: + return "NOT"; + case Operator::Or: + return "OR"; + case Operator::Pow: + return "**"; + case Operator::Resize: + return "resize"; + case Operator::Sub: + return "-"; + case Operator::True: + return ".TRUE."; + } + llvm_unreachable("Unhandler operator"); +} + +operation::Operator operation::OperationCode(const ProcedureDesignator &proc) { + Operator code{llvm::StringSwitch(proc.GetName()) + .Case("associated", Operator::Associated) + .Case("min", Operator::Min) + .Case("max", Operator::Max) + .Case("iand", Operator::And) + .Case("ior", Operator::Or) + .Case("ieor", Operator::Neqv) + .Default(Operator::Call)}; + if (code == Operator::Call && proc.GetSpecificIntrinsic()) { + return Operator::Intrinsic; + } + return code; +} + +std::pair>> +GetTopLevelOperation(const Expr &expr) { + return operation::ArgumentExtractor{}(expr); +} + +namespace operation { +struct ConvertCollector + : public Traverse>, std::vector>, + false> { + using Result = + std::pair>, std::vector>; + using Base = Traverse; + ConvertCollector() : Base(*this) {} + + Result Default() const { return {}; } + + using Base::operator(); + + template Result operator()(const Designator &x) const { + return {AsSomeExpr(x), {}}; + } + + template Result operator()(const FunctionRef &x) const { + return {AsSomeExpr(x), {}}; + } + + template Result operator()(const Constant &x) const { + return {AsSomeExpr(x), {}}; + } + + template + Result operator()(const Operation &x) const { + if constexpr (std::is_same_v>) { + // Ignore parentheses. + return (*this)(x.template operand<0>()); + } else if constexpr (is_convert_v) { + // Convert should always have a typed result, so it should be safe to + // dereference x.GetType(). + return Combine( + {std::nullopt, {*x.GetType()}}, (*this)(x.template operand<0>())); + } else if constexpr (is_complex_constructor_v) { + // This is a conversion iff the imaginary operand is 0. + if (IsZero(x.template operand<1>())) { + return Combine( + {std::nullopt, {*x.GetType()}}, (*this)(x.template operand<0>())); + } else { + return {AsSomeExpr(x.derived()), {}}; + } + } else { + return {AsSomeExpr(x.derived()), {}}; + } + } + + template + Result Combine(Result &&result, Rs &&...results) const { + Result v(std::move(result)); + auto setValue{[](std::optional> &x, + std::optional> &&y) { + assert((!x.has_value() || !y.has_value()) && "Multiple designators"); + if (!x.has_value()) { + x = std::move(y); + } + }}; + auto moveAppend{[](auto &accum, auto &&other) { + for (auto &&s : other) { + accum.push_back(std::move(s)); + } + }}; + (setValue(v.first, std::move(results).first), ...); + (moveAppend(v.second, std::move(results).second), ...); + return v; + } + +private: + template static bool IsZero(const A &x) { return false; } + template static bool IsZero(const Expr &x) { + return common::visit([](auto &&s) { return IsZero(s); }, x.u); + } + template static bool IsZero(const Constant &x) { + if (auto &&maybeScalar{x.GetScalarValue()}) { + return maybeScalar->IsZero(); + } else { + return false; + } + } + + template struct is_convert { + static constexpr bool value{false}; + }; + template + struct is_convert> { + static constexpr bool value{true}; + }; + template struct is_convert> { + // Conversion from complex to real. + static constexpr bool value{true}; + }; + template + static constexpr bool is_convert_v{is_convert::value}; + + template struct is_complex_constructor { + static constexpr bool value{false}; + }; + template struct is_complex_constructor> { + static constexpr bool value{true}; + }; + template + static constexpr bool is_complex_constructor_v{ + is_complex_constructor::value}; +}; +} // namespace operation + +std::optional> GetConvertInput(const Expr &x) { + // This returns Expr{x} when x is a designator/functionref/constant. + return operation::ConvertCollector{}(x).first; +} + +bool IsSameOrConvertOf(const Expr &expr, const Expr &x) { + // Check if expr is same as x, or a sequence of Convert operations on x. + if (expr == x) { + return true; + } else if (auto maybe{GetConvertInput(expr)}) { + return *maybe == x; + } else { + return false; + } +} } // namespace Fortran::evaluate namespace Fortran::semantics { diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 15bcff254756..2603a3f6dc64 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Frontend/Debug/Options.h" +#include "llvm/Frontend/Driver/CodeGenOptions.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -441,6 +442,15 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, opts.IsPIE = 1; } + if (args.hasArg(clang::driver::options::OPT_fprofile_generate)) { + opts.setProfileInstr(llvm::driver::ProfileInstrKind::ProfileIRInstr); + } + + if (auto A = args.getLastArg(clang::driver::options::OPT_fprofile_use_EQ)) { + opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileIRInstr); + opts.ProfileInstrumentUsePath = A->getValue(); + } + // -mcmodel option. if (const llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_mcmodel_EQ)) { @@ -1001,7 +1011,7 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args, if (wArg == "error") { res.setWarnAsErr(true); // -W(no-) - } else if (!features.ApplyCliOption(wArg)) { + } else if (!features.EnableWarning(wArg)) { const unsigned diagID = diags.getCustomDiagID( clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0"); diags.Report(diagID) << wArg; diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 1c8a419188b8..d684eeb69675 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -56,10 +56,12 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/ProfileData/InstrProfCorrelator.h" #include "llvm/Support/AMDGPUAddrSpace.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/PGOOptions.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" @@ -67,6 +69,7 @@ #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include "llvm/Transforms/IPO/Internalize.h" +#include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include #include @@ -919,6 +922,29 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { llvm::PassInstrumentationCallbacks pic; llvm::PipelineTuningOptions pto; std::optional pgoOpt; + + if (opts.hasProfileIRInstr()) { + // -fprofile-generate. + pgoOpt = llvm::PGOOptions(opts.InstrProfileOutput.empty() + ? llvm::driver::getDefaultProfileGenName() + : opts.InstrProfileOutput, + "", "", opts.MemoryProfileUsePath, nullptr, + llvm::PGOOptions::IRInstr, + llvm::PGOOptions::NoCSAction, + llvm::PGOOptions::ColdFuncOpt::Default, false, + /*PseudoProbeForProfiling=*/false, false); + } else if (opts.hasProfileIRUse()) { + llvm::IntrusiveRefCntPtr VFS = + llvm::vfs::getRealFileSystem(); + // -fprofile-use. + auto CSAction = opts.hasProfileCSIRUse() ? llvm::PGOOptions::CSIRUse + : llvm::PGOOptions::NoCSAction; + pgoOpt = llvm::PGOOptions( + opts.ProfileInstrumentUsePath, "", opts.ProfileRemappingFile, + opts.MemoryProfileUsePath, VFS, llvm::PGOOptions::IRUse, CSAction, + llvm::PGOOptions::ColdFuncOpt::Default, false); + } + llvm::StandardInstrumentations si(llvmModule->getContext(), opts.DebugPassManager); si.registerCallbacks(pic, &mam); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 5ff8101dba09..64b16b3abe99 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2033,7 +2033,11 @@ private: fir::LocalitySpecifierOperands privateClauseOps; auto doConcurrentLoopOp = mlir::dyn_cast_if_present(info.loopOp); - bool useDelayedPriv = enableDelayedPrivatization && doConcurrentLoopOp; + // TODO Promote to using `enableDelayedPrivatization` (which is enabled by + // default unlike the staging flag) once the implementation of this is more + // complete. + bool useDelayedPriv = + enableDelayedPrivatizationStaging && doConcurrentLoopOp; llvm::SetVector allPrivatizedSymbols; llvm::SmallSet mightHaveReadHostSym; diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt index 9c5db2b12651..8049cdf33317 100644 --- a/flang/lib/Lower/CMakeLists.txt +++ b/flang/lib/Lower/CMakeLists.txt @@ -23,6 +23,7 @@ add_flang_library(FortranLower LoweringOptions.cpp Mangler.cpp OpenACC.cpp + OpenMP/Atomic.cpp OpenMP/ClauseProcessor.cpp OpenMP/Clauses.cpp OpenMP/DataSharingProcessor.cpp diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 7378118cfef7..864499e6c343 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -26,6 +26,7 @@ #include "flang/Optimizer/Builder/IntrinsicCall.h" #include "flang/Optimizer/Builder/LowLevelIntrinsics.h" #include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h" #include "flang/Optimizer/Builder/Runtime/Derived.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/CUF/CUFOps.h" @@ -543,6 +544,19 @@ Fortran::lower::genCallOpAndResult( fir::FortranProcedureFlagsEnumAttr procAttrs = caller.getProcedureAttrs(builder.getContext()); + if (converter.getLoweringOptions().getCUDARuntimeCheck()) { + if (caller.getCallDescription().chevrons().empty()) { + for (auto [oper, arg] : + llvm::zip(operands, caller.getPassedArguments())) { + if (auto boxTy = mlir::dyn_cast(oper.getType())) { + const Fortran::semantics::Symbol *sym = caller.getDummySymbol(arg); + if (sym && Fortran::evaluate::IsCUDADeviceSymbol(*sym)) + fir::runtime::cuda::genDescriptorCheckSection(builder, loc, oper); + } + } + } + } + if (!caller.getCallDescription().chevrons().empty()) { // A call to a CUDA kernel with the chevron syntax. diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 69e9c53baa74..3ef3330cba2d 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -654,7 +654,7 @@ void genAtomicCapture(Fortran::lower::AbstractConverter &converter, mlir::Block &block = atomicCaptureOp->getRegion(0).back(); firOpBuilder.setInsertionPointToStart(&block); if (Fortran::parser::CheckForSingleVariableOnRHS(stmt1)) { - if (Fortran::semantics::CheckForSymbolMatch( + if (Fortran::evaluate::CheckForSymbolMatch( Fortran::semantics::GetExpr(stmt2Var), Fortran::semantics::GetExpr(stmt2Expr))) { // Atomic capture construct is of the form [capture-stmt, update-stmt] diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp new file mode 100644 index 000000000000..33a743f8f9dd --- /dev/null +++ b/flang/lib/Lower/OpenMP/Atomic.cpp @@ -0,0 +1,510 @@ +//===-- Atomic.cpp -- Lowering of atomic constructs -----------------------===// +// +// 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 "Atomic.h" +#include "Clauses.h" +#include "flang/Evaluate/expression.h" +#include "flang/Evaluate/fold.h" +#include "flang/Evaluate/tools.h" +#include "flang/Lower/AbstractConverter.h" +#include "flang/Lower/PFTBuilder.h" +#include "flang/Lower/StatementContext.h" +#include "flang/Lower/SymbolMap.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Parser/parse-tree.h" +#include "flang/Semantics/semantics.h" +#include "flang/Semantics/type.h" +#include "flang/Support/Fortran.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include + +static llvm::cl::opt DumpAtomicAnalysis("fdebug-dump-atomic-analysis"); + +using namespace Fortran; + +// Don't import the entire Fortran::lower. +namespace omp { +using namespace Fortran::lower::omp; +} + +[[maybe_unused]] static void +dumpAtomicAnalysis(const parser::OpenMPAtomicConstruct::Analysis &analysis) { + auto whatStr = [](int k) { + std::string txt = "?"; + switch (k & parser::OpenMPAtomicConstruct::Analysis::Action) { + case parser::OpenMPAtomicConstruct::Analysis::None: + txt = "None"; + break; + case parser::OpenMPAtomicConstruct::Analysis::Read: + txt = "Read"; + break; + case parser::OpenMPAtomicConstruct::Analysis::Write: + txt = "Write"; + break; + case parser::OpenMPAtomicConstruct::Analysis::Update: + txt = "Update"; + break; + } + switch (k & parser::OpenMPAtomicConstruct::Analysis::Condition) { + case parser::OpenMPAtomicConstruct::Analysis::IfTrue: + txt += " | IfTrue"; + break; + case parser::OpenMPAtomicConstruct::Analysis::IfFalse: + txt += " | IfFalse"; + break; + } + return txt; + }; + + auto exprStr = [&](const parser::TypedExpr &expr) { + if (auto *maybe = expr.get()) { + if (maybe->v) + return maybe->v->AsFortran(); + } + return ""s; + }; + auto assignStr = [&](const parser::AssignmentStmt::TypedAssignment &assign) { + if (auto *maybe = assign.get(); maybe && maybe->v) { + std::string str; + llvm::raw_string_ostream os(str); + maybe->v->AsFortran(os); + return str; + } + return ""s; + }; + + const semantics::SomeExpr &atom = *analysis.atom.get()->v; + + llvm::errs() << "Analysis {\n"; + llvm::errs() << " atom: " << atom.AsFortran() << "\n"; + llvm::errs() << " cond: " << exprStr(analysis.cond) << "\n"; + llvm::errs() << " op0 {\n"; + llvm::errs() << " what: " << whatStr(analysis.op0.what) << "\n"; + llvm::errs() << " assign: " << assignStr(analysis.op0.assign) << "\n"; + llvm::errs() << " }\n"; + llvm::errs() << " op1 {\n"; + llvm::errs() << " what: " << whatStr(analysis.op1.what) << "\n"; + llvm::errs() << " assign: " << assignStr(analysis.op1.assign) << "\n"; + llvm::errs() << " }\n"; + llvm::errs() << "}\n"; +} + +static bool isPointerAssignment(const evaluate::Assignment &assign) { + return common::visit( + common::visitors{ + [](const evaluate::Assignment::BoundsSpec &) { return true; }, + [](const evaluate::Assignment::BoundsRemapping &) { return true; }, + [](const auto &) { return false; }, + }, + assign.u); +} + +static fir::FirOpBuilder::InsertPoint +getInsertionPointBefore(mlir::Operation *op) { + return fir::FirOpBuilder::InsertPoint(op->getBlock(), + mlir::Block::iterator(op)); +} + +static fir::FirOpBuilder::InsertPoint +getInsertionPointAfter(mlir::Operation *op) { + return fir::FirOpBuilder::InsertPoint(op->getBlock(), + ++mlir::Block::iterator(op)); +} + +static mlir::IntegerAttr getAtomicHint(lower::AbstractConverter &converter, + const omp::List &clauses) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + for (const omp::Clause &clause : clauses) { + if (clause.id != llvm::omp::Clause::OMPC_hint) + continue; + auto &hint = std::get(clause.u); + auto maybeVal = evaluate::ToInt64(hint.v); + CHECK(maybeVal); + return builder.getI64IntegerAttr(*maybeVal); + } + return nullptr; +} + +static mlir::omp::ClauseMemoryOrderKind +getMemoryOrderKind(common::OmpMemoryOrderType kind) { + switch (kind) { + case common::OmpMemoryOrderType::Acq_Rel: + return mlir::omp::ClauseMemoryOrderKind::Acq_rel; + case common::OmpMemoryOrderType::Acquire: + return mlir::omp::ClauseMemoryOrderKind::Acquire; + case common::OmpMemoryOrderType::Relaxed: + return mlir::omp::ClauseMemoryOrderKind::Relaxed; + case common::OmpMemoryOrderType::Release: + return mlir::omp::ClauseMemoryOrderKind::Release; + case common::OmpMemoryOrderType::Seq_Cst: + return mlir::omp::ClauseMemoryOrderKind::Seq_cst; + } + llvm_unreachable("Unexpected kind"); +} + +static std::optional +getMemoryOrderKind(llvm::omp::Clause clauseId) { + switch (clauseId) { + case llvm::omp::Clause::OMPC_acq_rel: + return mlir::omp::ClauseMemoryOrderKind::Acq_rel; + case llvm::omp::Clause::OMPC_acquire: + return mlir::omp::ClauseMemoryOrderKind::Acquire; + case llvm::omp::Clause::OMPC_relaxed: + return mlir::omp::ClauseMemoryOrderKind::Relaxed; + case llvm::omp::Clause::OMPC_release: + return mlir::omp::ClauseMemoryOrderKind::Release; + case llvm::omp::Clause::OMPC_seq_cst: + return mlir::omp::ClauseMemoryOrderKind::Seq_cst; + default: + return std::nullopt; + } +} + +static std::optional +getMemoryOrderFromRequires(const semantics::Scope &scope) { + // The REQUIRES construct is only allowed in the main program scope + // and module scope, but seems like we also accept it in a subprogram + // scope. + // For safety, traverse all enclosing scopes and check if their symbol + // contains REQUIRES. + for (const auto *sc{&scope}; sc->kind() != semantics::Scope::Kind::Global; + sc = &sc->parent()) { + const semantics::Symbol *sym = sc->symbol(); + if (!sym) + continue; + + const common::OmpMemoryOrderType *admo = common::visit( + [](auto &&s) { + using WithOmpDeclarative = semantics::WithOmpDeclarative; + if constexpr (std::is_convertible_v) { + return s.ompAtomicDefaultMemOrder(); + } + return static_cast(nullptr); + }, + sym->details()); + if (admo) + return getMemoryOrderKind(*admo); + } + + return std::nullopt; +} + +static std::optional +getDefaultAtomicMemOrder(semantics::SemanticsContext &semaCtx) { + unsigned version = semaCtx.langOptions().OpenMPVersion; + if (version > 50) + return mlir::omp::ClauseMemoryOrderKind::Relaxed; + return std::nullopt; +} + +static std::optional +getAtomicMemoryOrder(semantics::SemanticsContext &semaCtx, + const omp::List &clauses, + const semantics::Scope &scope) { + for (const omp::Clause &clause : clauses) { + if (auto maybeKind = getMemoryOrderKind(clause.id)) + return *maybeKind; + } + + if (auto maybeKind = getMemoryOrderFromRequires(scope)) + return *maybeKind; + + return getDefaultAtomicMemOrder(semaCtx); +} + +static mlir::omp::ClauseMemoryOrderKindAttr +makeMemOrderAttr(lower::AbstractConverter &converter, + std::optional maybeKind) { + if (maybeKind) { + return mlir::omp::ClauseMemoryOrderKindAttr::get( + converter.getFirOpBuilder().getContext(), *maybeKind); + } + return nullptr; +} + +static mlir::Operation * // +genAtomicRead(lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, mlir::Location loc, + lower::StatementContext &stmtCtx, mlir::Value atomAddr, + const semantics::SomeExpr &atom, + const evaluate::Assignment &assign, mlir::IntegerAttr hint, + std::optional memOrder, + fir::FirOpBuilder::InsertPoint preAt, + fir::FirOpBuilder::InsertPoint atomicAt, + fir::FirOpBuilder::InsertPoint postAt) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + builder.restoreInsertionPoint(preAt); + + // If the atomic clause is read then the memory-order clause must + // not be release. + if (memOrder) { + if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release) { + // Reset it back to the default. + memOrder = getDefaultAtomicMemOrder(semaCtx); + } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) { + // The MLIR verifier doesn't like acq_rel either. + memOrder = mlir::omp::ClauseMemoryOrderKind::Acquire; + } + } + + mlir::Value storeAddr = + fir::getBase(converter.genExprAddr(assign.lhs, stmtCtx, &loc)); + mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); + mlir::Type storeType = fir::unwrapRefType(storeAddr.getType()); + + mlir::Value toAddr = [&]() { + if (atomType == storeType) + return storeAddr; + return builder.createTemporary(loc, atomType, ".tmp.atomval"); + }(); + + builder.restoreInsertionPoint(atomicAt); + mlir::Operation *op = builder.create( + loc, atomAddr, toAddr, mlir::TypeAttr::get(atomType), hint, + makeMemOrderAttr(converter, memOrder)); + + if (atomType != storeType) { + lower::ExprToValueMap overrides; + // The READ operation could be a part of UPDATE CAPTURE, so make sure + // we don't emit extra code into the body of the atomic op. + builder.restoreInsertionPoint(postAt); + mlir::Value load = builder.create(loc, toAddr); + overrides.try_emplace(&atom, load); + + converter.overrideExprValues(&overrides); + mlir::Value value = + fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); + converter.resetExprOverrides(); + + builder.create(loc, value, storeAddr); + } + return op; +} + +static mlir::Operation * // +genAtomicWrite(lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, mlir::Location loc, + lower::StatementContext &stmtCtx, mlir::Value atomAddr, + const semantics::SomeExpr &atom, + const evaluate::Assignment &assign, mlir::IntegerAttr hint, + std::optional memOrder, + fir::FirOpBuilder::InsertPoint preAt, + fir::FirOpBuilder::InsertPoint atomicAt, + fir::FirOpBuilder::InsertPoint postAt) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + builder.restoreInsertionPoint(preAt); + + // If the atomic clause is write then the memory-order clause must + // not be acquire. + if (memOrder) { + if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire) { + // Reset it back to the default. + memOrder = getDefaultAtomicMemOrder(semaCtx); + } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) { + // The MLIR verifier doesn't like acq_rel either. + memOrder = mlir::omp::ClauseMemoryOrderKind::Release; + } + } + + mlir::Value value = + fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); + mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); + mlir::Value converted = builder.createConvert(loc, atomType, value); + + builder.restoreInsertionPoint(atomicAt); + mlir::Operation *op = builder.create( + loc, atomAddr, converted, hint, makeMemOrderAttr(converter, memOrder)); + return op; +} + +static mlir::Operation * +genAtomicUpdate(lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, mlir::Location loc, + lower::StatementContext &stmtCtx, mlir::Value atomAddr, + const semantics::SomeExpr &atom, + const evaluate::Assignment &assign, mlir::IntegerAttr hint, + std::optional memOrder, + fir::FirOpBuilder::InsertPoint preAt, + fir::FirOpBuilder::InsertPoint atomicAt, + fir::FirOpBuilder::InsertPoint postAt) { + lower::ExprToValueMap overrides; + lower::StatementContext naCtx; + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + builder.restoreInsertionPoint(preAt); + + mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); + + // This must exist by now. + semantics::SomeExpr input = *evaluate::GetConvertInput(assign.rhs); + std::vector args = + evaluate::GetTopLevelOperation(input).second; + assert(!args.empty() && "Update operation without arguments"); + for (auto &arg : args) { + if (!evaluate::IsSameOrConvertOf(arg, atom)) { + mlir::Value val = fir::getBase(converter.genExprValue(arg, naCtx, &loc)); + overrides.try_emplace(&arg, val); + } + } + + builder.restoreInsertionPoint(atomicAt); + auto updateOp = builder.create( + loc, atomAddr, hint, makeMemOrderAttr(converter, memOrder)); + + mlir::Region ®ion = updateOp->getRegion(0); + mlir::Block *block = builder.createBlock(®ion, {}, {atomType}, {loc}); + mlir::Value localAtom = fir::getBase(block->getArgument(0)); + overrides.try_emplace(&atom, localAtom); + + converter.overrideExprValues(&overrides); + mlir::Value updated = + fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); + mlir::Value converted = builder.createConvert(loc, atomType, updated); + builder.create(loc, converted); + converter.resetExprOverrides(); + + builder.restoreInsertionPoint(postAt); // For naCtx cleanups + return updateOp; +} + +static mlir::Operation * +genAtomicOperation(lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, mlir::Location loc, + lower::StatementContext &stmtCtx, int action, + mlir::Value atomAddr, const semantics::SomeExpr &atom, + const evaluate::Assignment &assign, mlir::IntegerAttr hint, + std::optional memOrder, + fir::FirOpBuilder::InsertPoint preAt, + fir::FirOpBuilder::InsertPoint atomicAt, + fir::FirOpBuilder::InsertPoint postAt) { + if (isPointerAssignment(assign)) { + TODO(loc, "Code generation for pointer assignment is not implemented yet"); + } + + // This function and the functions called here do not preserve the + // builder's insertion point, or set it to anything specific. + switch (action) { + case parser::OpenMPAtomicConstruct::Analysis::Read: + return genAtomicRead(converter, semaCtx, loc, stmtCtx, atomAddr, atom, + assign, hint, memOrder, preAt, atomicAt, postAt); + case parser::OpenMPAtomicConstruct::Analysis::Write: + return genAtomicWrite(converter, semaCtx, loc, stmtCtx, atomAddr, atom, + assign, hint, memOrder, preAt, atomicAt, postAt); + case parser::OpenMPAtomicConstruct::Analysis::Update: + return genAtomicUpdate(converter, semaCtx, loc, stmtCtx, atomAddr, atom, + assign, hint, memOrder, preAt, atomicAt, postAt); + default: + return nullptr; + } +} + +void Fortran::lower::omp::lowerAtomic( + AbstractConverter &converter, SymMap &symTable, + semantics::SemanticsContext &semaCtx, pft::Evaluation &eval, + const parser::OpenMPAtomicConstruct &construct) { + auto get = [](auto &&typedWrapper) -> decltype(&*typedWrapper.get()->v) { + if (auto *maybe = typedWrapper.get(); maybe && maybe->v) { + return &*maybe->v; + } else { + return nullptr; + } + }; + + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + auto &dirSpec = std::get(construct.t); + omp::List clauses = makeClauses(dirSpec.Clauses(), semaCtx); + lower::StatementContext stmtCtx; + + const parser::OpenMPAtomicConstruct::Analysis &analysis = construct.analysis; + if (DumpAtomicAnalysis) + dumpAtomicAnalysis(analysis); + + const semantics::SomeExpr &atom = *get(analysis.atom); + mlir::Location loc = converter.genLocation(construct.source); + mlir::Value atomAddr = + fir::getBase(converter.genExprAddr(atom, stmtCtx, &loc)); + mlir::IntegerAttr hint = getAtomicHint(converter, clauses); + std::optional memOrder = + getAtomicMemoryOrder(semaCtx, clauses, + semaCtx.FindScope(construct.source)); + + if (auto *cond = get(analysis.cond)) { + (void)cond; + TODO(loc, "OpenMP ATOMIC COMPARE"); + } else { + int action0 = analysis.op0.what & analysis.Action; + int action1 = analysis.op1.what & analysis.Action; + mlir::Operation *captureOp = nullptr; + fir::FirOpBuilder::InsertPoint preAt = builder.saveInsertionPoint(); + fir::FirOpBuilder::InsertPoint atomicAt, postAt; + + if (construct.IsCapture()) { + // Capturing operation. + assert(action0 != analysis.None && action1 != analysis.None && + "Expexcing two actions"); + (void)action0; + (void)action1; + captureOp = builder.create( + loc, hint, makeMemOrderAttr(converter, memOrder)); + // Set the non-atomic insertion point to before the atomic.capture. + preAt = getInsertionPointBefore(captureOp); + + mlir::Block *block = builder.createBlock(&captureOp->getRegion(0)); + builder.setInsertionPointToEnd(block); + // Set the atomic insertion point to before the terminator inside + // atomic.capture. + mlir::Operation *term = builder.create(loc); + atomicAt = getInsertionPointBefore(term); + postAt = getInsertionPointAfter(captureOp); + hint = nullptr; + memOrder = std::nullopt; + } else { + // Non-capturing operation. + assert(action0 != analysis.None && action1 == analysis.None && + "Expexcing single action"); + assert(!(analysis.op0.what & analysis.Condition)); + postAt = atomicAt = preAt; + } + + // The builder's insertion point needs to be specifically set before + // each call to `genAtomicOperation`. + mlir::Operation *firstOp = genAtomicOperation( + converter, semaCtx, loc, stmtCtx, analysis.op0.what, atomAddr, atom, + *get(analysis.op0.assign), hint, memOrder, preAt, atomicAt, postAt); + assert(firstOp && "Should have created an atomic operation"); + atomicAt = getInsertionPointAfter(firstOp); + + mlir::Operation *secondOp = nullptr; + if (analysis.op1.what != analysis.None) { + secondOp = genAtomicOperation( + converter, semaCtx, loc, stmtCtx, analysis.op1.what, atomAddr, atom, + *get(analysis.op1.assign), hint, memOrder, preAt, atomicAt, postAt); + } + + if (construct.IsCapture()) { + // If this is a capture operation, the first/second ops will be inside + // of it. Set the insertion point to past the capture op itself. + builder.restoreInsertionPoint(postAt); + } else { + if (secondOp) { + builder.setInsertionPointAfter(secondOp); + } else { + builder.setInsertionPointAfter(firstOp); + } + } + } +} diff --git a/flang/lib/Lower/OpenMP/Atomic.h b/flang/lib/Lower/OpenMP/Atomic.h new file mode 100644 index 000000000000..96db4d7e90c8 --- /dev/null +++ b/flang/lib/Lower/OpenMP/Atomic.h @@ -0,0 +1,36 @@ +//===-- Atomic.h -- Lowering of atomic constructs -------------------------===// +// +// 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 FORTRAN_LOWER_OPENMP_ATOMIC_H +#define FORTRAN_LOWER_OPENMP_ATOMIC_H + +namespace Fortran { +namespace lower { +class AbstractConverter; +class SymMap; + +namespace pft { +struct Evaluation; +} +} // namespace lower + +namespace parser { +struct OpenMPAtomicConstruct; +} + +namespace semantics { +class SemanticsContext; +} +} // namespace Fortran + +namespace Fortran::lower::omp { +void lowerAtomic(AbstractConverter &converter, SymMap &symTable, + semantics::SemanticsContext &semaCtx, pft::Evaluation &eval, + const parser::OpenMPAtomicConstruct &construct); +} + +#endif // FORTRAN_LOWER_OPENMP_ATOMIC_H diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 88baad8827e9..7bea427099a2 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -727,12 +727,15 @@ public: // Is the type inside a box? bool isBox() const { return inBox; } + bool isBoxChar() const { return inBoxChar; } + private: void typeScan(mlir::Type type); std::optional charLen; llvm::SmallVector shape; bool inBox = false; + bool inBoxChar = false; }; void TypeInfo::typeScan(mlir::Type ty) { @@ -748,6 +751,9 @@ void TypeInfo::typeScan(mlir::Type ty) { typeScan(cty.getEleTy()); } else if (auto cty = mlir::dyn_cast(ty)) { charLen = cty.getLen(); + } else if (auto cty = mlir::dyn_cast(ty)) { + inBoxChar = true; + typeScan(cty.getEleTy()); } else if (auto hty = mlir::dyn_cast(ty)) { typeScan(hty.getEleTy()); } else if (auto pty = mlir::dyn_cast(ty)) { @@ -791,12 +797,6 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter, fir::FortranVariableFlagsAttr attrs; if (varAttrs != fir::FortranVariableFlagsEnum::None) attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs); - llvm::SmallVector typeparams; - if (typeInfo.getCharLength().has_value()) { - mlir::Value charLen = builder.createIntegerConstant( - loc, builder.getCharacterLengthType(), *typeInfo.getCharLength()); - typeparams.push_back(charLen); - } mlir::Value shape; if (!typeInfo.isBox() && !typeInfo.getShape().empty()) { llvm::SmallVector extents; @@ -805,11 +805,34 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter, builder.createIntegerConstant(loc, builder.getIndexType(), extent)); shape = builder.create(loc, extents); } + mlir::Value dst = funcOp.getArgument(0); + mlir::Value src = funcOp.getArgument(1); + llvm::SmallVector typeparams; + if (typeInfo.isBoxChar()) { + // fir.boxchar will be passed here as fir.ref + auto loadDst = builder.create(loc, dst); + auto loadSrc = builder.create(loc, src); + // get the actual fir.ref type + mlir::Type refType = + fir::ReferenceType::get(mlir::cast(eleTy).getEleTy()); + auto unboxedDst = builder.create( + loc, refType, builder.getIndexType(), loadDst); + auto unboxedSrc = builder.create( + loc, refType, builder.getIndexType(), loadSrc); + // Add length to type parameters + typeparams.push_back(unboxedDst.getResult(1)); + dst = unboxedDst.getResult(0); + src = unboxedSrc.getResult(0); + } else if (typeInfo.getCharLength().has_value()) { + mlir::Value charLen = builder.createIntegerConstant( + loc, builder.getCharacterLengthType(), *typeInfo.getCharLength()); + typeparams.push_back(charLen); + } auto declDst = builder.create( - loc, funcOp.getArgument(0), copyFuncName + "_dst", shape, typeparams, + loc, dst, copyFuncName + "_dst", shape, typeparams, /*dummy_scope=*/nullptr, attrs); auto declSrc = builder.create( - loc, funcOp.getArgument(1), copyFuncName + "_src", shape, typeparams, + loc, src, copyFuncName + "_src", shape, typeparams, /*dummy_scope=*/nullptr, attrs); converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs); builder.create(loc); @@ -835,10 +858,13 @@ bool ClauseProcessor::processCopyprivate( // CopyPrivate variables must be passed by reference. However, in the case // of assumed shapes/vla the type is not a !fir.ref, but a !fir.box. - // In these cases to retrieve the appropriate !fir.ref> to - // access the data we need we must perform an alloca and then store to it - // and retrieve the data from the new alloca. - if (mlir::isa(symType)) { + // In the case of character types, the passed in type can also be + // !fir.boxchar. In these cases to retrieve the appropriate + // !fir.ref> or !fir.ref> to access the data + // we need we must perform an alloca and then store to it and retrieve the + // data from the new alloca. + if (mlir::isa(symType) || + mlir::isa(symType)) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); auto alloca = builder.create(currentLocation, symType); builder.create(currentLocation, symVal, alloca); @@ -926,14 +952,10 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap, for (const omp::Object &object : objects) { assert(object.ref() && "Expecting designator"); mlir::Value dependVar; + SomeExpr expr = *object.ref(); - if (evaluate::ExtractSubstring(*object.ref())) { - TODO(converter.getCurrentLocation(), - "substring not supported for task depend"); - } else if (evaluate::IsArrayElement(*object.ref())) { - // Array Section - SomeExpr expr = *object.ref(); - + if (evaluate::IsArrayElement(expr) || evaluate::ExtractSubstring(expr)) { + // Array Section or character (sub)string if (isVectorSubscript(expr)) { // OpenMP needs the address of the first indexed element (required by // the standard to be the lowest index) to identify the dependency. We @@ -947,7 +969,8 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap, converter.getCurrentLocation(), converter, expr, symMap, stmtCtx); dependVar = entity.getBase(); } - } else if (evaluate::isStructureComponent(*object.ref())) { + } else if (evaluate::isStructureComponent(expr) || + evaluate::ExtractComplexPart(expr)) { SomeExpr expr = *object.ref(); hlfir::EntityWithAttributes entity = convertExprToHLFIR( converter.getCurrentLocation(), converter, expr, symMap, stmtCtx); @@ -1246,7 +1269,7 @@ void ClauseProcessor::processMapObjects( bool ClauseProcessor::processMap( mlir::Location currentLocation, lower::StatementContext &stmtCtx, - mlir::omp::MapClauseOps &result, + mlir::omp::MapClauseOps &result, llvm::omp::Directive directive, llvm::SmallVectorImpl *mapSyms) const { // We always require tracking of symbols, even if the caller does not, // so we create an optionally used local set of symbols when the mapSyms @@ -1264,9 +1287,18 @@ bool ClauseProcessor::processMap( llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; std::string mapperIdName = "__implicit_mapper"; - // If the map type is specified, then process it else Tofrom is the - // default. - Map::MapType type = mapType.value_or(Map::MapType::Tofrom); + // If the map type is specified, then process it else set the appropriate + // default value + Map::MapType type; + if (directive == llvm::omp::Directive::OMPD_target_enter_data && + semaCtx.langOptions().OpenMPVersion >= 52) + type = mapType.value_or(Map::MapType::To); + else if (directive == llvm::omp::Directive::OMPD_target_exit_data && + semaCtx.langOptions().OpenMPVersion >= 52) + type = mapType.value_or(Map::MapType::From); + else + type = mapType.value_or(Map::MapType::Tofrom); + switch (type) { case Map::MapType::To: mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO; diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h index c957a94d387e..3d8c4a337a4a 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.h +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h @@ -139,6 +139,7 @@ public: bool processMap(mlir::Location currentLocation, lower::StatementContext &stmtCtx, mlir::omp::MapClauseOps &result, + llvm::omp::Directive directive = llvm::omp::OMPD_unknown, llvm::SmallVectorImpl *mapSyms = nullptr) const; bool processMotionClauses(lower::StatementContext &stmtCtx, diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index f3088b18b77f..b599d69a3627 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -70,19 +70,18 @@ struct SymbolAndDesignatorExtractor { static void verify(const SymbolWithDesignator &sd) { const semantics::Symbol *symbol = std::get<0>(sd); - assert(symbol && "Expecting symbol"); - auto &maybeDsg = std::get<1>(sd); + const std::optional> &maybeDsg = + std::get<1>(sd); if (!maybeDsg) return; // Symbol with no designator -> OK - std::optional maybeRef = - evaluate::ExtractDataRef(*maybeDsg); + assert(symbol && "Expecting symbol"); + std::optional maybeRef = evaluate::ExtractDataRef( + *maybeDsg, /*intoSubstring=*/true, /*intoComplexPart=*/true); if (maybeRef) { if (&maybeRef->GetLastSymbol() == symbol) return; // Symbol with a designator for it -> OK llvm_unreachable("Expecting designator for given symbol"); } else { - // This could still be a Substring or ComplexPart, but at least Substring - // is not allowed in OpenMP. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) maybeDsg->dump(); #endif @@ -906,8 +905,8 @@ Inclusive make(const parser::OmpClause::Inclusive &inp, Indirect make(const parser::OmpClause::Indirect &inp, semantics::SemanticsContext &semaCtx) { - // inp -> empty - llvm_unreachable("Empty: indirect"); + // inp.v.v -> std::optional + return Indirect{maybeApply(makeExprFn(semaCtx), inp.v.v)}; } Init make(const parser::OmpClause::Init &inp, @@ -1044,7 +1043,7 @@ Map make(const parser::OmpClause::Map &inp, auto type = [&]() -> std::optional { if (t3) return convert1(t3->v); - return Map::MapType::Tofrom; + return std::nullopt; }(); Map::MapTypeModifiers typeMods; diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp index 1b8670b379f8..3fae3f3a0ddf 100644 --- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp +++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp @@ -204,6 +204,42 @@ void DataSharingProcessor::collectOmpObjectListSymbol( } void DataSharingProcessor::collectSymbolsForPrivatization() { + // Add checks here for exceptional cases where privatization is not + // needed and be deferred to a later phase (like OpenMP IRBuilder). + // Such cases are suggested to be clearly documented and explained + // instead of being silently skipped + auto isException = [&](const Fortran::semantics::Symbol *sym) -> bool { + // `OmpPreDetermined` symbols cannot be exceptions since + // their privatized symbols are heavily used in FIR. + if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined)) + return false; + + // The handling of linear clause is deferred to the OpenMP + // IRBuilder which is responsible for all its aspects, + // including privatization. Privatizing linear variables at this point would + // cause the following structure: + // + // omp.op linear(%linear = %step : !fir.ref) { + // Use %linear in this BB + // } + // + // to be changed to the following: + // + // omp. op linear(%linear = %step : !fir.ref) + // private(%linear -> %arg0 : !fir.ref) { + // Declare and use %arg0 in this BB + // } + // + // The OpenMP IRBuilder needs to map the linear MLIR value + // (i.e. %linear) to its `uses` in the BB to correctly + // implement the functionalities of linear clause. However, + // privatizing here disallows the IRBuilder to + // draw a relation between %linear and %arg0. Hence skip. + if (sym->test(Fortran::semantics::Symbol::Flag::OmpLinear)) + return true; + return false; + }; + for (const omp::Clause &clause : clauses) { if (const auto &privateClause = std::get_if(&clause.u)) { @@ -222,10 +258,10 @@ void DataSharingProcessor::collectSymbolsForPrivatization() { } // TODO For common blocks, add the underlying objects within the block. Doing - // so, we won't need to explicitely handle block objects (or forget to do + // so, we won't need to explicitly handle block objects (or forget to do // so). for (auto *sym : explicitlyPrivatizedSymbols) - if (!sym->test(Fortran::semantics::Symbol::Flag::OmpLinear)) + if (!isException(sym)) allPrivatizedSymbols.insert(sym); } diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 3f3b85696db3..ebd1d038716e 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -12,6 +12,7 @@ #include "flang/Lower/OpenMP.h" +#include "Atomic.h" #include "ClauseProcessor.h" #include "Clauses.h" #include "DataSharingProcessor.h" @@ -41,13 +42,10 @@ #include "mlir/Transforms/RegionUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" -#include "llvm/Support/CommandLine.h" using namespace Fortran::lower::omp; using namespace Fortran::common::openmp; -static llvm::cl::opt DumpAtomicAnalysis("fdebug-dump-atomic-analysis"); - //===----------------------------------------------------------------------===// // Code generation helper functions //===----------------------------------------------------------------------===// @@ -201,6 +199,8 @@ private: /// structures, but it will probably still require some further work to support /// reverse offloading. static llvm::SmallVector hostEvalInfo; +static llvm::SmallVector + sectionsStack; /// Bind symbols to their corresponding entry block arguments. /// @@ -1125,16 +1125,6 @@ markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter, declareTargetOp.setDeclareTarget(deviceType, captureClause); } -static bool isPointerAssignment(const evaluate::Assignment &assign) { - return common::visit( - common::visitors{ - [](const evaluate::Assignment::BoundsSpec &) { return true; }, - [](const evaluate::Assignment::BoundsRemapping &) { return true; }, - [](const auto &) { return false; }, - }, - assign.u); -} - //===----------------------------------------------------------------------===// // Op body generation helper structures and functions //===----------------------------------------------------------------------===// @@ -1829,7 +1819,8 @@ static void genTargetClauses( } cp.processIf(llvm::omp::Directive::OMPD_target, clauseOps); cp.processIsDevicePtr(clauseOps, isDevicePtrSyms); - cp.processMap(loc, stmtCtx, clauseOps, &mapSyms); + cp.processMap(loc, stmtCtx, clauseOps, llvm::omp::Directive::OMPD_unknown, + &mapSyms); cp.processNowait(clauseOps); cp.processThreadLimit(stmtCtx, clauseOps); @@ -1882,7 +1873,7 @@ static void genTargetEnterExitUpdateDataClauses( if (directive == llvm::omp::Directive::OMPD_target_update) cp.processMotionClauses(stmtCtx, clauseOps); else - cp.processMap(loc, stmtCtx, clauseOps); + cp.processMap(loc, stmtCtx, clauseOps, directive); cp.processNowait(clauseOps); } @@ -1977,13 +1968,13 @@ static void genWsloopClauses( llvm::SmallVectorImpl &reductionSyms) { ClauseProcessor cp(converter, semaCtx, clauses); cp.processNowait(clauseOps); - cp.processLinear(clauseOps); cp.processOrder(clauseOps); cp.processOrdered(clauseOps); cp.processReduction(loc, clauseOps, reductionSyms); cp.processSchedule(stmtCtx, clauseOps); - cp.processTODO(loc, llvm::omp::Directive::OMPD_do); + cp.processTODO( + loc, llvm::omp::Directive::OMPD_do); } //===----------------------------------------------------------------------===// @@ -2220,8 +2211,12 @@ static mlir::omp::SectionsOp genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, mlir::Location loc, - const ConstructQueue &queue, ConstructQueue::const_iterator item, - const parser::OmpSectionBlocks §ionBlocks) { + const ConstructQueue &queue, + ConstructQueue::const_iterator item) { + assert(!sectionsStack.empty()); + const auto §ionBlocks = + std::get(sectionsStack.back()->t); + sectionsStack.pop_back(); mlir::omp::SectionsOperands clauseOps; llvm::SmallVector reductionSyms; genSectionsClauses(converter, semaCtx, item->clauses, loc, clauseOps, @@ -2668,6 +2663,7 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, mlir::Location loc, const ConstructQueue &queue, ConstructQueue::const_iterator item) { + lower::SymMapScope scope(symTable); mlir::omp::TeamsOperands clauseOps; llvm::SmallVector reductionSyms; genTeamsClauses(converter, semaCtx, stmtCtx, item->clauses, loc, clauseOps, @@ -2686,220 +2682,6 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, queue, item, clauseOps); } -//===----------------------------------------------------------------------===// -// Code generation for atomic operations -//===----------------------------------------------------------------------===// -static fir::FirOpBuilder::InsertPoint -getInsertionPointBefore(mlir::Operation *op) { - return fir::FirOpBuilder::InsertPoint(op->getBlock(), - mlir::Block::iterator(op)); -} - -static fir::FirOpBuilder::InsertPoint -getInsertionPointAfter(mlir::Operation *op) { - return fir::FirOpBuilder::InsertPoint(op->getBlock(), - ++mlir::Block::iterator(op)); -} - -static mlir::IntegerAttr getAtomicHint(lower::AbstractConverter &converter, - const List &clauses) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - for (const Clause &clause : clauses) { - if (clause.id != llvm::omp::Clause::OMPC_hint) - continue; - auto &hint = std::get(clause.u); - auto maybeVal = evaluate::ToInt64(hint.v); - CHECK(maybeVal); - return builder.getI64IntegerAttr(*maybeVal); - } - return nullptr; -} - -static mlir::omp::ClauseMemoryOrderKindAttr -getAtomicMemoryOrder(lower::AbstractConverter &converter, - semantics::SemanticsContext &semaCtx, - const List &clauses) { - std::optional kind; - unsigned version = semaCtx.langOptions().OpenMPVersion; - - for (const Clause &clause : clauses) { - switch (clause.id) { - case llvm::omp::Clause::OMPC_acq_rel: - kind = mlir::omp::ClauseMemoryOrderKind::Acq_rel; - break; - case llvm::omp::Clause::OMPC_acquire: - kind = mlir::omp::ClauseMemoryOrderKind::Acquire; - break; - case llvm::omp::Clause::OMPC_relaxed: - kind = mlir::omp::ClauseMemoryOrderKind::Relaxed; - break; - case llvm::omp::Clause::OMPC_release: - kind = mlir::omp::ClauseMemoryOrderKind::Release; - break; - case llvm::omp::Clause::OMPC_seq_cst: - kind = mlir::omp::ClauseMemoryOrderKind::Seq_cst; - break; - default: - break; - } - } - - // Starting with 5.1, if no memory-order clause is present, the effect - // is as if "relaxed" was present. - if (!kind) { - if (version <= 50) - return nullptr; - kind = mlir::omp::ClauseMemoryOrderKind::Relaxed; - } - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - return mlir::omp::ClauseMemoryOrderKindAttr::get(builder.getContext(), *kind); -} - -static mlir::Operation * // -genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc, - lower::StatementContext &stmtCtx, mlir::Value atomAddr, - const semantics::SomeExpr &atom, - const evaluate::Assignment &assign, mlir::IntegerAttr hint, - mlir::omp::ClauseMemoryOrderKindAttr memOrder, - fir::FirOpBuilder::InsertPoint preAt, - fir::FirOpBuilder::InsertPoint atomicAt, - fir::FirOpBuilder::InsertPoint postAt) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - builder.restoreInsertionPoint(preAt); - - mlir::Value storeAddr = - fir::getBase(converter.genExprAddr(assign.lhs, stmtCtx, &loc)); - mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); - mlir::Type storeType = fir::unwrapRefType(storeAddr.getType()); - - mlir::Value toAddr = [&]() { - if (atomType == storeType) - return storeAddr; - return builder.createTemporary(loc, atomType, ".tmp.atomval"); - }(); - - builder.restoreInsertionPoint(atomicAt); - mlir::Operation *op = builder.create( - loc, atomAddr, toAddr, mlir::TypeAttr::get(atomType), hint, memOrder); - - if (atomType != storeType) { - lower::ExprToValueMap overrides; - // The READ operation could be a part of UPDATE CAPTURE, so make sure - // we don't emit extra code into the body of the atomic op. - builder.restoreInsertionPoint(postAt); - mlir::Value load = builder.create(loc, toAddr); - overrides.try_emplace(&atom, load); - - converter.overrideExprValues(&overrides); - mlir::Value value = - fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); - converter.resetExprOverrides(); - - builder.create(loc, value, storeAddr); - } - return op; -} - -static mlir::Operation * // -genAtomicWrite(lower::AbstractConverter &converter, mlir::Location loc, - lower::StatementContext &stmtCtx, mlir::Value atomAddr, - const semantics::SomeExpr &atom, - const evaluate::Assignment &assign, mlir::IntegerAttr hint, - mlir::omp::ClauseMemoryOrderKindAttr memOrder, - fir::FirOpBuilder::InsertPoint preAt, - fir::FirOpBuilder::InsertPoint atomicAt, - fir::FirOpBuilder::InsertPoint postAt) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - builder.restoreInsertionPoint(preAt); - - mlir::Value value = - fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); - mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); - mlir::Value converted = builder.createConvert(loc, atomType, value); - - builder.restoreInsertionPoint(atomicAt); - mlir::Operation *op = builder.create( - loc, atomAddr, converted, hint, memOrder); - return op; -} - -static mlir::Operation * -genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc, - lower::StatementContext &stmtCtx, mlir::Value atomAddr, - const semantics::SomeExpr &atom, - const evaluate::Assignment &assign, mlir::IntegerAttr hint, - mlir::omp::ClauseMemoryOrderKindAttr memOrder, - fir::FirOpBuilder::InsertPoint preAt, - fir::FirOpBuilder::InsertPoint atomicAt, - fir::FirOpBuilder::InsertPoint postAt) { - lower::ExprToValueMap overrides; - lower::StatementContext naCtx; - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - builder.restoreInsertionPoint(preAt); - - mlir::Type atomType = fir::unwrapRefType(atomAddr.getType()); - - // This must exist by now. - SomeExpr input = *semantics::GetConvertInput(assign.rhs); - std::vector args{semantics::GetTopLevelOperation(input).second}; - assert(!args.empty() && "Update operation without arguments"); - for (auto &arg : args) { - if (!semantics::IsSameOrConvertOf(arg, atom)) { - mlir::Value val = fir::getBase(converter.genExprValue(arg, naCtx, &loc)); - overrides.try_emplace(&arg, val); - } - } - - builder.restoreInsertionPoint(atomicAt); - auto updateOp = - builder.create(loc, atomAddr, hint, memOrder); - - mlir::Region ®ion = updateOp->getRegion(0); - mlir::Block *block = builder.createBlock(®ion, {}, {atomType}, {loc}); - mlir::Value localAtom = fir::getBase(block->getArgument(0)); - overrides.try_emplace(&atom, localAtom); - - converter.overrideExprValues(&overrides); - mlir::Value updated = - fir::getBase(converter.genExprValue(assign.rhs, stmtCtx, &loc)); - mlir::Value converted = builder.createConvert(loc, atomType, updated); - builder.create(loc, converted); - converter.resetExprOverrides(); - - builder.restoreInsertionPoint(postAt); // For naCtx cleanups - return updateOp; -} - -static mlir::Operation * -genAtomicOperation(lower::AbstractConverter &converter, mlir::Location loc, - lower::StatementContext &stmtCtx, int action, - mlir::Value atomAddr, const semantics::SomeExpr &atom, - const evaluate::Assignment &assign, mlir::IntegerAttr hint, - mlir::omp::ClauseMemoryOrderKindAttr memOrder, - fir::FirOpBuilder::InsertPoint preAt, - fir::FirOpBuilder::InsertPoint atomicAt, - fir::FirOpBuilder::InsertPoint postAt) { - if (isPointerAssignment(assign)) { - TODO(loc, "Code generation for pointer assignment is not implemented yet"); - } - - // This function and the functions called here do not preserve the - // builder's insertion point, or set it to anything specific. - switch (action) { - case parser::OpenMPAtomicConstruct::Analysis::Read: - return genAtomicRead(converter, loc, stmtCtx, atomAddr, atom, assign, hint, - memOrder, preAt, atomicAt, postAt); - case parser::OpenMPAtomicConstruct::Analysis::Write: - return genAtomicWrite(converter, loc, stmtCtx, atomAddr, atom, assign, hint, - memOrder, preAt, atomicAt, postAt); - case parser::OpenMPAtomicConstruct::Analysis::Update: - return genAtomicUpdate(converter, loc, stmtCtx, atomAddr, atom, assign, - hint, memOrder, preAt, atomicAt, postAt); - default: - return nullptr; - } -} - //===----------------------------------------------------------------------===// // Code generation functions for the standalone version of constructs that can // also be a leaf of a composite construct @@ -2975,6 +2757,7 @@ static mlir::omp::ParallelOp genStandaloneParallel( lower::StatementContext &stmtCtx, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, mlir::Location loc, const ConstructQueue &queue, ConstructQueue::const_iterator item) { + lower::SymMapScope scope(symTable); mlir::omp::ParallelOperands parallelClauseOps; llvm::SmallVector parallelReductionSyms; genParallelClauses(converter, semaCtx, stmtCtx, item->clauses, loc, @@ -3458,10 +3241,7 @@ static void genOMPDispatch(lower::AbstractConverter &converter, // Lowered in the enclosing genSectionsOp. break; case llvm::omp::Directive::OMPD_sections: - // Called directly from genOMP([...], OpenMPSectionsConstruct) because it - // has a different prototype. - // This code path is still taken when iterating through the construct queue - // in genBodyOfOp + genSectionsOp(converter, symTable, semaCtx, eval, loc, queue, item); break; case llvm::omp::Directive::OMPD_simd: newOp = @@ -3806,160 +3586,11 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, // OpenMPConstruct visitors //===----------------------------------------------------------------------===// -[[maybe_unused]] static void -dumpAtomicAnalysis(const parser::OpenMPAtomicConstruct::Analysis &analysis) { - auto whatStr = [](int k) { - std::string txt = "?"; - switch (k & parser::OpenMPAtomicConstruct::Analysis::Action) { - case parser::OpenMPAtomicConstruct::Analysis::None: - txt = "None"; - break; - case parser::OpenMPAtomicConstruct::Analysis::Read: - txt = "Read"; - break; - case parser::OpenMPAtomicConstruct::Analysis::Write: - txt = "Write"; - break; - case parser::OpenMPAtomicConstruct::Analysis::Update: - txt = "Update"; - break; - } - switch (k & parser::OpenMPAtomicConstruct::Analysis::Condition) { - case parser::OpenMPAtomicConstruct::Analysis::IfTrue: - txt += " | IfTrue"; - break; - case parser::OpenMPAtomicConstruct::Analysis::IfFalse: - txt += " | IfFalse"; - break; - } - return txt; - }; - - auto exprStr = [&](const parser::TypedExpr &expr) { - if (auto *maybe = expr.get()) { - if (maybe->v) - return maybe->v->AsFortran(); - } - return ""s; - }; - auto assignStr = [&](const parser::AssignmentStmt::TypedAssignment &assign) { - if (auto *maybe = assign.get(); maybe && maybe->v) { - std::string str; - llvm::raw_string_ostream os(str); - maybe->v->AsFortran(os); - return str; - } - return ""s; - }; - - const SomeExpr &atom = *analysis.atom.get()->v; - - llvm::errs() << "Analysis {\n"; - llvm::errs() << " atom: " << atom.AsFortran() << "\n"; - llvm::errs() << " cond: " << exprStr(analysis.cond) << "\n"; - llvm::errs() << " op0 {\n"; - llvm::errs() << " what: " << whatStr(analysis.op0.what) << "\n"; - llvm::errs() << " assign: " << assignStr(analysis.op0.assign) << "\n"; - llvm::errs() << " }\n"; - llvm::errs() << " op1 {\n"; - llvm::errs() << " what: " << whatStr(analysis.op1.what) << "\n"; - llvm::errs() << " assign: " << assignStr(analysis.op1.assign) << "\n"; - llvm::errs() << " }\n"; - llvm::errs() << "}\n"; -} - static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, const parser::OpenMPAtomicConstruct &construct) { - auto get = [](auto &&typedWrapper) -> decltype(&*typedWrapper.get()->v) { - if (auto *maybe = typedWrapper.get(); maybe && maybe->v) { - return &*maybe->v; - } else { - return nullptr; - } - }; - - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - auto &dirSpec = std::get(construct.t); - List clauses = makeClauses(dirSpec.Clauses(), semaCtx); - lower::StatementContext stmtCtx; - - const parser::OpenMPAtomicConstruct::Analysis &analysis = construct.analysis; - if (DumpAtomicAnalysis) - dumpAtomicAnalysis(analysis); - - const semantics::SomeExpr &atom = *get(analysis.atom); - mlir::Location loc = converter.genLocation(construct.source); - mlir::Value atomAddr = - fir::getBase(converter.genExprAddr(atom, stmtCtx, &loc)); - mlir::IntegerAttr hint = getAtomicHint(converter, clauses); - mlir::omp::ClauseMemoryOrderKindAttr memOrder = - getAtomicMemoryOrder(converter, semaCtx, clauses); - - if (auto *cond = get(analysis.cond)) { - (void)cond; - TODO(loc, "OpenMP ATOMIC COMPARE"); - } else { - int action0 = analysis.op0.what & analysis.Action; - int action1 = analysis.op1.what & analysis.Action; - mlir::Operation *captureOp = nullptr; - fir::FirOpBuilder::InsertPoint preAt = builder.saveInsertionPoint(); - fir::FirOpBuilder::InsertPoint atomicAt, postAt; - - if (construct.IsCapture()) { - // Capturing operation. - assert(action0 != analysis.None && action1 != analysis.None && - "Expexcing two actions"); - captureOp = - builder.create(loc, hint, memOrder); - // Set the non-atomic insertion point to before the atomic.capture. - preAt = getInsertionPointBefore(captureOp); - - mlir::Block *block = builder.createBlock(&captureOp->getRegion(0)); - builder.setInsertionPointToEnd(block); - // Set the atomic insertion point to before the terminator inside - // atomic.capture. - mlir::Operation *term = builder.create(loc); - atomicAt = getInsertionPointBefore(term); - postAt = getInsertionPointAfter(captureOp); - hint = nullptr; - memOrder = nullptr; - } else { - // Non-capturing operation. - assert(action0 != analysis.None && action1 == analysis.None && - "Expexcing single action"); - assert(!(analysis.op0.what & analysis.Condition)); - postAt = atomicAt = preAt; - } - - // The builder's insertion point needs to be specifically set before - // each call to `genAtomicOperation`. - mlir::Operation *firstOp = genAtomicOperation( - converter, loc, stmtCtx, analysis.op0.what, atomAddr, atom, - *get(analysis.op0.assign), hint, memOrder, preAt, atomicAt, postAt); - assert(firstOp && "Should have created an atomic operation"); - atomicAt = getInsertionPointAfter(firstOp); - - mlir::Operation *secondOp = nullptr; - if (analysis.op1.what != analysis.None) { - secondOp = genAtomicOperation(converter, loc, stmtCtx, analysis.op1.what, - atomAddr, atom, *get(analysis.op1.assign), - hint, memOrder, preAt, atomicAt, postAt); - } - - if (construct.IsCapture()) { - // If this is a capture operation, the first/second ops will be inside - // of it. Set the insertion point to past the capture op itself. - builder.restoreInsertionPoint(postAt); - } else { - if (secondOp) { - builder.setInsertionPointAfter(secondOp); - } else { - builder.setInsertionPointAfter(firstOp); - } - } - } + lowerAtomic(converter, symTable, semaCtx, eval, construct); } static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, @@ -4128,8 +3759,6 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, std::get(beginSectionsDirective.t), semaCtx); const auto &endSectionsDirective = std::get(sectionsConstruct.t); - const auto §ionBlocks = - std::get(sectionsConstruct.t); clauses.append(makeClauses( std::get(endSectionsDirective.t), semaCtx)); mlir::Location currentLocation = converter.getCurrentLocation(); @@ -4141,22 +3770,10 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, ConstructQueue queue{ buildConstructQueue(converter.getFirOpBuilder().getModule(), semaCtx, eval, source, directive, clauses)}; - ConstructQueue::iterator next = queue.begin(); - // Generate constructs that come first e.g. Parallel - while (next != queue.end() && - next->id != llvm::omp::Directive::OMPD_sections) { - genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue, - next); - next = std::next(next); - } - // call genSectionsOp directly (not via genOMPDispatch) so that we can add the - // sectionBlocks argument - assert(next != queue.end()); - assert(next->id == llvm::omp::Directive::OMPD_sections); - genSectionsOp(converter, symTable, semaCtx, eval, currentLocation, queue, - next, sectionBlocks); - assert(std::next(next) == queue.end()); + sectionsStack.push_back(§ionsConstruct); + genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue, + queue.begin()); } static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp index 2cc458cb6130..68023610c3c5 100644 --- a/flang/lib/Lower/PFTBuilder.cpp +++ b/flang/lib/Lower/PFTBuilder.cpp @@ -1096,7 +1096,9 @@ private: // The first executable statement in the subprogram is preceded by a // branch to the entry point, so it starts a new block. - if (initialEval->hasNestedEvaluations()) + // OpenMP directives can generate code around the nested evaluations. + if (initialEval->hasNestedEvaluations() && + !initialEval->isOpenMPDirective()) initialEval = &initialEval->getFirstNestedEvaluation(); else if (initialEval->isA()) initialEval = initialEval->lexicalSuccessor; diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 584f3c8ee310..6ac87067f651 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -283,6 +283,9 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() { if (auto doConcurentOp = getRegion().getParentOfType()) return doConcurentOp.getBody(); + if (auto firLocalOp = getRegion().getParentOfType()) + return &getRegion().front(); + return getEntryBlock(); } diff --git a/flang/lib/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp b/flang/lib/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp index 90662c094c65..a943469a7672 100644 --- a/flang/lib/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp @@ -32,3 +32,18 @@ void fir::runtime::cuda::genSyncGlobalDescriptor(fir::FirOpBuilder &builder, builder, loc, fTy, hostPtr, sourceFile, sourceLine)}; builder.create(loc, callee, args); } + +void fir::runtime::cuda::genDescriptorCheckSection(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Value desc) { + mlir::func::FuncOp func = + fir::runtime::getRuntimeFunc(loc, + builder); + auto fTy = func.getFunctionType(); + mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); + mlir::Value sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + llvm::SmallVector args{fir::runtime::createArguments( + builder, loc, fTy, desc, sourceFile, sourceLine)}; + builder.create(loc, func, args); +} diff --git a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp index 82b11ad7db32..69bdb48146a5 100644 --- a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp +++ b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp @@ -274,12 +274,12 @@ public: auto loc = embox.getLoc(); mlir::Type i8Ty = builder.getI8Type(); mlir::Type i8Ptr = builder.getRefType(i8Ty); - // For AArch64, PPC32 and PPC64, the thunk is populated by a call to + // For PPC32 and PPC64, the thunk is populated by a call to // __trampoline_setup, which is defined in // compiler-rt/lib/builtins/trampoline_setup.c and requires the - // thunk size greater than 32 bytes. For RISCV and x86_64, the - // thunk setup doesn't go through __trampoline_setup and fits in 32 - // bytes. + // thunk size greater than 32 bytes. For AArch64, RISCV and x86_64, + // the thunk setup doesn't go through __trampoline_setup and fits in + // 32 bytes. fir::SequenceType::Extent thunkSize = triple.getTrampolineSize(); mlir::Type buffTy = SequenceType::get({thunkSize}, i8Ty); auto buffer = builder.create(loc, buffTy); diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 82d960a6fc61..a3de3ae9d116 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3294,6 +3294,30 @@ struct LoadOpConversion : public fir::FIROpConversion { } }; +struct LocalitySpecifierOpConversion + : public fir::FIROpConversion { + using FIROpConversion::FIROpConversion; + llvm::LogicalResult + matchAndRewrite(fir::LocalitySpecifierOp localizer, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { +#ifdef EXPENSIVE_CHECKS + auto uses = mlir::SymbolTable::getSymbolUses( + localizer, localizer->getParentOfType()); + + // `fir.local` ops are not supposed to have any uses at this point (i.e. + // during lowering to LLVM). In case of serialization, the + // `fir.do_concurrent` users are expected to have been lowered to + // `fir.do_loop` nests. In case of parallelization, the `fir.do_concurrent` + // users are expected to have been lowered to the target parallel model + // (e.g. OpenMP). + assert(uses && uses->empty()); +#endif + + rewriter.eraseOp(localizer); + return mlir::success(); + } +}; + /// Lower `fir.no_reassoc` to LLVM IR dialect. /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast /// math flags? @@ -4249,15 +4273,15 @@ void fir::populateFIRToLLVMConversionPatterns( FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion, - MulcOpConversion, NegcOpConversion, NoReassocOpConversion, - SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion, - SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion, - ShiftOpConversion, SliceOpConversion, StoreOpConversion, - StringLitOpConversion, SubcOpConversion, TypeDescOpConversion, - TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, - UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion, - XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter, - options); + LocalitySpecifierOpConversion, MulcOpConversion, NegcOpConversion, + NoReassocOpConversion, SelectCaseOpConversion, SelectOpConversion, + SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion, + ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion, + StoreOpConversion, StringLitOpConversion, SubcOpConversion, + TypeDescOpConversion, TypeInfoOpConversion, UnboxCharOpConversion, + UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion, + XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion, + ZeroOpConversion>(converter, options); // Patterns that are populated without a type converter do not trigger // target materializations for the operands of the root op. diff --git a/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp index de97a0bbc184..2774382c22bf 100644 --- a/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp +++ b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp @@ -250,6 +250,8 @@ PackArrayConversion::genRepackedBox(fir::FirOpBuilder &builder, fir::IfOp ifOp = builder.create(loc, boxType, doPack, /*withElseRegion=*/true); + // Assume that the repacking is unlikely. + ifOp.setUnlikelyIfWeights(); // Return original box. builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); @@ -322,20 +324,24 @@ UnpackArrayConversion::matchAndRewrite(fir::UnpackArrayOp op, auto isNotSame = builder.genPtrCompare(loc, mlir::arith::CmpIPredicate::ne, tempAddr, originalAddr); - builder.genIfThen(loc, isNotSame).genThen([&]() {}); - // Copy from temporary to the original. - if (!op.getNoCopy()) - fir::runtime::genShallowCopy(builder, loc, originalBox, tempBox, - /*resultIsAllocated=*/true); + builder.genIfThen(loc, isNotSame) + .genThen([&]() { + // Copy from temporary to the original. + if (!op.getNoCopy()) + fir::runtime::genShallowCopy(builder, loc, originalBox, tempBox, + /*resultIsAllocated=*/true); - // Deallocate, if it was allocated in heap. - // Note that the stack attribute does not always mean - // that the allocation was actually done in stack memory. - // There are currently cases where we delegate the allocation - // to the runtime that uses heap memory, even when the stack - // attribute is set on fir.pack_array. - if (!op.getStack() || !canAllocateTempOnStack(originalBox)) - builder.create(loc, tempAddr); + // Deallocate, if it was allocated in heap. + // Note that the stack attribute does not always mean + // that the allocation was actually done in stack memory. + // There are currently cases where we delegate the allocation + // to the runtime that uses heap memory, even when the stack + // attribute is set on fir.pack_array. + if (!op.getStack() || !canAllocateTempOnStack(originalBox)) + builder.create(loc, tempAddr); + }) + .getIfOp() + .setUnlikelyIfWeights(); }); rewriter.eraseOp(op); return mlir::success(); diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 6181e1fad424..ecfa2939e96a 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -4418,6 +4418,19 @@ mlir::ParseResult fir::IfOp::parse(mlir::OpAsmParser &parser, parser.resolveOperand(cond, i1Type, result.operands)) return mlir::failure(); + if (mlir::succeeded( + parser.parseOptionalKeyword(getWeightsAttrAssemblyName()))) { + if (parser.parseLParen()) + return mlir::failure(); + mlir::DenseI32ArrayAttr weights; + if (parser.parseCustomAttributeWithFallback(weights, mlir::Type{})) + return mlir::failure(); + if (weights) + result.addAttribute(getRegionWeightsAttrName(result.name), weights); + if (parser.parseRParen()) + return mlir::failure(); + } + if (parser.parseOptionalArrowTypeList(result.types)) return mlir::failure(); @@ -4449,6 +4462,11 @@ llvm::LogicalResult fir::IfOp::verify() { void fir::IfOp::print(mlir::OpAsmPrinter &p) { bool printBlockTerminators = false; p << ' ' << getCondition(); + if (auto weights = getRegionWeightsAttr()) { + p << ' ' << getWeightsAttrAssemblyName() << '('; + p.printStrippedAttrOrType(weights); + p << ')'; + } if (!getResults().empty()) { p << " -> (" << getResultTypes() << ')'; printBlockTerminators = true; @@ -4464,7 +4482,8 @@ void fir::IfOp::print(mlir::OpAsmPrinter &p) { p.printRegion(otherReg, /*printEntryBlockArgs=*/false, printBlockTerminators); } - p.printOptionalAttrDict((*this)->getAttrs()); + p.printOptionalAttrDict((*this)->getAttrs(), + /*elideAttrs=*/{getRegionWeightsAttrName()}); } void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl &results, diff --git a/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp b/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp index 8a9e9b80134b..3d35803e6a2d 100644 --- a/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp +++ b/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp @@ -212,9 +212,12 @@ public: } rewriter.setInsertionPointToEnd(condBlock); - rewriter.create( + auto branchOp = rewriter.create( loc, ifOp.getCondition(), ifOpBlock, llvm::ArrayRef(), otherwiseBlock, llvm::ArrayRef()); + llvm::ArrayRef weights = ifOp.getWeights(); + if (!weights.empty()) + branchOp.setWeights(weights); rewriter.replaceOp(ifOp, continueBlock->getArguments()); return success(); } diff --git a/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp b/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp index cb9e48cced2a..e440852b3103 100644 --- a/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp +++ b/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp @@ -180,41 +180,50 @@ public: std::optional localSyms = loop.getLocalSyms(); - for (auto [localVar, localArg, localizerSym] : llvm::zip_equal( + for (auto localInfo : llvm::zip_equal( loop.getLocalVars(), loop.getRegionLocalArgs(), *localSyms)) { + mlir::Value localVar = std::get<0>(localInfo); + mlir::BlockArgument localArg = std::get<1>(localInfo); + mlir::Attribute localizerSym = std::get<2>(localInfo); mlir::SymbolRefAttr localizerName = llvm::cast(localizerSym); fir::LocalitySpecifierOp localizer = findLocalizer(loop, localizerName); - if (!localizer.getInitRegion().empty() || - !localizer.getDeallocRegion().empty()) - TODO(localizer.getLoc(), "localizers with `init` and `dealloc` " - "regions are not handled yet."); - // TODO Should this be a heap allocation instead? For now, we allocate // on the stack for each loop iteration. mlir::Value localAlloc = rewriter.create(loop.getLoc(), localizer.getType()); - if (localizer.getLocalitySpecifierType() == - fir::LocalitySpecifierType::LocalInit) { + auto cloneLocalizerRegion = [&](mlir::Region ®ion, + mlir::ValueRange regionArgs, + mlir::Block::iterator insertionPoint) { // It is reasonable to make this assumption since, at this stage, // control-flow ops are not converted yet. Therefore, things like `if` // conditions will still be represented by their encapsulating `fir` // dialect ops. - assert(localizer.getCopyRegion().hasOneBlock() && - "Expected localizer to have a single block."); - mlir::Block *beforeLocalInit = rewriter.getInsertionBlock(); - mlir::Block *afterLocalInit = rewriter.splitBlock( - rewriter.getInsertionBlock(), rewriter.getInsertionPoint()); - rewriter.cloneRegionBefore(localizer.getCopyRegion(), afterLocalInit); - mlir::Block *copyRegionBody = beforeLocalInit->getNextNode(); + assert(region.hasOneBlock() && + "Expected localizer region to have a single block."); + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPoint(rewriter.getInsertionBlock(), + insertionPoint); + mlir::IRMapping mapper; + mapper.map(region.getArguments(), regionArgs); + for (mlir::Operation &op : region.front().without_terminator()) + (void)rewriter.clone(op, mapper); + }; - rewriter.eraseOp(copyRegionBody->getTerminator()); - rewriter.mergeBlocks(afterLocalInit, copyRegionBody); - rewriter.mergeBlocks(copyRegionBody, beforeLocalInit, - {localVar, localArg}); - } + if (!localizer.getInitRegion().empty()) + cloneLocalizerRegion(localizer.getInitRegion(), {localVar, localArg}, + rewriter.getInsertionPoint()); + + if (localizer.getLocalitySpecifierType() == + fir::LocalitySpecifierType::LocalInit) + cloneLocalizerRegion(localizer.getCopyRegion(), {localVar, localArg}, + rewriter.getInsertionPoint()); + + if (!localizer.getDeallocRegion().empty()) + cloneLocalizerRegion(localizer.getDeallocRegion(), {localArg}, + rewriter.getInsertionBlock()->end()); rewriter.replaceAllUsesWith(localArg, localAlloc); } diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 9b112a213391..c55642d96950 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1004,6 +1004,8 @@ TYPE_PARSER( // "IF" >> construct(construct( parenthesized(Parser{}))) || "INBRANCH" >> construct(construct()) || + "INDIRECT" >> construct(construct( + maybe(parenthesized(scalarLogicalExpr)))) || "INIT" >> construct(construct( parenthesized(Parser{}))) || "INCLUSIVE" >> construct(construct( diff --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt index 18c89587843a..c0fda3631c01 100644 --- a/flang/lib/Semantics/CMakeLists.txt +++ b/flang/lib/Semantics/CMakeLists.txt @@ -40,7 +40,6 @@ add_flang_library(FortranSemantics resolve-directives.cpp resolve-names-utils.cpp resolve-names.cpp - rewrite-directives.cpp rewrite-parse-tree.cpp runtime-type-info.cpp scope.cpp diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp index 2c215f45bf51..08053594c12e 100644 --- a/flang/lib/Semantics/check-allocate.cpp +++ b/flang/lib/Semantics/check-allocate.cpp @@ -10,6 +10,7 @@ #include "assignment.h" #include "definable.h" #include "flang/Evaluate/fold.h" +#include "flang/Evaluate/shape.h" #include "flang/Evaluate/type.h" #include "flang/Parser/parse-tree.h" #include "flang/Parser/tools.h" @@ -33,6 +34,7 @@ struct AllocateCheckerInfo { bool gotMold{false}; bool gotStream{false}; bool gotPinned{false}; + std::optional sourceExprShape; }; class AllocationCheckerHelper { @@ -259,6 +261,9 @@ static std::optional CheckAllocateOptions( CheckCopyabilityInPureScope(messages, *expr, scope); } } + auto maybeShape{evaluate::GetShape(context.foldingContext(), *expr)}; + info.sourceExprShape = + evaluate::AsConstantExtents(context.foldingContext(), maybeShape); } else { // Error already reported on source expression. // Do not continue allocate checks. @@ -581,6 +586,52 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) { .Attach( ultimate_->name(), "Declared here with rank %d"_en_US, rank_); return false; + } else if (allocateInfo_.gotSource && allocateInfo_.sourceExprShape && + allocateInfo_.sourceExprShape->size() == + static_cast(allocateShapeSpecRank_)) { + std::size_t j{0}; + for (const auto &shapeSpec : + std::get>(allocation_.t)) { + if (j >= allocateInfo_.sourceExprShape->size()) { + break; + } + std::optional lbound; + if (const auto &lb{std::get<0>(shapeSpec.t)}) { + lbound.reset(); + const auto &lbExpr{lb->thing.thing.value()}; + if (const auto *expr{GetExpr(context, lbExpr)}) { + auto folded{ + evaluate::Fold(context.foldingContext(), SomeExpr(*expr))}; + lbound = evaluate::ToInt64(folded); + evaluate::SetExpr(lbExpr, std::move(folded)); + } + } else { + lbound = 1; + } + if (lbound) { + const auto &ubExpr{std::get<1>(shapeSpec.t).thing.thing.value()}; + if (const auto *expr{GetExpr(context, ubExpr)}) { + auto folded{ + evaluate::Fold(context.foldingContext(), SomeExpr(*expr))}; + auto ubound{evaluate::ToInt64(folded)}; + evaluate::SetExpr(ubExpr, std::move(folded)); + if (ubound) { + auto extent{*ubound - *lbound + 1}; + if (extent < 0) { + extent = 0; + } + if (extent != allocateInfo_.sourceExprShape->at(j)) { + context.Say(name_.source, + "Allocation has extent %jd on dimension %d, but SOURCE= has extent %jd"_err_en_US, + static_cast(extent), j + 1, + static_cast( + allocateInfo_.sourceExprShape->at(j))); + } + } + } + } + ++j; + } } } } else { // allocating a scalar object diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 46a5b970fdf0..f9d64485f140 100644 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -2958,6 +2958,14 @@ static std::optional DefinesGlobalName(const Symbol &symbol) { return std::nullopt; } +static bool IsSameSymbolFromHermeticModule( + const Symbol &symbol, const Symbol &other) { + return symbol.name() == other.name() && symbol.owner().IsModule() && + other.owner().IsModule() && symbol.owner() != other.owner() && + symbol.owner().GetName() && + symbol.owner().GetName() == other.owner().GetName(); +} + // 19.2 p2 void CheckHelper::CheckGlobalName(const Symbol &symbol) { if (auto global{DefinesGlobalName(symbol)}) { @@ -2975,6 +2983,8 @@ void CheckHelper::CheckGlobalName(const Symbol &symbol) { (!IsExternalProcedureDefinition(symbol) || !IsExternalProcedureDefinition(other))) { // both are procedures/BLOCK DATA, not both definitions + } else if (IsSameSymbolFromHermeticModule(symbol, other)) { + // Both symbols are the same thing. } else if (symbol.has()) { Warn(common::LanguageFeature::BenignNameClash, symbol.name(), "Module '%s' conflicts with a global name"_port_en_US, diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 4dccb0e88e32..3abb5a304b00 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -11,6 +11,8 @@ #include "resolve-names-utils.h" #include "flang/Evaluate/check-expression.h" #include "flang/Evaluate/expression.h" +#include "flang/Evaluate/shape.h" +#include "flang/Evaluate/tools.h" #include "flang/Evaluate/type.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/expression.h" @@ -1718,6 +1720,22 @@ void OmpStructureChecker::Leave(const parser::OpenMPDepobjConstruct &x) { void OmpStructureChecker::Enter(const parser::OpenMPRequiresConstruct &x) { const auto &dir{std::get(x.t)}; PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_requires); + + if (visitedAtomicSource_.empty()) { + return; + } + const auto &clauseList{std::get(x.t)}; + for (const parser::OmpClause &clause : clauseList.v) { + llvm::omp::Clause id{clause.Id()}; + if (id == llvm::omp::Clause::OMPC_atomic_default_mem_order) { + parser::MessageFormattedText txt( + "REQUIRES directive with '%s' clause found lexically after atomic operation without a memory order clause"_err_en_US, + parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(id))); + parser::Message message(clause.source, txt); + message.Attach(visitedAtomicSource_, "Previous atomic construct"_en_US); + context_.Say(std::move(message)); + } + } } void OmpStructureChecker::Leave(const parser::OpenMPRequiresConstruct &) { @@ -1819,15 +1837,24 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to); const parser::OmpClause *linkClause = FindClause(llvm::omp::Clause::OMPC_link); + const parser::OmpClause *indirectClause = + FindClause(llvm::omp::Clause::OMPC_indirect); if (!enterClause && !toClause && !linkClause) { context_.Say(x.source, "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US); } + if (indirectClause && !enterClause) { + context_.Say(x.source, + "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US); + } unsigned version{context_.langOptions().OpenMPVersion}; if (toClause && version >= 52) { context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); } + if (indirectClause) { + CheckAllowedClause(llvm::omp::Clause::OMPC_indirect); + } } } @@ -2961,6 +2988,8 @@ static bool IsPointerAssignment(const evaluate::Assignment &x) { std::holds_alternative(x.u); } +namespace operation = Fortran::evaluate::operation; + static bool IsCheckForAssociated(const SomeExpr &cond) { return GetTopLevelOperation(cond).first == operation::Operator::Associated; } @@ -3500,37 +3529,56 @@ void OmpStructureChecker::CheckAtomicUpdateAssignment( operation::ToString(top.first)); return; } - // Check if `atom` occurs exactly once in the argument list. + // Check how many times `atom` occurs as an argument, if it's a subexpression + // of an argument, and collect the non-atom arguments. std::vector nonAtom; - auto unique{[&]() { // -> iterator - auto found{top.second.end()}; - for (auto i{top.second.begin()}, e{top.second.end()}; i != e; ++i) { - if (IsSameOrConvertOf(*i, atom)) { - if (found != top.second.end()) { - return top.second.end(); - } - found = i; + MaybeExpr subExpr; + auto atomCount{[&]() { + int count{0}; + for (const SomeExpr &arg : top.second) { + if (IsSameOrConvertOf(arg, atom)) { + ++count; } else { - nonAtom.push_back(*i); + if (!subExpr && IsSubexpressionOf(atom, arg)) { + subExpr = arg; + } + nonAtom.push_back(arg); } } - return found; + return count; }()}; - if (unique == top.second.end()) { - if (top.first == operation::Operator::Identity) { - // This is "x = y". + bool hasError{false}; + if (subExpr) { + context_.Say(rsrc, + "The atomic variable %s cannot be a proper subexpression of an argument (here: %s) in the update operation"_err_en_US, + atom.AsFortran(), subExpr->AsFortran()); + hasError = true; + } + if (top.first == operation::Operator::Identity) { + // This is "x = y". + assert((atomCount == 0 || atomCount == 1) && "Unexpected count"); + if (atomCount == 0) { context_.Say(rsrc, "The atomic variable %s should appear as an argument in the update operation"_err_en_US, atom.AsFortran()); - } else { - assert(top.first != operation::Operator::Identity && - "Handle this separately"); - context_.Say(rsrc, - "The atomic variable %s should occur exactly once among the arguments of the top-level %s operator"_err_en_US, - atom.AsFortran(), operation::ToString(top.first)); + hasError = true; } } else { + if (atomCount == 0) { + context_.Say(rsrc, + "The atomic variable %s should appear as an argument of the top-level %s operator"_err_en_US, + atom.AsFortran(), operation::ToString(top.first)); + hasError = true; + } else if (atomCount > 1) { + context_.Say(rsrc, + "The atomic variable %s should be exactly one of the arguments of the top-level %s operator"_err_en_US, + atom.AsFortran(), operation::ToString(top.first)); + hasError = true; + } + } + + if (!hasError) { CheckStorageOverlap(atom, nonAtom, source); } } @@ -4027,6 +4075,9 @@ void OmpStructureChecker::CheckAtomicUpdate( } void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) { + if (visitedAtomicSource_.empty()) + visitedAtomicSource_ = x.source; + // All of the following groups have the "exclusive" property, i.e. at // most one clause from each group is allowed. // The exclusivity-checking code should eventually be unified for all @@ -6524,6 +6575,29 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) { void OmpStructureChecker::CheckArraySection( const parser::ArrayElement &arrayElement, const parser::Name &name, const llvm::omp::Clause clause) { + // Sometimes substring operations are incorrectly parsed as array accesses. + // Detect this by looking for array accesses on character variables which are + // not arrays. + bool isSubstring{false}; + evaluate::ExpressionAnalyzer ea{context_}; + if (MaybeExpr expr = ea.Analyze(arrayElement.base)) { + std::optional shape = evaluate::GetShape(expr); + // Not an array: rank 0 + if (shape && shape->size() == 0) { + if (std::optional type = expr->GetType()) { + if (type->category() == evaluate::TypeCategory::Character) { + // Substrings are explicitly denied by the standard [6.0:163:9-11]. + // This is supported as an extension. This restriction was added in + // OpenMP 5.2. + isSubstring = true; + context_.Say(GetContext().clauseSource, + "The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2."_port_en_US); + } else { + llvm_unreachable("Array indexing on a variable that isn't an array"); + } + } + } + } if (!arrayElement.subscripts.empty()) { for (const auto &subscript : arrayElement.subscripts) { if (const auto *triplet{ @@ -6541,6 +6615,10 @@ void OmpStructureChecker::CheckArraySection( name.ToString(), parser::ToUpperCaseLetters(getClauseName(clause).str())); } + if (isSubstring) { + context_.Say(GetContext().clauseSource, + "Cannot specify a step for a substring"_err_en_US); + } } const auto &lower{std::get<0>(triplet->t)}; const auto &upper{std::get<1>(triplet->t)}; @@ -6564,6 +6642,12 @@ void OmpStructureChecker::CheckArraySection( } } } + } else if (std::get_if(&subscript.u)) { + // base(n) is valid as an array index but not as a substring operation + if (isSubstring) { + context_.Say(GetContext().clauseSource, + "Substrings must be in the form parent-string(lb:ub)"_err_en_US); + } } } } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 2074ec611dc2..beb6e0528e81 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -360,6 +360,7 @@ private: }; int directiveNest_[LastType + 1] = {0}; + parser::CharBlock visitedAtomicSource_; SymbolSourceMap deferredNonVariables_; using LoopConstruct = std::variant &x) { - Indent("expr some type"); + Indent("relational some type"); Show(x.u); Outdent(); } diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index a72641866aa1..82c8536902eb 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -109,15 +109,14 @@ bool ModFileWriter::WriteAll() { } void ModFileWriter::WriteAll(const Scope &scope) { - for (const auto &child : scope.children()) { + for (const Scope &child : scope.children()) { WriteOne(child); } } void ModFileWriter::WriteOne(const Scope &scope) { if (scope.kind() == Scope::Kind::Module) { - auto *symbol{scope.symbol()}; - if (!symbol->test(Symbol::Flag::ModFile)) { + if (const auto *symbol{scope.symbol()}) { Write(*symbol); } WriteAll(scope); // write out submodules @@ -134,7 +133,7 @@ static std::string ModFileName(const SourceName &name, // Write the module file for symbol, which must be a module or submodule. void ModFileWriter::Write(const Symbol &symbol) { const auto &module{symbol.get()}; - if (module.moduleFileHash()) { + if (symbol.test(Symbol::Flag::ModFile) || module.moduleFileHash()) { return; // already written } const auto *ancestor{module.ancestor()}; @@ -143,18 +142,22 @@ void ModFileWriter::Write(const Symbol &symbol) { std::string path{context_.moduleDirectory() + '/' + ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())}; - UnorderedSymbolSet hermeticModules; - hermeticModules.insert(symbol); + std::set hermeticModuleNames; + hermeticModuleNames.insert(symbol.name().ToString()); UnorderedSymbolSet additionalModules; PutSymbols(DEREF(symbol.scope()), hermeticModuleFileOutput_ ? &additionalModules : nullptr); auto asStr{GetAsString(symbol)}; while (!additionalModules.empty()) { - for (auto ref : UnorderedSymbolSet{std::move(additionalModules)}) { - if (hermeticModules.insert(*ref).second && - !ref->owner().IsIntrinsicModules()) { - PutSymbols(DEREF(ref->scope()), &additionalModules); - asStr += GetAsString(*ref); + UnorderedSymbolSet nextPass{std::move(additionalModules)}; + additionalModules.clear(); + for (const Symbol &modSym : nextPass) { + if (!modSym.owner().IsIntrinsicModules() && + hermeticModuleNames.find(modSym.name().ToString()) == + hermeticModuleNames.end()) { + hermeticModuleNames.insert(modSym.name().ToString()); + PutSymbols(DEREF(modSym.scope()), &additionalModules); + asStr += GetAsString(modSym); } } } @@ -368,16 +371,19 @@ void ModFileWriter::PutSymbols( CollectSymbols(scope, sorted, uses, modules); // Write module files for dependencies first so that their // hashes are known. - for (auto ref : modules) { + for (const Symbol &mod : modules) { if (hermeticModules) { - hermeticModules->insert(*ref); + hermeticModules->insert(mod); } else { - Write(*ref); - needs_ << ModHeader::need - << CheckSumString( - ref->get().moduleFileHash().value()) - << (ref->owner().IsIntrinsicModules() ? " i " : " n ") - << ref->name().ToString() << '\n'; + Write(mod); + // It's possible that the module's file already existed and + // without its own hash due to being embedded in a hermetic + // module file. + if (auto hash{mod.get().moduleFileHash()}) { + needs_ << ModHeader::need << CheckSumString(*hash) + << (mod.owner().IsIntrinsicModules() ? " i " : " n ") + << mod.name().ToString() << '\n'; + } } } std::string buf; // stuff after CONTAINS in derived type @@ -851,25 +857,25 @@ void CollectSymbols(const Scope &scope, SymbolVector &sorted, auto symbols{scope.GetSymbols()}; std::size_t commonSize{scope.commonBlocks().size()}; sorted.reserve(symbols.size() + commonSize); - for (SymbolRef symbol : symbols) { - const auto *generic{symbol->detailsIf()}; + for (const Symbol &symbol : symbols) { + const auto *generic{symbol.detailsIf()}; if (generic) { uses.insert(uses.end(), generic->uses().begin(), generic->uses().end()); - for (auto ref : generic->uses()) { - modules.insert(GetUsedModule(ref->get())); + for (const Symbol &used : generic->uses()) { + modules.insert(GetUsedModule(used.get())); } - } else if (const auto *use{symbol->detailsIf()}) { + } else if (const auto *use{symbol.detailsIf()}) { modules.insert(GetUsedModule(*use)); } - if (symbol->test(Symbol::Flag::ParentComp)) { - } else if (symbol->has()) { + if (symbol.test(Symbol::Flag::ParentComp)) { + } else if (symbol.has()) { namelist.push_back(symbol); } else if (generic) { if (generic->specific() && - &generic->specific()->owner() == &symbol->owner()) { + &generic->specific()->owner() == &symbol.owner()) { sorted.push_back(*generic->specific()); } else if (generic->derivedType() && - &generic->derivedType()->owner() == &symbol->owner()) { + &generic->derivedType()->owner() == &symbol.owner()) { sorted.push_back(*generic->derivedType()); } generics.push_back(symbol); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 93bf510fbc3c..885c02e6ec74 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -23,6 +23,7 @@ #include "flang/Semantics/openmp-modifiers.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" +#include "llvm/Frontend/OpenMP/OMP.h.inc" #include "llvm/Support/Debug.h" #include #include @@ -384,6 +385,9 @@ public: bool Pre(const parser::OpenMPSectionsConstruct &); void Post(const parser::OpenMPSectionsConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPSectionConstruct &); + void Post(const parser::OpenMPSectionConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPCriticalConstruct &critical); void Post(const parser::OpenMPCriticalConstruct &) { PopContext(); } @@ -737,9 +741,7 @@ public: } const parser::OmpClause *associatedClause{nullptr}; - void SetAssociatedClause(const parser::OmpClause &c) { - associatedClause = &c; - } + void SetAssociatedClause(const parser::OmpClause *c) { associatedClause = c; } const parser::OmpClause *GetAssociatedClause() { return associatedClause; } private: @@ -833,8 +835,8 @@ private: void AddOmpRequiresToScope(Scope &, WithOmpDeclarative::RequiresFlags, std::optional); - void IssueNonConformanceWarning( - llvm::omp::Directive D, parser::CharBlock source); + void IssueNonConformanceWarning(llvm::omp::Directive D, + parser::CharBlock source, unsigned EmitFromVersion); void CreateImplicitSymbols(const Symbol *symbol); @@ -1666,7 +1668,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) { } if (beginDir.v == llvm::omp::Directive::OMPD_master || beginDir.v == llvm::omp::Directive::OMPD_parallel_master) - IssueNonConformanceWarning(beginDir.v, beginDir.source); + IssueNonConformanceWarning(beginDir.v, beginDir.source, 52); ClearDataSharingAttributeObjects(); ClearPrivateDataSharingAttributeObjects(); ClearAllocateNames(); @@ -1789,7 +1791,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) { beginDir.v == llvm::omp::OMPD_parallel_master_taskloop || beginDir.v == llvm::omp::OMPD_parallel_master_taskloop_simd || beginDir.v == llvm::omp::Directive::OMPD_target_loop) - IssueNonConformanceWarning(beginDir.v, beginDir.source); + IssueNonConformanceWarning(beginDir.v, beginDir.source, 52); ClearDataSharingAttributeObjects(); SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); @@ -1916,12 +1918,17 @@ std::int64_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses( } if (orderedLevel && (!collapseLevel || orderedLevel >= collapseLevel)) { - SetAssociatedClause(*ordClause); + SetAssociatedClause(ordClause); return orderedLevel; } else if (!orderedLevel && collapseLevel) { - SetAssociatedClause(*collClause); + SetAssociatedClause(collClause); return collapseLevel; - } // orderedLevel < collapseLevel is an error handled in structural checks + } else { + SetAssociatedClause(nullptr); + } + // orderedLevel < collapseLevel is an error handled in structural + // checks + return 1; // default is outermost loop } @@ -1949,9 +1956,31 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel( ivDSA = Symbol::Flag::OmpLastPrivate; } + bool isLoopConstruct{ + GetContext().directive == llvm::omp::Directive::OMPD_loop}; + const parser::OmpClause *clause{GetAssociatedClause()}; + bool hasCollapseClause{ + clause ? (clause->Id() == llvm::omp::OMPC_collapse) : false}; + const auto &outer{std::get>(x.t)}; if (outer.has_value()) { for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) { + if (loop->IsDoConcurrent()) { + // DO CONCURRENT is explicitly allowed for the LOOP construct so long as + // there isn't a COLLAPSE clause + if (isLoopConstruct) { + if (hasCollapseClause) { + // hasCollapseClause implies clause != nullptr + context_.Say(clause->source, + "DO CONCURRENT loops cannot be used with the COLLAPSE clause."_err_en_US); + } + } else { + auto &stmt = + std::get>(loop->t); + context_.Say(stmt.source, + "DO CONCURRENT loops cannot form part of a loop nest."_err_en_US); + } + } // go through all the nested do-loops and resolve index variables const parser::Name *iv{GetLoopIndex(*loop)}; if (iv) { @@ -2003,6 +2032,12 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) { return true; } +bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionConstruct &x) { + PushContext(x.source, llvm::omp::Directive::OMPD_section); + GetContext().withinConstruct = true; + return true; +} + bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) { const auto &beginCriticalDir{std::get(x.t)}; const auto &endCriticalDir{std::get(x.t)}; @@ -2073,7 +2108,8 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPDispatchConstruct &x) { } bool OmpAttributeVisitor::Pre(const parser::OpenMPExecutableAllocate &x) { - IssueNonConformanceWarning(llvm::omp::Directive::OMPD_allocate, x.source); + IssueNonConformanceWarning(llvm::omp::Directive::OMPD_allocate, x.source, 52); + PushContext(x.source, llvm::omp::Directive::OMPD_allocate); const auto &list{std::get>(x.t)}; if (list) { @@ -3023,10 +3059,19 @@ void OmpAttributeVisitor::CheckSourceLabel(const parser::Label &label) { void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source, const parser::CharBlock target, std::optional sourceContext, std::optional targetContext) { + auto dirContextsSame = [](DirContext &lhs, DirContext &rhs) -> bool { + // Sometimes nested constructs share a scope but are different contexts. + // The directiveSource comparison is for OmpSection. Sections do not have + // their own scopes and two different sections both have the same directive. + // Their source however is different. This string comparison is unfortunate + // but should only happen for GOTOs inside of SECTION. + return (lhs.scope == rhs.scope) && (lhs.directive == rhs.directive) && + (lhs.directiveSource == rhs.directiveSource); + }; unsigned version{context_.langOptions().OpenMPVersion}; if (targetContext && (!sourceContext || - (sourceContext->scope != targetContext->scope && + (!dirContextsSame(*targetContext, *sourceContext) && !DoesScopeContain( &targetContext->scope, sourceContext->scope)))) { context_ @@ -3038,7 +3083,7 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source, } if (sourceContext && (!targetContext || - (sourceContext->scope != targetContext->scope && + (!dirContextsSame(*sourceContext, *targetContext) && !DoesScopeContain( &sourceContext->scope, targetContext->scope)))) { context_ @@ -3128,11 +3173,16 @@ void OmpAttributeVisitor::AddOmpRequiresToScope(Scope &scope, } while (!scopeIter->IsGlobal()); } -void OmpAttributeVisitor::IssueNonConformanceWarning( - llvm::omp::Directive D, parser::CharBlock source) { +void OmpAttributeVisitor::IssueNonConformanceWarning(llvm::omp::Directive D, + parser::CharBlock source, unsigned EmitFromVersion) { std::string warnStr; llvm::raw_string_ostream warnStrOS(warnStr); unsigned version{context_.langOptions().OpenMPVersion}; + // We only want to emit the warning when the version being used has the + // directive deprecated + if (version < EmitFromVersion) { + return; + } warnStrOS << "OpenMP directive " << parser::ToUpperCaseLetters( llvm::omp::getOpenMPDirectiveName(D, version).str()) diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 7db447aee002..9e465f8ff3e1 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1729,7 +1729,6 @@ bool OmpVisitor::NeedsScope(const parser::OpenMPBlockConstruct &x) { switch (beginDir.v) { case llvm::omp::Directive::OMPD_master: case llvm::omp::Directive::OMPD_ordered: - case llvm::omp::Directive::OMPD_taskgroup: return false; default: return true; @@ -1801,9 +1800,9 @@ void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec, Walk(std::get(spec.t)); auto &varName{std::get(spec.t)}; DeclareObjectEntity(varName); + EndDeclTypeSpec(); Walk(clauses); - EndDeclTypeSpec(); PopScope(); } @@ -2828,6 +2827,16 @@ Scope &ScopeHandler::NonDerivedTypeScope() { return currScope_->IsDerivedType() ? currScope_->parent() : *currScope_; } +static void SetImplicitCUDADevice(Symbol &symbol) { + if (auto *object{symbol.detailsIf()}) { + if (!object->cudaDataAttr() && !IsValue(symbol) && + !IsFunctionResult(symbol)) { + // Implicitly set device attribute if none is set in device context. + object->set_cudaDataAttr(common::CUDADataAttr::Device); + } + } +} + void ScopeHandler::PushScope(Scope::Kind kind, Symbol *symbol) { PushScope(currScope().MakeScope(kind, symbol)); } @@ -2867,9 +2876,35 @@ void ScopeHandler::PopScope() { // Entities that are not yet classified as objects or procedures are now // assumed to be objects. // TODO: Statement functions + bool inDeviceSubprogram{false}; + const Symbol *scopeSym{currScope().GetSymbol()}; + if (currScope().kind() == Scope::Kind::BlockConstruct) { + scopeSym = GetProgramUnitContaining(currScope()).GetSymbol(); + } + if (scopeSym) { + if (auto *details{scopeSym->detailsIf()}) { + // Check the current procedure is a device procedure to apply implicit + // attribute at the end. + if (auto attrs{details->cudaSubprogramAttrs()}) { + if (*attrs == common::CUDASubprogramAttrs::Device || + *attrs == common::CUDASubprogramAttrs::Global || + *attrs == common::CUDASubprogramAttrs::Grid_Global) { + inDeviceSubprogram = true; + } + } + } + } for (auto &pair : currScope()) { ConvertToObjectEntity(*pair.second); } + + // Apply CUDA device attributes if in a device subprogram + if (inDeviceSubprogram && currScope().kind() == Scope::Kind::BlockConstruct) { + for (auto &pair : currScope()) { + SetImplicitCUDADevice(*pair.second); + } + } + funcResultStack_.Pop(); // If popping back into a global scope, pop back to the top scope. Scope *hermetic{context().currentHermeticModuleFileScope()}; @@ -9555,40 +9590,11 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) { info.Resolve(&MakeSymbol(symbolName, Attrs{}, std::move(genericDetails))); } -static void SetImplicitCUDADevice(bool inDeviceSubprogram, Symbol &symbol) { - if (inDeviceSubprogram && symbol.has()) { - auto *object{symbol.detailsIf()}; - if (!object->cudaDataAttr() && !IsValue(symbol) && - !IsFunctionResult(symbol)) { - // Implicitly set device attribute if none is set in device context. - object->set_cudaDataAttr(common::CUDADataAttr::Device); - } - } -} - void ResolveNamesVisitor::FinishSpecificationPart( const std::list &decls) { misparsedStmtFuncFound_ = false; funcResultStack().CompleteFunctionResultType(); CheckImports(); - bool inDeviceSubprogram{false}; - Symbol *scopeSym{currScope().symbol()}; - if (currScope().kind() == Scope::Kind::BlockConstruct) { - scopeSym = currScope().parent().symbol(); - } - if (scopeSym) { - if (auto *details{scopeSym->detailsIf()}) { - // Check the current procedure is a device procedure to apply implicit - // attribute at the end. - if (auto attrs{details->cudaSubprogramAttrs()}) { - if (*attrs == common::CUDASubprogramAttrs::Device || - *attrs == common::CUDASubprogramAttrs::Global || - *attrs == common::CUDASubprogramAttrs::Grid_Global) { - inDeviceSubprogram = true; - } - } - } - } for (auto &pair : currScope()) { auto &symbol{*pair.second}; if (inInterfaceBlock()) { @@ -9623,11 +9629,6 @@ void ResolveNamesVisitor::FinishSpecificationPart( SetBindNameOn(symbol); } } - if (currScope().kind() == Scope::Kind::BlockConstruct) { - // Only look for specification in BlockConstruct. Other cases are done in - // ResolveSpecificationParts. - SetImplicitCUDADevice(inDeviceSubprogram, symbol); - } } currScope().InstantiateDerivedTypes(); for (const auto &decl : decls) { @@ -10187,7 +10188,9 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) { } ApplyImplicitRules(symbol); // Apply CUDA implicit attributes if needed. - SetImplicitCUDADevice(inDeviceSubprogram, symbol); + if (inDeviceSubprogram) { + SetImplicitCUDADevice(symbol); + } // Main program local objects usually don't have an implied SAVE attribute, // as one might think, but in the exceptional case of a derived type // local object that contains a coarray, we have to mark it as an diff --git a/flang/lib/Semantics/rewrite-directives.cpp b/flang/lib/Semantics/rewrite-directives.cpp deleted file mode 100644 index b4fef2c881b6..000000000000 --- a/flang/lib/Semantics/rewrite-directives.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//===-- lib/Semantics/rewrite-directives.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "rewrite-directives.h" -#include "flang/Parser/parse-tree-visitor.h" -#include "flang/Parser/parse-tree.h" -#include "flang/Semantics/semantics.h" -#include "flang/Semantics/symbol.h" -#include "llvm/Frontend/OpenMP/OMP.h" -#include - -namespace Fortran::semantics { - -using namespace parser::literals; - -class DirectiveRewriteMutator { -public: - explicit DirectiveRewriteMutator(SemanticsContext &context) - : context_{context} {} - - // Default action for a parse tree node is to visit children. - template bool Pre(T &) { return true; } - template void Post(T &) {} - -protected: - SemanticsContext &context_; -}; - -// Rewrite atomic constructs to add an explicit memory ordering to all that do -// not specify it, honoring in this way the `atomic_default_mem_order` clause of -// the REQUIRES directive. -class OmpRewriteMutator : public DirectiveRewriteMutator { -public: - explicit OmpRewriteMutator(SemanticsContext &context) - : DirectiveRewriteMutator(context) {} - - template bool Pre(T &) { return true; } - template void Post(T &) {} - - bool Pre(parser::OpenMPAtomicConstruct &); - bool Pre(parser::OpenMPRequiresConstruct &); - -private: - bool atomicDirectiveDefaultOrderFound_{false}; -}; - -bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) { - // Find top-level parent of the operation. - Symbol *topLevelParent{[&]() { - Symbol *symbol{nullptr}; - Scope *scope{&context_.FindScope( - std::get(x.t).source)}; - do { - if (Symbol * parent{scope->symbol()}) { - symbol = parent; - } - scope = &scope->parent(); - } while (!scope->IsGlobal()); - - assert(symbol && - "Atomic construct must be within a scope associated with a symbol"); - return symbol; - }()}; - - // Get the `atomic_default_mem_order` clause from the top-level parent. - std::optional defaultMemOrder; - common::visit( - [&](auto &details) { - if constexpr (std::is_convertible_v) { - if (details.has_ompAtomicDefaultMemOrder()) { - defaultMemOrder = *details.ompAtomicDefaultMemOrder(); - } - } - }, - topLevelParent->details()); - - if (!defaultMemOrder) { - return false; - } - - auto findMemOrderClause{[](const parser::OmpClauseList &clauses) { - return llvm::any_of( - clauses.v, [](auto &clause) -> const parser::OmpClause * { - switch (clause.Id()) { - case llvm::omp::Clause::OMPC_acq_rel: - case llvm::omp::Clause::OMPC_acquire: - case llvm::omp::Clause::OMPC_relaxed: - case llvm::omp::Clause::OMPC_release: - case llvm::omp::Clause::OMPC_seq_cst: - return &clause; - default: - return nullptr; - } - }); - }}; - - auto &dirSpec{std::get(x.t)}; - auto &clauseList{std::get>(dirSpec.t)}; - if (clauseList) { - if (findMemOrderClause(*clauseList)) { - return false; - } - } else { - clauseList = parser::OmpClauseList(decltype(parser::OmpClauseList::v){}); - } - - // Add a memory order clause to the atomic directive. - atomicDirectiveDefaultOrderFound_ = true; - switch (*defaultMemOrder) { - case common::OmpMemoryOrderType::Acq_Rel: - clauseList->v.emplace_back(parser::OmpClause{parser::OmpClause::AcqRel{}}); - break; - case common::OmpMemoryOrderType::Relaxed: - clauseList->v.emplace_back(parser::OmpClause{parser::OmpClause::Relaxed{}}); - break; - case common::OmpMemoryOrderType::Seq_Cst: - clauseList->v.emplace_back(parser::OmpClause{parser::OmpClause::SeqCst{}}); - break; - default: - // FIXME: Don't process other values at the moment since their validity - // depends on the OpenMP version (which is unavailable here). - break; - } - - return false; -} - -bool OmpRewriteMutator::Pre(parser::OpenMPRequiresConstruct &x) { - for (parser::OmpClause &clause : std::get(x.t).v) { - if (std::holds_alternative( - clause.u) && - atomicDirectiveDefaultOrderFound_) { - context_.Say(clause.source, - "REQUIRES directive with '%s' clause found lexically after atomic " - "operation without a memory order clause"_err_en_US, - parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName( - llvm::omp::OMPC_atomic_default_mem_order) - .str())); - } - } - return false; -} - -bool RewriteOmpParts(SemanticsContext &context, parser::Program &program) { - if (!context.IsEnabled(common::LanguageFeature::OpenMP)) { - return true; - } - OmpRewriteMutator ompMutator{context}; - parser::Walk(program, ompMutator); - return !context.AnyFatalError(); -} - -} // namespace Fortran::semantics diff --git a/flang/lib/Semantics/rewrite-directives.h b/flang/lib/Semantics/rewrite-directives.h deleted file mode 100644 index 675962192842..000000000000 --- a/flang/lib/Semantics/rewrite-directives.h +++ /dev/null @@ -1,24 +0,0 @@ -//===-- lib/Semantics/rewrite-directives.h ----------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef FORTRAN_SEMANTICS_REWRITE_DIRECTIVES_H_ -#define FORTRAN_SEMANTICS_REWRITE_DIRECTIVES_H_ - -namespace Fortran::parser { -struct Program; -} // namespace Fortran::parser - -namespace Fortran::semantics { -class SemanticsContext; -} // namespace Fortran::semantics - -namespace Fortran::semantics { -bool RewriteOmpParts(SemanticsContext &, parser::Program &); -} // namespace Fortran::semantics - -#endif // FORTRAN_SEMANTICS_REWRITE_DIRECTIVES_H_ diff --git a/flang/lib/Semantics/rewrite-parse-tree.cpp b/flang/lib/Semantics/rewrite-parse-tree.cpp index 577558e7e33b..4eeb1b9ed3c1 100644 --- a/flang/lib/Semantics/rewrite-parse-tree.cpp +++ b/flang/lib/Semantics/rewrite-parse-tree.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "rewrite-parse-tree.h" -#include "rewrite-directives.h" + #include "flang/Common/indirection.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/parse-tree.h" @@ -229,7 +229,7 @@ void RewriteMutator::Post(parser::WriteStmt &x) { bool RewriteParseTree(SemanticsContext &context, parser::Program &program) { RewriteMutator mutator{context}; parser::Walk(program, mutator); - return !context.AnyFatalError() && RewriteOmpParts(context, program); + return !context.AnyFatalError(); } } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index 26ae81f97895..51ba21a9e5ed 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -82,17 +82,17 @@ private: const SomeExpr &genre, std::int64_t = 0) const; SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const; std::vector DescribeBindings( - const Scope &dtScope, Scope &); + const Scope &dtScope, Scope &, const SymbolVector &bindings); std::map DescribeSpecialGenerics( - const Scope &dtScope, const Scope &thisScope, - const DerivedTypeSpec *) const; + const Scope &dtScope, const Scope &thisScope, const DerivedTypeSpec *, + const SymbolVector &bindings) const; void DescribeSpecialGeneric(const GenericDetails &, std::map &, const Scope &, - const DerivedTypeSpec *) const; + const DerivedTypeSpec *, const SymbolVector &bindings) const; void DescribeSpecialProc(std::map &, const Symbol &specificOrBinding, bool isAssignment, bool isFinal, std::optional, const Scope *, const DerivedTypeSpec *, - bool isTypeBound) const; + const SymbolVector *bindings) const; void IncorporateDefinedIoGenericInterfaces( std::map &, common::DefinedIo, const Scope *, const DerivedTypeSpec *); @@ -595,8 +595,9 @@ const Symbol *RuntimeTableBuilder::DescribeType( // Compile the "vtable" of type-bound procedure bindings std::uint32_t specialBitSet{0}; if (!dtSymbol->attrs().test(Attr::ABSTRACT)) { + SymbolVector boundProcedures{CollectBindings(dtScope)}; std::vector bindings{ - DescribeBindings(dtScope, scope)}; + DescribeBindings(dtScope, scope, boundProcedures)}; AddValue(dtValues, derivedTypeSchema_, bindingDescCompName, SaveDerivedPointerTarget(scope, SaveObjectName( @@ -609,12 +610,14 @@ const Symbol *RuntimeTableBuilder::DescribeType( // subroutines override any parent bindings, but FINAL subroutines do not // (the runtime will call all of them). std::map specials{ - DescribeSpecialGenerics(dtScope, dtScope, derivedTypeSpec)}; + DescribeSpecialGenerics( + dtScope, dtScope, derivedTypeSpec, boundProcedures)}; if (derivedTypeSpec) { - for (auto &ref : FinalsForDerivedTypeInstantiation(*derivedTypeSpec)) { - DescribeSpecialProc(specials, *ref, /*isAssignment-*/ false, + for (const Symbol &symbol : + FinalsForDerivedTypeInstantiation(*derivedTypeSpec)) { + DescribeSpecialProc(specials, symbol, /*isAssignment-*/ false, /*isFinal=*/true, std::nullopt, nullptr, derivedTypeSpec, - /*isTypeBound=*/true); + &boundProcedures); } IncorporateDefinedIoGenericInterfaces(specials, common::DefinedIo::ReadFormatted, &scope, derivedTypeSpec); @@ -661,6 +664,10 @@ const Symbol *RuntimeTableBuilder::DescribeType( AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s, IntExpr<1>( derivedTypeSpec && !MayRequireFinalization(*derivedTypeSpec))); + // Similarly, a flag to enable optimized runtime assignment. + AddValue(dtValues, derivedTypeSchema_, "nodefinedassignment"s, + IntExpr<1>( + derivedTypeSpec && !MayHaveDefinedAssignment(*derivedTypeSpec))); } dtObject.get().set_init(MaybeExpr{ StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))}); @@ -1041,15 +1048,16 @@ SymbolVector CollectBindings(const Scope &dtScope) { } std::vector -RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) { +RuntimeTableBuilder::DescribeBindings( + const Scope &dtScope, Scope &scope, const SymbolVector &bindings) { std::vector result; - for (const SymbolRef &ref : CollectBindings(dtScope)) { + for (const Symbol &symbol : bindings) { evaluate::StructureConstructorValues values; AddValue(values, bindingSchema_, procCompName, SomeExpr{evaluate::ProcedureDesignator{ - ref.get().get().symbol()}}); + symbol.get().symbol()}}); AddValue(values, bindingSchema_, "name"s, - SaveNameAsPointerTarget(scope, ref.get().name().ToString())); + SaveNameAsPointerTarget(scope, symbol.name().ToString())); result.emplace_back(DEREF(bindingSchema_.AsDerived()), std::move(values)); } return result; @@ -1057,16 +1065,18 @@ RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) { std::map RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope, - const Scope &thisScope, const DerivedTypeSpec *derivedTypeSpec) const { + const Scope &thisScope, const DerivedTypeSpec *derivedTypeSpec, + const SymbolVector &bindings) const { std::map specials; if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) { - specials = - DescribeSpecialGenerics(*parentScope, thisScope, derivedTypeSpec); + specials = DescribeSpecialGenerics( + *parentScope, thisScope, derivedTypeSpec, bindings); } for (const auto &pair : dtScope) { const Symbol &symbol{*pair.second}; if (const auto *generic{symbol.detailsIf()}) { - DescribeSpecialGeneric(*generic, specials, thisScope, derivedTypeSpec); + DescribeSpecialGeneric( + *generic, specials, thisScope, derivedTypeSpec, bindings); } } return specials; @@ -1074,15 +1084,16 @@ RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope, void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic, std::map &specials, - const Scope &dtScope, const DerivedTypeSpec *derivedTypeSpec) const { + const Scope &dtScope, const DerivedTypeSpec *derivedTypeSpec, + const SymbolVector &bindings) const { common::visit( common::visitors{ [&](const GenericKind::OtherKind &k) { if (k == GenericKind::OtherKind::Assignment) { - for (auto ref : generic.specificProcs()) { - DescribeSpecialProc(specials, *ref, /*isAssignment=*/true, + for (const Symbol &specific : generic.specificProcs()) { + DescribeSpecialProc(specials, specific, /*isAssignment=*/true, /*isFinal=*/false, std::nullopt, &dtScope, derivedTypeSpec, - /*isTypeBound=*/true); + &bindings); } } }, @@ -1092,10 +1103,10 @@ void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic, case common::DefinedIo::ReadUnformatted: case common::DefinedIo::WriteFormatted: case common::DefinedIo::WriteUnformatted: - for (auto ref : generic.specificProcs()) { - DescribeSpecialProc(specials, *ref, /*isAssignment=*/false, + for (const Symbol &specific : generic.specificProcs()) { + DescribeSpecialProc(specials, specific, /*isAssignment=*/false, /*isFinal=*/false, io, &dtScope, derivedTypeSpec, - /*isTypeBound=*/true); + &bindings); } break; } @@ -1109,7 +1120,8 @@ void RuntimeTableBuilder::DescribeSpecialProc( std::map &specials, const Symbol &specificOrBinding, bool isAssignment, bool isFinal, std::optional io, const Scope *dtScope, - const DerivedTypeSpec *derivedTypeSpec, bool isTypeBound) const { + const DerivedTypeSpec *derivedTypeSpec, + const SymbolVector *bindings) const { const auto *binding{specificOrBinding.detailsIf()}; if (binding && dtScope) { // use most recent override binding = &DEREF(dtScope->FindComponent(specificOrBinding.name())) @@ -1128,6 +1140,9 @@ void RuntimeTableBuilder::DescribeSpecialProc( // component assignment as part of intrinsic assignment. // Non-type-bound generic INTERFACEs and assignments from incompatible // types must not be used for component intrinsic assignment. + if (!binding) { + return; + } CHECK(proc->dummyArguments.size() == 2); const auto t1{ DEREF(std::get_if( @@ -1137,7 +1152,7 @@ void RuntimeTableBuilder::DescribeSpecialProc( DEREF(std::get_if( &proc->dummyArguments[1].u)) .type.type()}; - if (!binding || t1.category() != TypeCategory::Derived || + if (t1.category() != TypeCategory::Derived || t2.category() != TypeCategory::Derived || t1.IsUnlimitedPolymorphic() || t2.IsUnlimitedPolymorphic()) { return; @@ -1149,7 +1164,7 @@ void RuntimeTableBuilder::DescribeSpecialProc( } which = proc->IsElemental() ? elementalAssignmentEnum_ : scalarAssignmentEnum_; - if (binding && binding->passName() && + if (binding->passName() && *binding->passName() == proc->dummyArguments[1].name) { argThatMightBeDescriptor = 1; isArgDescriptorSet |= 2; @@ -1234,8 +1249,19 @@ void RuntimeTableBuilder::DescribeSpecialProc( values, specialSchema_, "which"s, SomeExpr{std::move(which.value())}); AddValue(values, specialSchema_, "isargdescriptorset"s, IntExpr<1>(isArgDescriptorSet)); - AddValue(values, specialSchema_, "istypebound"s, - IntExpr<1>(isTypeBound ? 1 : 0)); + int bindingIndex{0}; + if (bindings) { + int j{0}; + for (const Symbol &bind : DEREF(bindings)) { + ++j; + if (&bind.get().symbol() == &specific) { + bindingIndex = j; // index offset by 1 + break; + } + } + } + CHECK(bindingIndex <= 255); + AddValue(values, specialSchema_, "istypebound"s, IntExpr<1>(bindingIndex)); AddValue(values, specialSchema_, "isargcontiguousset"s, IntExpr<1>(isArgContiguousSet)); AddValue(values, specialSchema_, procCompName, @@ -1260,7 +1286,7 @@ void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces( CHECK(std::get(genericDetails.kind().u) == definedIo); for (auto ref : genericDetails.specificProcs()) { DescribeSpecialProc(specials, *ref, false, false, definedIo, nullptr, - derivedTypeSpec, false); + derivedTypeSpec, /*bindings=*/nullptr); } } } diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp index a1445187b1e9..d053179448c0 100644 --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -17,7 +17,6 @@ #include "flang/Semantics/tools.h" #include "flang/Semantics/type.h" #include "flang/Support/Fortran.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -814,6 +813,38 @@ bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived) { return std::any_of(directs.begin(), directs.end(), IsAllocatable); } +static bool MayHaveDefinedAssignment( + const DerivedTypeSpec &derived, std::set &checked) { + if (const Scope *scope{derived.GetScope()}; + scope && checked.find(scope) == checked.end()) { + checked.insert(scope); + for (const auto &[_, symbolRef] : *scope) { + if (const auto *generic{symbolRef->detailsIf()}) { + if (generic->kind().IsAssignment()) { + return true; + } + } else if (symbolRef->has() && + !IsPointer(*symbolRef)) { + if (const DeclTypeSpec *type{symbolRef->GetType()}) { + if (type->IsPolymorphic()) { + return true; + } else if (const DerivedTypeSpec *derived{type->AsDerived()}) { + if (MayHaveDefinedAssignment(*derived, checked)) { + return true; + } + } + } + } + } + } + return false; +} + +bool MayHaveDefinedAssignment(const DerivedTypeSpec &derived) { + std::set checked; + return MayHaveDefinedAssignment(derived, checked); +} + bool IsAssumedLengthCharacter(const Symbol &symbol) { if (const DeclTypeSpec * type{symbol.GetType()}) { return type->category() == DeclTypeSpec::Character && @@ -1757,332 +1788,4 @@ bool HadUseError( } } -bool CheckForSymbolMatch(const SomeExpr *lhs, const SomeExpr *rhs) { - if (lhs && rhs) { - if (SymbolVector lhsSymbols{evaluate::GetSymbolVector(*lhs)}; - !lhsSymbols.empty()) { - const Symbol &first{*lhsSymbols.front()}; - for (const Symbol &symbol : evaluate::GetSymbolVector(*rhs)) { - if (first == symbol) { - return true; - } - } - } - } - return false; -} - -namespace operation { -template // -SomeExpr asSomeExpr(const T &x) { - auto copy{x}; - return AsGenericExpr(std::move(copy)); -} - -template // -struct ArgumentExtractor - : public evaluate::Traverse, - std::pair>, false> { - using Arguments = std::vector; - using Result = std::pair; - using Base = evaluate::Traverse, - Result, false>; - static constexpr auto IgnoreResizes = IgnoreResizingConverts; - static constexpr auto Logical = common::TypeCategory::Logical; - ArgumentExtractor() : Base(*this) {} - - Result Default() const { return {}; } - - using Base::operator(); - - template // - Result operator()( - const evaluate::Constant> &x) const { - if (const auto &val{x.GetScalarValue()}) { - return val->IsTrue() - ? std::make_pair(operation::Operator::True, Arguments{}) - : std::make_pair(operation::Operator::False, Arguments{}); - } - return Default(); - } - - template // - Result operator()(const evaluate::FunctionRef &x) const { - Result result{operation::OperationCode(x.proc()), {}}; - for (size_t i{0}, e{x.arguments().size()}; i != e; ++i) { - if (auto *e{x.UnwrapArgExpr(i)}) { - result.second.push_back(*e); - } - } - return result; - } - - template - Result operator()(const evaluate::Operation &x) const { - if constexpr (std::is_same_v>) { - // Ignore top-level parentheses. - return (*this)(x.template operand<0>()); - } - if constexpr (IgnoreResizes && - std::is_same_v>) { - // Ignore conversions within the same category. - // Atomic operations on int(kind=1) may be implicitly widened - // to int(kind=4) for example. - return (*this)(x.template operand<0>()); - } else { - return std::make_pair(operation::OperationCode(x), - OperationArgs(x, std::index_sequence_for{})); - } - } - - template // - Result operator()(const evaluate::Designator &x) const { - return {operation::Operator::Identity, {asSomeExpr(x)}}; - } - - template // - Result operator()(const evaluate::Constant &x) const { - return {operation::Operator::Identity, {asSomeExpr(x)}}; - } - - template // - Result Combine(Result &&result, Rs &&...results) const { - // There shouldn't be any combining needed, since we're stopping the - // traversal at the top-level operation, but implement one that picks - // the first non-empty result. - if constexpr (sizeof...(Rs) == 0) { - return std::move(result); - } else { - if (!result.second.empty()) { - return std::move(result); - } else { - return Combine(std::move(results)...); - } - } - } - -private: - template - Arguments OperationArgs(const evaluate::Operation &x, - std::index_sequence) const { - return Arguments{SomeExpr(x.template operand())...}; - } -}; -} // namespace operation - -std::string operation::ToString(operation::Operator op) { - switch (op) { - case Operator::Unknown: - return "??"; - case Operator::Add: - return "+"; - case Operator::And: - return "AND"; - case Operator::Associated: - return "ASSOCIATED"; - case Operator::Call: - return "function-call"; - case Operator::Constant: - return "constant"; - case Operator::Convert: - return "type-conversion"; - case Operator::Div: - return "/"; - case Operator::Eq: - return "=="; - case Operator::Eqv: - return "EQV"; - case Operator::False: - return ".FALSE."; - case Operator::Ge: - return ">="; - case Operator::Gt: - return ">"; - case Operator::Identity: - return "identity"; - case Operator::Intrinsic: - return "intrinsic"; - case Operator::Le: - return "<="; - case Operator::Lt: - return "<"; - case Operator::Max: - return "MAX"; - case Operator::Min: - return "MIN"; - case Operator::Mul: - return "*"; - case Operator::Ne: - return "/="; - case Operator::Neqv: - return "NEQV/EOR"; - case Operator::Not: - return "NOT"; - case Operator::Or: - return "OR"; - case Operator::Pow: - return "**"; - case Operator::Resize: - return "resize"; - case Operator::Sub: - return "-"; - case Operator::True: - return ".TRUE."; - } - llvm_unreachable("Unhandler operator"); -} - -operation::Operator operation::OperationCode( - const evaluate::ProcedureDesignator &proc) { - Operator code = llvm::StringSwitch(proc.GetName()) - .Case("associated", Operator::Associated) - .Case("min", Operator::Min) - .Case("max", Operator::Max) - .Case("iand", Operator::And) - .Case("ior", Operator::Or) - .Case("ieor", Operator::Neqv) - .Default(Operator::Call); - if (code == Operator::Call && proc.GetSpecificIntrinsic()) { - return Operator::Intrinsic; - } - return code; -} - -std::pair> GetTopLevelOperation( - const SomeExpr &expr) { - return operation::ArgumentExtractor{}(expr); -} - -namespace operation { -struct ConvertCollector - : public evaluate::Traverse>, false> { - using Result = std::pair>; - using Base = evaluate::Traverse; - ConvertCollector() : Base(*this) {} - - Result Default() const { return {}; } - - using Base::operator(); - - template // - Result operator()(const evaluate::Designator &x) const { - return {asSomeExpr(x), {}}; - } - - template // - Result operator()(const evaluate::FunctionRef &x) const { - return {asSomeExpr(x), {}}; - } - - template // - Result operator()(const evaluate::Constant &x) const { - return {asSomeExpr(x), {}}; - } - - template - Result operator()(const evaluate::Operation &x) const { - if constexpr (std::is_same_v>) { - // Ignore parentheses. - return (*this)(x.template operand<0>()); - } else if constexpr (is_convert_v) { - // Convert should always have a typed result, so it should be safe to - // dereference x.GetType(). - return Combine( - {std::nullopt, {*x.GetType()}}, (*this)(x.template operand<0>())); - } else if constexpr (is_complex_constructor_v) { - // This is a conversion iff the imaginary operand is 0. - if (IsZero(x.template operand<1>())) { - return Combine( - {std::nullopt, {*x.GetType()}}, (*this)(x.template operand<0>())); - } else { - return {asSomeExpr(x.derived()), {}}; - } - } else { - return {asSomeExpr(x.derived()), {}}; - } - } - - template // - Result Combine(Result &&result, Rs &&...results) const { - Result v(std::move(result)); - auto setValue{[](MaybeExpr &x, MaybeExpr &&y) { - assert((!x.has_value() || !y.has_value()) && "Multiple designators"); - if (!x.has_value()) { - x = std::move(y); - } - }}; - auto moveAppend{[](auto &accum, auto &&other) { - for (auto &&s : other) { - accum.push_back(std::move(s)); - } - }}; - (setValue(v.first, std::move(results).first), ...); - (moveAppend(v.second, std::move(results).second), ...); - return v; - } - -private: - template // - static bool IsZero(const T &x) { - return false; - } - template // - static bool IsZero(const evaluate::Expr &x) { - return common::visit([](auto &&s) { return IsZero(s); }, x.u); - } - template // - static bool IsZero(const evaluate::Constant &x) { - if (auto &&maybeScalar{x.GetScalarValue()}) { - return maybeScalar->IsZero(); - } else { - return false; - } - } - - template // - struct is_convert { - static constexpr bool value{false}; - }; - template // - struct is_convert> { - static constexpr bool value{true}; - }; - template // - struct is_convert> { - // Conversion from complex to real. - static constexpr bool value{true}; - }; - template // - static constexpr bool is_convert_v = is_convert::value; - - template // - struct is_complex_constructor { - static constexpr bool value{false}; - }; - template // - struct is_complex_constructor> { - static constexpr bool value{true}; - }; - template // - static constexpr bool is_complex_constructor_v = - is_complex_constructor::value; -}; -} // namespace operation - -MaybeExpr GetConvertInput(const SomeExpr &x) { - // This returns SomeExpr(x) when x is a designator/functionref/constant. - return operation::ConvertCollector{}(x).first; -} - -bool IsSameOrConvertOf(const SomeExpr &expr, const SomeExpr &x) { - // Check if expr is same as x, or a sequence of Convert operations on x. - if (expr == x) { - return true; - } else if (auto maybe{GetConvertInput(expr)}) { - return *maybe == x; - } else { - return false; - } -} } // namespace Fortran::semantics \ No newline at end of file diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp index 08ded173de51..17b5f8368916 100644 --- a/flang/lib/Support/Fortran-features.cpp +++ b/flang/lib/Support/Fortran-features.cpp @@ -151,22 +151,23 @@ LanguageFeatureControl::LanguageFeatureControl() { warnLanguage_.set(LanguageFeature::NullActualForAllocatable); } -// Take a string from the Cli and apply it to the LanguageFeatureControl. -bool LanguageFeatureControl::ApplyCliOption(std::string input) { +std::optional LanguageFeatureControl::FindWarning( + std::string_view input) { bool negated{false}; if (input.size() > 3 && input.substr(0, 3) == "no-") { negated = true; input = input.substr(3); } - if (auto it{cliOptions_.find(input)}; it != cliOptions_.end()) { - if (std::holds_alternative(it->second)) { - EnableWarning(std::get(it->second), !negated); - return true; - } - if (std::holds_alternative(it->second)) { - EnableWarning(std::get(it->second), !negated); - return true; - } + if (auto it{cliOptions_.find(std::string{input})}; it != cliOptions_.end()) { + return std::make_pair(it->second, !negated); + } + return std::nullopt; +} + +bool LanguageFeatureControl::EnableWarning(std::string_view input) { + if (auto warningAndEnabled{FindWarning(input)}) { + EnableWarning(warningAndEnabled->first, warningAndEnabled->second); + return true; } return false; } diff --git a/flang/module/__fortran_type_info.f90 b/flang/module/__fortran_type_info.f90 index b30a6bf69756..8dd27d6e4c01 100644 --- a/flang/module/__fortran_type_info.f90 +++ b/flang/module/__fortran_type_info.f90 @@ -52,7 +52,8 @@ module __fortran_type_info integer(1) :: noInitializationNeeded ! 1 if no component w/ init integer(1) :: noDestructionNeeded ! 1 if no component w/ dealloc/final integer(1) :: noFinalizationNeeded ! 1 if nothing finalizeable - integer(1) :: __padding0(4) + integer(1) :: noDefinedAssignment ! 1 if no defined ASSIGNMENT(=) + integer(1) :: __padding0(3) end type type :: Binding @@ -116,7 +117,7 @@ module __fortran_type_info type, bind(c) :: SpecialBinding integer(1) :: which ! SpecialBinding::Which integer(1) :: isArgDescriptorSet - integer(1) :: isTypeBound + integer(1) :: isTypeBound ! binding index + 1, if any integer(1) :: isArgContiguousSet integer(1) :: __padding0(4) type(__builtin_c_funptr) :: proc diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt index a658f6f984fa..8520bec64697 100644 --- a/flang/test/CMakeLists.txt +++ b/flang/test/CMakeLists.txt @@ -73,6 +73,7 @@ if (NOT FLANG_STANDALONE_BUILD) not llvm-dis llvm-objdump + llvm-profdata llvm-readobj split-file ) diff --git a/flang/test/Driver/flang-f-opts.f90 b/flang/test/Driver/flang-f-opts.f90 index 4493a519e201..b972b9b7b2a5 100644 --- a/flang/test/Driver/flang-f-opts.f90 +++ b/flang/test/Driver/flang-f-opts.f90 @@ -8,3 +8,8 @@ ! CHECK-LABEL: "-fc1" ! CHECK: -ffp-contract=off ! CHECK: -O3 + +! RUN: %flang -### -S -fprofile-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-LLVM %s +! CHECK-PROFILE-GENERATE-LLVM: "-fprofile-generate" +! RUN: %flang -### -S -fprofile-use=%S %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-DIR %s +! CHECK-PROFILE-USE-DIR: "-fprofile-use={{.*}}" diff --git a/flang/test/Driver/flang-openmp-version-macro.f90 b/flang/test/Driver/flang-openmp-version-macro.f90 index 95b3071544d0..f690ab381948 100644 --- a/flang/test/Driver/flang-openmp-version-macro.f90 +++ b/flang/test/Driver/flang-openmp-version-macro.f90 @@ -2,7 +2,6 @@ ! RUN: %flang_fc1 -fopenmp -cpp -E %s | FileCheck %s --check-prefix=DEFAULT-OPENMP-VERSION ! RUN: %flang_fc1 -fopenmp -fopenmp-version=11 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-11 -! RUN: %flang_fc1 -fopenmp -fopenmp-version=11 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-11 ! RUN: %flang_fc1 -fopenmp -fopenmp-version=20 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-20 ! RUN: %flang_fc1 -fopenmp -fopenmp-version=25 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-25 ! RUN: %flang_fc1 -fopenmp -fopenmp-version=30 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-30 @@ -12,6 +11,7 @@ ! RUN: %flang_fc1 -fopenmp -fopenmp-version=50 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-50 ! RUN: %flang_fc1 -fopenmp -fopenmp-version=51 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-51 ! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-52 +! RUN: %flang_fc1 -fopenmp -fopenmp-version=60 -cpp -E %s | FileCheck %s --check-prefix=OPENMP-VERSION-60 ! DEFAULT-OPENMP-VERSION: integer :: var1 = 201107 ! OPENMP-VERSION-11: integer :: var1 = 199911 @@ -24,6 +24,7 @@ ! OPENMP-VERSION-50: integer :: var1 = 201811 ! OPENMP-VERSION-51: integer :: var1 = 202011 ! OPENMP-VERSION-52: integer :: var1 = 202111 +! OPENMP-VERSION-60: integer :: var1 = 202411 #if _OPENMP integer :: var1 = _OPENMP diff --git a/flang/test/Fir/boxproc.fir b/flang/test/Fir/boxproc.fir index 5d82522055ad..97d9b38ed6f4 100644 --- a/flang/test/Fir/boxproc.fir +++ b/flang/test/Fir/boxproc.fir @@ -3,7 +3,7 @@ // RUN: %if powerpc-registered-target %{tco --target=powerpc64le-unknown-linux-gnu %s | FileCheck %s --check-prefixes=CHECK,CHECK-PPC %} // CHECK-LABEL: define void @_QPtest_proc_dummy() -// CHECK-AARCH64: %[[VAL_3:.*]] = alloca [36 x i8], i64 1, align 1 +// CHECK-AARCH64: %[[VAL_3:.*]] = alloca [32 x i8], i64 1, align 1 // CHECK-X86: %[[VAL_3:.*]] = alloca [32 x i8], i64 1, align 1 // CHECK-PPC: %[[VAL_3:.*]] = alloca [4{{[0-8]+}} x i8], i64 1, align 1 // CHECK: %[[VAL_1:.*]] = alloca { ptr }, i64 1, align 8 @@ -63,7 +63,7 @@ func.func @_QPtest_proc_dummy_other(%arg0: !fir.boxproc<() -> ()>) { } // CHECK-LABEL: define void @_QPtest_proc_dummy_char() -// CHECK-AARCH64: %[[VAL_20:.*]] = alloca [36 x i8], i64 1, align 1 +// CHECK-AARCH64: %[[VAL_20:.*]] = alloca [32 x i8], i64 1, align 1 // CHECK-X86: %[[VAL_20:.*]] = alloca [32 x i8], i64 1, align 1 // CHECK-PPC: %[[VAL_20:.*]] = alloca [4{{[0-8]+}} x i8], i64 1, align 1 // CHECK: %[[VAL_2:.*]] = alloca { { ptr, i64 } }, i64 1, align 8 diff --git a/flang/test/Fir/cfg-conversion-if.fir b/flang/test/Fir/cfg-conversion-if.fir new file mode 100644 index 000000000000..1e30ee8e64f0 --- /dev/null +++ b/flang/test/Fir/cfg-conversion-if.fir @@ -0,0 +1,46 @@ +// RUN: fir-opt --split-input-file --cfg-conversion %s | FileCheck %s + +func.func private @callee() -> none + +// CHECK-LABEL: func.func @if_then( +// CHECK-SAME: %[[ARG0:.*]]: i1) { +// CHECK: cf.cond_br %[[ARG0]] weights([10, 90]), ^bb1, ^bb2 +// CHECK: ^bb1: +// CHECK: %[[VAL_0:.*]] = fir.call @callee() : () -> none +// CHECK: cf.br ^bb2 +// CHECK: ^bb2: +// CHECK: return +// CHECK: } +func.func @if_then(%cond: i1) { + fir.if %cond weights([10, 90]) { + fir.call @callee() : () -> none + } + return +} + +// ----- + +// CHECK-LABEL: func.func @if_then_else( +// CHECK-SAME: %[[ARG0:.*]]: i1) -> i32 { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32 +// CHECK: cf.cond_br %[[ARG0]] weights([90, 10]), ^bb1, ^bb2 +// CHECK: ^bb1: +// CHECK: cf.br ^bb3(%[[VAL_0]] : i32) +// CHECK: ^bb2: +// CHECK: cf.br ^bb3(%[[VAL_1]] : i32) +// CHECK: ^bb3(%[[VAL_2:.*]]: i32): +// CHECK: cf.br ^bb4 +// CHECK: ^bb4: +// CHECK: return %[[VAL_2]] : i32 +// CHECK: } +func.func @if_then_else(%cond: i1) -> i32 { + %c0 = arith.constant 0 : i32 + %c1 = arith.constant 1 : i32 + %result = fir.if %cond weights([90, 10]) -> i32 { + fir.result %c0 : i32 + } else { + fir.result %c1 : i32 + } + return %result : i32 +} diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index 9c444d2f4e0b..3585bf9efca3 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -1015,3 +1015,19 @@ func.func @test_box_total_elements(%arg0: !fir.class> %6 = arith.addi %2, %5 : index return %6 : index } + +// CHECK-LABEL: func.func @test_if_weights( +// CHECK-SAME: %[[ARG0:.*]]: i1) { +func.func @test_if_weights(%cond: i1) { +// CHECK: fir.if %[[ARG0]] weights([99, 1]) { +// CHECK: } + fir.if %cond weights([99, 1]) { + } +// CHECK: fir.if %[[ARG0]] weights([99, 1]) { +// CHECK: } else { +// CHECK: } + fir.if %cond weights ([99,1]) { + } else { + } + return +} diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index 45cae1f82cb8..aca0ecc1abdc 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -1393,3 +1393,31 @@ fir.local {type = local_init} @x.localizer : f32 init { ^bb0(%arg0: f32, %arg1: f32): fir.yield(%arg0 : f32) } + +// ----- + +func.func @wrong_weights_number_in_if_then(%cond: i1) { +// expected-error @below {{expects number of region weights to match number of regions: 1 vs 2}} + fir.if %cond weights([50]) { + } + return +} + +// ----- + +func.func @wrong_weights_number_in_if_then_else(%cond: i1) { +// expected-error @below {{expects number of region weights to match number of regions: 3 vs 2}} + fir.if %cond weights([50, 40, 10]) { + } else { + } + return +} + +// ----- + +func.func @negative_weight_in_if_then(%cond: i1) { +// expected-error @below {{weight #0 must be non-negative}} + fir.if %cond weights([-1, 101]) { + } + return +} diff --git a/flang/test/Fir/local.fir b/flang/test/Fir/local.fir new file mode 100644 index 000000000000..006f5ca94467 --- /dev/null +++ b/flang/test/Fir/local.fir @@ -0,0 +1,10 @@ +// RUN: fir-opt --fir-to-llvm-ir %s | FileCheck %s + +// Tests that `fir.local` ops are dropped from the module before LLVM lowering. + +fir.local {type = local} @local_privatizer : i32 +func.func @foo() { + return +} + +// CHECK-NOT: fir.local diff --git a/flang/test/HLFIR/fir-local-alloca-block.fir b/flang/test/HLFIR/fir-local-alloca-block.fir new file mode 100644 index 000000000000..9d76e86fec3d --- /dev/null +++ b/flang/test/HLFIR/fir-local-alloca-block.fir @@ -0,0 +1,34 @@ +// Tests that `fir.local` ops are able to provide an alloca block when required. + +// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s + +fir.local {type = local_init} @localizer : !fir.box> copy { +^bb0(%arg0: !fir.ref>>, %arg1: !fir.ref>>): + %0 = fir.load %arg0 : !fir.ref>> + hlfir.assign %0 to %arg1 : !fir.box>, !fir.ref>> + fir.yield(%arg1 : !fir.ref>>) +} + +func.func @foo() { + %c1 = arith.constant 1 : index + %0 = fir.alloca !fir.box> + fir.do_concurrent { + fir.do_concurrent.loop (%arg0) = (%c1) to (%c1) step (%c1) local(@localizer %0 -> %arg1 : !fir.ref>>) { + } + } + return +} + +// CHECK: fir.local {type = local_init} @localizer : ![[TYPE:fir.box>]] copy { +// CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref, %[[VAL_1:.*]]: !fir.ref): +// CHECK: %[[VAL_2:.*]] = fir.alloca ![[TYPE]] +// CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]], %[[VAL_4]] : (![[TYPE]], index) -> (index, index, index) +// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_1]] : !fir.ref +// CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_2]] : (!fir.ref) -> !fir.ref> +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_3]] : (![[TYPE]]) -> !fir.box +// CHECK: fir.call @_FortranAAssign(%[[VAL_10]], %[[VAL_11]], %{{.*}}, %{{.*}}) +// CHECK: fir.yield(%[[VAL_1]] : !fir.ref) +// CHECK: } diff --git a/flang/test/Integration/cold_array_repacking.f90 b/flang/test/Integration/cold_array_repacking.f90 new file mode 100644 index 000000000000..11b7d8c21b67 --- /dev/null +++ b/flang/test/Integration/cold_array_repacking.f90 @@ -0,0 +1,30 @@ +! Check that the branch weights used by the array repacking +! are propagated all the way to LLVM IR: +! RUN: %flang_fc1 -frepack-arrays -emit-llvm %s -o - | FileCheck %s + +! CHECK-LABEL: define void @test_( +! CHECK-SAME: ptr [[TMP0:%.*]]) +! CHECK: [[TMP4:%.*]] = ptrtoint ptr [[TMP0]] to i64 +! CHECK: [[TMP5:%.*]] = icmp ne i64 [[TMP4]], 0 +! CHECK: br i1 [[TMP5]], label %[[BB6:.*]], label %[[BB46:.*]] +! CHECK: [[BB6]]: +! CHECK: [[TMP7:%.*]] = call i1 @_FortranAIsContiguous(ptr [[TMP0]]) +! CHECK: [[TMP8:%.*]] = icmp eq i1 [[TMP7]], false +! CHECK: [[TMP13:%.*]] = and i1 [[TMP8]], [[TMP12:.*]] +! CHECK: br i1 [[TMP13]], label %[[BB14:.*]], label %[[BB46]], !prof [[PROF2:![0-9]+]] +! CHECK: [[BB14]]: +! CHECK: call void @_FortranAShallowCopyDirect +! CHECK: br label %[[BB46]] +! CHECK: [[BB46]]: +! CHECK: br i1 [[TMP5]], label %[[BB48:.*]], label %[[BB57:.*]] +! CHECK: [[BB48]]: +! CHECK: br i1 [[TMP55:.*]], label %[[BB56:.*]], label %[[BB57]], !prof [[PROF2]] +! CHECK: [[BB56]]: +! CHECK: call void @_FortranAShallowCopyDirect +! CHECK: br label %[[BB57]] +! CHECK: [[BB57]]: +! CHECK: ret void +! CHECK: [[PROF2]] = !{!"branch_weights", i32 0, i32 1} +subroutine test(x) + real :: x(:) +end subroutine test diff --git a/flang/test/Lower/CUDA/cuda-runtime-check.cuf b/flang/test/Lower/CUDA/cuda-runtime-check.cuf new file mode 100644 index 000000000000..f26d372769ca --- /dev/null +++ b/flang/test/Lower/CUDA/cuda-runtime-check.cuf @@ -0,0 +1,22 @@ +! RUN: bbc -emit-hlfir -fcuda %s -o - | FileCheck %s + +! Check insertion of runtime checks + +interface + subroutine foo(a) + real, device, dimension(:,:) :: a + end subroutine +end interface + + real, device, allocatable, dimension(:,:) :: a + allocate(a(10,10)) + call foo(a(1:10,1:10:2)) +end + +subroutine foo(a) + real, device, dimension(:,:) :: a +end subroutine + +! CHECK-LABEL: func.func @_QQmain() +! CHECK: fir.call @_FortranACUFDescriptorCheckSection +! CHECK: fir.call @_QPfoo diff --git a/flang/test/Lower/OpenMP/Todo/declare-mapper-iterator.f90 b/flang/test/Lower/OpenMP/Todo/declare-mapper-iterator.f90 new file mode 100644 index 000000000000..dacd6d624659 --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/declare-mapper-iterator.f90 @@ -0,0 +1,11 @@ +!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s + +!CHECK: Support for iterator modifiers is not implemented yet +subroutine f(arg) + type :: s + integer :: a(10) + end type + type(s) :: arg(:) + + !$omp declare mapper(m: s :: v) map(mapper(m), iterator(i = 1:10): v%a(i)) +end diff --git a/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 b/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 new file mode 100644 index 000000000000..d441cac47f5d --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 @@ -0,0 +1,34 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fc1 -emit-fir -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK: not yet implemented: Unhandled clause INDIRECT in DECLARE TARGET construct + !$omp declare target enter(func1) indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/flang/test/Lower/OpenMP/Todo/omp-doconcurrent.f90 b/flang/test/Lower/OpenMP/Todo/omp-doconcurrent.f90 deleted file mode 100644 index a6d70fa44592..000000000000 --- a/flang/test/Lower/OpenMP/Todo/omp-doconcurrent.f90 +++ /dev/null @@ -1,10 +0,0 @@ -! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s -! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s - -! CHECK: not yet implemented: Do Concurrent in Worksharing loop construct -subroutine sb() - !$omp do - do concurrent(i=1:10) - print *, i - end do -end subroutine diff --git a/flang/test/Lower/OpenMP/copyprivate5.f90 b/flang/test/Lower/OpenMP/copyprivate5.f90 new file mode 100644 index 000000000000..c75eb82a45e9 --- /dev/null +++ b/flang/test/Lower/OpenMP/copyprivate5.f90 @@ -0,0 +1,36 @@ +! Test lowering of COPYPRIVATE with character arguments +! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s + +! Testcase from: https://github.com/llvm/llvm-project/issues/142123 + +! CHECK-LABEL: func.func private @_copy_boxchar_c8xU( +! CHECK-SAME: %arg0: [[TYPE:!fir.ref>]], +! CHECK-SAME: %arg1: [[TYPE]]) attributes {llvm.linkage = #llvm.linkage} { +! CHECK: %[[RDST:.*]] = fir.load %arg0 : [[TYPE]] +! CHECK: %[[RSRC:.*]] = fir.load %arg1 : [[TYPE]] +! CHECK: %[[UDST:.*]]:2 = fir.unboxchar %[[RDST:.*]] : ([[UTYPE:!fir.boxchar<1>]]) -> ([[RTYPE:!fir.ref>]], [[ITYPE:index]]) +! CHECK: %[[USRC:.*]]:2 = fir.unboxchar %[[RSRC:.*]] : ([[UTYPE]]) -> ([[RTYPE]], [[ITYPE]]) +! CHECK: %[[DST:.*]]:2 = hlfir.declare %[[UDST:.*]]#0 typeparams %[[UDST:.*]]#1 {uniq_name = "[[NAME1:.*]]"} : ([[RTYPE]], [[ITYPE]]) -> ([[UTYPE]], [[RTYPE]]) +! CHECK: %[[SRC:.*]]:2 = hlfir.declare %[[USRC:.*]]#0 typeparams %[[UDST:.*]]#1 {uniq_name = "[[NAME2:.*]]"} : ([[RTYPE]], [[ITYPE]]) -> ([[UTYPE]], [[RTYPE]]) +! CHECK: hlfir.assign %[[SRC:.*]]#0 to %[[DST:.*]]#0 : [[UTYPE]], [[UTYPE]] +! CHECK: return +! CHECK: } + +! CHECK-LABEL: func.func @_QPs(%arg0: !fir.boxchar<1> {fir.bindc_name = "c"}) { +! CHECK: %[[ALLOC:.*]] = fir.alloca !fir.boxchar<1> +! CHECK: fir.store %[[SRC:.*]] to %[[ALLOC:.*]] : !fir.ref> +! CHECK: omp.single copyprivate([[ALLOC:.*]] -> @_copy_boxchar_c8xU : !fir.ref>) { +! CHECK: hlfir.assign %[[NEW_VAL:.*]] to %[[SRC:.*]] : !fir.ref>, !fir.boxchar<1> +! CHECK: omp.terminator +! CHECK: } + +subroutine s(c) +character(*) :: c +!$omp single copyprivate(c) +c = "bar" +!$omp end single +end subroutine + +character(len=3) :: c +call s(c) +end diff --git a/flang/test/Lower/OpenMP/depend-complex.f90 b/flang/test/Lower/OpenMP/depend-complex.f90 new file mode 100644 index 000000000000..488696b56507 --- /dev/null +++ b/flang/test/Lower/OpenMP/depend-complex.f90 @@ -0,0 +1,22 @@ +! RUN: %flang_fc1 -fopenmp -emit-hlfir -o - %s | FileCheck %s + +subroutine depend_complex(z) +! CHECK-LABEL: func.func @_QPdepend_complex( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {fir.bindc_name = "z"}) { + complex :: z +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFdepend_complexEz"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) + !$omp task depend(in:z%re) +! CHECK: %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0 real : (!fir.ref>) -> !fir.ref +! CHECK: omp.task depend(taskdependin -> %[[VAL_2]] : !fir.ref) { +! CHECK: omp.terminator +! CHECK: } + !$omp end task + !$omp task depend(in:z%im) +! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_1]]#0 imag : (!fir.ref>) -> !fir.ref +! CHECK: omp.task depend(taskdependin -> %[[VAL_3]] : !fir.ref) { +! CHECK: omp.terminator +! CHECK: } + !$omp end task +end subroutine + diff --git a/flang/test/Lower/OpenMP/depend-substring.f90 b/flang/test/Lower/OpenMP/depend-substring.f90 new file mode 100644 index 000000000000..5de11e06cc10 --- /dev/null +++ b/flang/test/Lower/OpenMP/depend-substring.f90 @@ -0,0 +1,108 @@ +! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s + +subroutine substring_0(c) + character(:), pointer :: c + !$omp task depend(out:c(:)) + !$omp end task +end +! CHECK-LABEL: func.func @_QPsubstring_0( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "c"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsubstring_0Ec"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box>>) -> !fir.ptr> +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box>>) -> index +! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr>, index) -> !fir.boxchar<1> +! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_8]] : (!fir.box>>) -> index +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (index) -> i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_11]], %[[VAL_7]] : index +! CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_13]], %[[VAL_12]] : index +! CHECK: %[[VAL_15:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_15]] : index +! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_14]], %[[VAL_15]] : index +! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_11]] typeparams %[[VAL_17]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1> +! CHECK: %[[VAL_19:.*]] = fir.box_addr %[[VAL_18]] : (!fir.boxchar<1>) -> !fir.ref> +! CHECK: omp.task depend(taskdependout -> %[[VAL_19]] : !fir.ref>) { +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +subroutine substring_1(c) + character(:), pointer :: c + !$omp task depend(out:c(2:)) + !$omp end task +end +! CHECK-LABEL: func.func @_QPsubstring_1( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "c"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsubstring_1Ec"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box>>) -> !fir.ptr> +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box>>) -> index +! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr>, index) -> !fir.boxchar<1> +! CHECK: %[[VAL_7:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_8]] : (!fir.box>>) -> index +! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (index) -> i64 +! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index +! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_11]], %[[VAL_7]] : index +! CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_13]], %[[VAL_12]] : index +! CHECK: %[[VAL_15:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_15]] : index +! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_14]], %[[VAL_15]] : index +! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_11]] typeparams %[[VAL_17]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1> +! CHECK: %[[VAL_19:.*]] = fir.box_addr %[[VAL_18]] : (!fir.boxchar<1>) -> !fir.ref> +! CHECK: omp.task depend(taskdependout -> %[[VAL_19]] : !fir.ref>) { +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +subroutine substring_2(c) + character(:), pointer :: c + !$omp task depend(out:c(:2)) + !$omp end task +end +! CHECK-LABEL: func.func @_QPsubstring_2( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "c"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsubstring_2Ec"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box>>) -> !fir.ptr> +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box>>) -> index +! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr>, index) -> !fir.boxchar<1> +! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_8:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_9:.*]] = arith.constant 2 : index +! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_8]] typeparams %[[VAL_9]] : (!fir.boxchar<1>, index, index, index) -> !fir.ref> +! CHECK: omp.task depend(taskdependout -> %[[VAL_10]] : !fir.ref>) { +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +subroutine substring_4(c) + character(:), pointer :: c + !$omp task depend(out:c) + !$omp end task +end +! CHECK-LABEL: func.func @_QPsubstring_4( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {fir.bindc_name = "c"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsubstring_4Ec"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> +! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box>>) -> !fir.ptr> +! CHECK: omp.task depend(taskdependout -> %[[VAL_3]] : !fir.ptr>) { +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } diff --git a/flang/test/Lower/OpenMP/flush02.f90 b/flang/test/Lower/OpenMP/flush02.f90 new file mode 100644 index 000000000000..b372e700e1a1 --- /dev/null +++ b/flang/test/Lower/OpenMP/flush02.f90 @@ -0,0 +1,32 @@ +! This test checks lowering of OpenMP Flush Directive. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +module flush02_mod + type t1 + integer(kind=4) :: x = 4 + end type t1 + + type :: t2 + type(t1) :: y = t1(2) + end type t2 + + +contains + + subroutine sub01(pt) + class(t1), intent(inout) :: pt + type(t2) :: dt + integer, allocatable :: a(:) + integer, pointer :: b(:) + + ! CHECK: omp.flush({{.*}} : !fir.ref>>>) + ! CHECK: omp.flush({{.*}} : !fir.ref) + ! CHECK: omp.flush({{.*}} : !fir.ref}>>) + ! CHECK: omp.flush({{.*}} : !fir.class>) + !$omp flush(a) + !$omp flush(p) + !$omp flush(dt) + !$omp flush(pt) + end subroutine +end module flush02_mod diff --git a/flang/test/Lower/OpenMP/ignore-target-data.f90 b/flang/test/Lower/OpenMP/ignore-target-data.f90 new file mode 100644 index 000000000000..f1a150d5dfab --- /dev/null +++ b/flang/test/Lower/OpenMP/ignore-target-data.f90 @@ -0,0 +1,30 @@ +!RUN: %flang_fc1 -emit-llvm -fopenmp %s -o - | FileCheck %s --check-prefix=NORT +!RUN: %flang_fc1 -emit-llvm -fopenmp %s -o - | FileCheck %s --check-prefix=LLVM + +!Make sure that there are no calls to the mapper. +!NORT-NOT: call{{.*}}__tgt_target_data_begin_mapper +!NORT-NOT: call{{.*}}__tgt_target_data_end_mapper + +!Make sure we generate the body +!LLVM: define internal void @_QFPf(ptr %[[A0:[0-9]+]], ptr %[[A1:[0-9]+]]) +!LLVM: %[[V0:[0-9]+]] = load i32, ptr %[[A0]], align 4 +!LLVM: %[[V1:[0-9]+]] = load i32, ptr %[[A1]], align 4 +!LLVM: %[[V2:[0-9]+]] = add i32 %[[V0]], %[[V1]] +!LLVM: store i32 %[[V2]], ptr %[[A0]], align 4 +!LLVM: ret void +!LLVM: } + + +program test + +call f(1, 2) + +contains + +subroutine f(x, y) + integer :: x, y + !$omp target data map(tofrom: x, y) + x = x + y + !$omp end target data +end subroutine +end diff --git a/flang/test/Lower/OpenMP/implicit-dsa.f90 b/flang/test/Lower/OpenMP/implicit-dsa.f90 index f0f149bb415b..0d2db63edfe7 100644 --- a/flang/test/Lower/OpenMP/implicit-dsa.f90 +++ b/flang/test/Lower/OpenMP/implicit-dsa.f90 @@ -5,6 +5,14 @@ ! Privatizers +! CHECK-LABEL: omp.private +! CHECK-SAME: {type = firstprivate} @[[TEST7_Y_FIRSTPRIV:.*]] : i32 +! CHECK-SAME: copy { + +! CHECK-LABEL: omp.private +! CHECK-SAME: {type = firstprivate} @[[TEST7_X_FIRSTPRIV:.*]] : i32 +! CHECK-SAME: copy { + ! CHECK-LABEL: omp.private ! CHECK-SAME: {type = private} @[[TEST6_Y_PRIV:.*]] : i32 ! CHECK-NOT: copy { @@ -277,22 +285,19 @@ subroutine implicit_dsa_test6 !$omp end task end subroutine -! Test taskgroup - it uses the same scope as task. +! Test taskgroup. !CHECK-LABEL: func @_QPimplicit_dsa_test7 !CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFimplicit_dsa_test7Ex"} !CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFimplicit_dsa_test7Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFimplicit_dsa_test7Ey"} !CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]] {uniq_name = "_QFimplicit_dsa_test7Ey"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: omp.task { +!CHECK: omp.task private(@[[TEST7_X_FIRSTPRIV]] %[[X_DECL]]#0 -> %[[PRIV_X:[^,]*]], +!CHECK-SAME: @[[TEST7_Y_FIRSTPRIV]] %[[Y_DECL]]#0 -> %[[PRIV_Y:.*]] : !fir.ref, !fir.ref) { +!CHECK: %[[PRIV_X_DECL:.*]]:2 = hlfir.declare %[[PRIV_X]] {uniq_name = "_QFimplicit_dsa_test7Ex"} +!CHECK: %[[PRIV_Y_DECL:.*]]:2 = hlfir.declare %[[PRIV_Y]] {uniq_name = "_QFimplicit_dsa_test7Ey"} !CHECK: omp.taskgroup { -!CHECK-NEXT: %[[PRIV_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFimplicit_dsa_test7Ex"} -!CHECK-NEXT: %[[PRIV_X_DECL:.*]]:2 = hlfir.declare %[[PRIV_X]] {uniq_name = "_QFimplicit_dsa_test7Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK-NEXT: %[[TEMP:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref +!CHECK-NEXT: %[[TEMP:.*]] = fir.load %[[PRIV_Y_DECL]]#0 : !fir.ref !CHECK-NEXT: hlfir.assign %[[TEMP]] to %[[PRIV_X_DECL]]#0 : i32, !fir.ref -!CHECK-NEXT: %[[PRIV_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFimplicit_dsa_test7Ey"} -!CHECK-NEXT: %[[PRIV_Y_DECL:.*]]:2 = hlfir.declare %[[PRIV_Y]] {uniq_name = "_QFimplicit_dsa_test7Ey"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK-NEXT: %[[TEMP2:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref -!CHECK-NEXT: hlfir.assign %[[TEMP2]] to %[[PRIV_Y_DECL]]#0 : i32, !fir.ref !CHECK: } !CHECK: } subroutine implicit_dsa_test7 diff --git a/flang/test/Lower/OpenMP/multiple-entry-points.f90 b/flang/test/Lower/OpenMP/multiple-entry-points.f90 new file mode 100644 index 000000000000..2b8caa79eaa1 --- /dev/null +++ b/flang/test/Lower/OpenMP/multiple-entry-points.f90 @@ -0,0 +1,46 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +! Check the first entry point +!CHECK: func.func @_QPprocess_a +!CHECK: omp.parallel +!CHECK: omp.wsloop +!CHECK: %[[V0:[0-9]+]] = fir.load %{{[0-9]+}} : !fir.ref +!CHECK: %[[V1:[a-z_0-9]+]] = arith.constant 2.000000e+00 : f32 +!CHECK: = arith.mulf %[[V0]], %[[V1]] fastmath : f32 +!CHECK: omp.terminator +!CHECK-NOT: omp +!CHECK: return + +! Check the second entry point +!CHECK: func.func @_QPprocess_b +!CHECK: omp.parallel +!CHECK: fir.do_loop +!CHECK: %[[V3:[0-9]+]] = fir.load %[[V2:[0-9]+]]#0 : !fir.ref +!CHECK: %[[V4:[0-9]+]] = fir.load %[[V2]]#0 : !fir.ref +!CHECK: = arith.muli %[[V3]], %[[V4]] : i32 +!CHECK: omp.terminator +!CHECK-NOT: omp +!CHECK: return + +subroutine process_a(n, a) + integer, intent(in) :: n + real, intent(inout) :: a(n) + integer :: i + + !$omp parallel do + do i = 1, n + a(i) = a(i) * 2.0 + end do + !$omp end parallel do + + return + + entry process_b(n, b) + + !$omp parallel + do i = 1, n + a(i) = i * i + end do + !$omp end parallel + +end subroutine process_a diff --git a/flang/test/Lower/OpenMP/requires-admo-acqrel.f90 b/flang/test/Lower/OpenMP/requires-admo-acqrel.f90 new file mode 100644 index 000000000000..525a846f410d --- /dev/null +++ b/flang/test/Lower/OpenMP/requires-admo-acqrel.f90 @@ -0,0 +1,19 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s + +module m +!$omp requires atomic_default_mem_order(acq_rel) + +contains + +subroutine f00(x, v) + integer :: x, v +!CHECK: omp.atomic.read %{{[ %#=0-9]+}} memory_order(acquire) + !$omp atomic read + v = x + +!CHECK: omp.atomic.write %{{[ %#=0-9]+}} memory_order(release) + !$omp atomic write + x = v +end + +end module diff --git a/flang/test/Lower/OpenMP/requires-admo-invalid1.f90 b/flang/test/Lower/OpenMP/requires-admo-invalid1.f90 new file mode 100644 index 000000000000..b21d3bbbc786 --- /dev/null +++ b/flang/test/Lower/OpenMP/requires-admo-invalid1.f90 @@ -0,0 +1,16 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s + +module m +!$omp requires atomic_default_mem_order(acquire) + +contains + +subroutine f00(x, v) + integer :: x, v +!CHECK: omp.atomic.write %{{[ %#=0-9]+}} memory_order(relaxed) + !$omp atomic write + x = v +end + +end module + diff --git a/flang/test/Lower/OpenMP/requires-admo-invalid2.f90 b/flang/test/Lower/OpenMP/requires-admo-invalid2.f90 new file mode 100644 index 000000000000..33caa25dcc64 --- /dev/null +++ b/flang/test/Lower/OpenMP/requires-admo-invalid2.f90 @@ -0,0 +1,16 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s + +module m +!$omp requires atomic_default_mem_order(release) + +contains + +subroutine f00(x, v) + integer :: x, v +!CHECK: omp.atomic.read {{[ %#=0-9]+}} memory_order(relaxed) + !$omp atomic read + v = x +end + +end module + diff --git a/flang/test/Lower/OpenMP/requires-atomic-default-mem-order.f90 b/flang/test/Lower/OpenMP/requires-atomic-default-mem-order.f90 new file mode 100644 index 000000000000..91cb654aeeb3 --- /dev/null +++ b/flang/test/Lower/OpenMP/requires-atomic-default-mem-order.f90 @@ -0,0 +1,22 @@ +!RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=50 %s -o - | FileCheck %s + +module m +!$omp requires atomic_default_mem_order(acq_rel) + +contains + +!CHECK: %[[V:[0-9]+]]:2 = hlfir.declare {{.*}} {uniq_name = "_QMmFf00Ev"} +!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare {{.*}} {uniq_name = "_QMmFf00Ex"} +!CHECK: omp.atomic.read %[[V]]#0 = %[[X]]#0 memory_order(acquire) +!CHECK: omp.atomic.write %[[X]]#0 = %{{[0-9]+}} memory_order(release) + +subroutine f00(x, v) + integer :: x, v + !$omp atomic read + v = x + + !$omp atomic write + x = v +end + +end module diff --git a/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 new file mode 100644 index 000000000000..0d4fd964b71e --- /dev/null +++ b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 @@ -0,0 +1,27 @@ +! This test checks the lowering and application of default map types for the target enter/exit data constructs and map clauses + +!RUN: %flang -fc1 -emit-fir -fopenmp -fopenmp-version=52 -o - %s | FileCheck %s --check-prefix=CHECK-52 +!RUN: not %flang -fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-51 + +module test + real, allocatable :: A + +contains + subroutine initialize() + allocate(A) + !$omp target enter data map(A) + !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, f32) map_clauses(to) capture(ByRef) var_ptr_ptr(%5 : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} + !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%6 : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK-51: to and alloc map types are permitted + + end subroutine initialize + + subroutine finalize() + !$omp target exit data map(A) + !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, f32) map_clauses(from) capture(ByRef) var_ptr_ptr(%3 : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} + !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, !fir.box>) map_clauses(from) capture(ByRef) members(%4 : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK-51: from, release and delete map types are permitted + deallocate(A) + + end subroutine finalize +end module test diff --git a/flang/test/Lower/OpenMP/target-parallel-private.f90 b/flang/test/Lower/OpenMP/target-parallel-private.f90 new file mode 100644 index 000000000000..cc04b77e4a52 --- /dev/null +++ b/flang/test/Lower/OpenMP/target-parallel-private.f90 @@ -0,0 +1,21 @@ +! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization \ +! RUN: -o - %s 2>&1 | FileCheck %s +! RUN: bbc -emit-hlfir -fopenmp --enable-delayed-privatization -o - %s 2>&1 |\ +! RUN: FileCheck %s + +!=============================================================================== +! `private` clause on `target parallel` +!=============================================================================== + +subroutine target_parallel_private() +integer, dimension(3) :: i +!$omp target parallel private(i) +!$omp end target parallel +end subroutine + +! CHECK: omp.private {type = private} @[[PRIVATIZER:.*]] : {{.*}} + +! CHECK: omp.target {{.*}} { +! CHECK: omp.parallel private(@[[PRIVATIZER]] %{{.*}} -> %{{.*}} : {{.*}}) { +! CHECK: } +! CHECK: } diff --git a/flang/test/Lower/OpenMP/target-teams-private.f90 b/flang/test/Lower/OpenMP/target-teams-private.f90 new file mode 100644 index 000000000000..65d97649b5cf --- /dev/null +++ b/flang/test/Lower/OpenMP/target-teams-private.f90 @@ -0,0 +1,20 @@ +! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization \ +! RUN: -o - %s 2>&1 | FileCheck %s +! RUN: bbc -emit-hlfir -fopenmp --enable-delayed-privatization -o - %s 2>&1 |\ +! RUN: FileCheck %s + +!=============================================================================== +! `private` clause on `target teams` +!=============================================================================== + +subroutine target_teams_private() +integer, dimension(3) :: i +!$omp target teams private(i) +!$omp end target teams +end subroutine + +! CHECK: omp.target {{.*}} { +! CHECK: omp.teams { +! CHECK: %{{.*}} = fir.alloca !fir.array<3xi32> {bindc_name = "i", {{.*}}} +! CHECK: } +! CHECK: } diff --git a/flang/test/Lower/OpenMP/taskgroup02.f90 b/flang/test/Lower/OpenMP/taskgroup02.f90 new file mode 100644 index 000000000000..1e996a030c23 --- /dev/null +++ b/flang/test/Lower/OpenMP/taskgroup02.f90 @@ -0,0 +1,32 @@ +! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s + +! Check that variables are not privatized twice when TASKGROUP is used. + +!CHECK-LABEL: func.func @_QPsub() { +!CHECK: omp.parallel { +!CHECK: %[[PAR_I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsubEi"} +!CHECK: omp.master { +!CHECK: omp.taskgroup { +!CHECK-NEXT: omp.task private(@_QFsubEi_firstprivate_i32 %[[PAR_I]]#0 -> %[[TASK_I:.*]] : !fir.ref) { +!CHECK: %[[TASK_I_DECL:.*]]:2 = hlfir.declare %[[TASK_I]] {uniq_name = "_QFsubEi"} +!CHECK: } +!CHECK: } +!CHECK: } +!CHECK: } + +subroutine sub() + integer, dimension(10) :: a + integer :: i + + !$omp parallel + !$omp master + do i=1,10 + !$omp taskgroup + !$omp task shared(a) + a(i) = 1 + !$omp end task + !$omp end taskgroup + end do + !$omp end master + !$omp end parallel +end subroutine diff --git a/flang/test/Lower/OpenMP/wsloop-linear.f90 b/flang/test/Lower/OpenMP/wsloop-linear.f90 deleted file mode 100644 index b99677108be2..000000000000 --- a/flang/test/Lower/OpenMP/wsloop-linear.f90 +++ /dev/null @@ -1,57 +0,0 @@ -! This test checks lowering of OpenMP DO Directive (Worksharing) -! with linear clause - -! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s - -!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFsimple_linearEx"} -!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFsimple_linearEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: %[[const:.*]] = arith.constant 1 : i32 -subroutine simple_linear - implicit none - integer :: x, y, i - !CHECK: omp.wsloop linear(%[[X]]#0 = %[[const]] : !fir.ref) {{.*}} - !$omp do linear(x) - !CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref - !CHECK: %[[const:.*]] = arith.constant 2 : i32 - !CHECK: %[[RESULT:.*]] = arith.addi %[[LOAD]], %[[const]] : i32 - do i = 1, 10 - y = x + 2 - end do - !$omp end do -end subroutine - - -!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlinear_stepEx"} -!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFlinear_stepEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) -subroutine linear_step - implicit none - integer :: x, y, i - !CHECK: %[[const:.*]] = arith.constant 4 : i32 - !CHECK: omp.wsloop linear(%[[X]]#0 = %[[const]] : !fir.ref) {{.*}} - !$omp do linear(x:4) - !CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref - !CHECK: %[[const:.*]] = arith.constant 2 : i32 - !CHECK: %[[RESULT:.*]] = arith.addi %[[LOAD]], %[[const]] : i32 - do i = 1, 10 - y = x + 2 - end do - !$omp end do -end subroutine - -!CHECK: %[[A_alloca:.*]] = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFlinear_exprEa"} -!CHECK: %[[A:.*]]:2 = hlfir.declare %[[A_alloca]] {uniq_name = "_QFlinear_exprEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlinear_exprEx"} -!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFlinear_exprEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) -subroutine linear_expr - implicit none - integer :: x, y, i, a - !CHECK: %[[LOAD_A:.*]] = fir.load %[[A]]#0 : !fir.ref - !CHECK: %[[const:.*]] = arith.constant 4 : i32 - !CHECK: %[[LINEAR_EXPR:.*]] = arith.addi %[[LOAD_A]], %[[const]] : i32 - !CHECK: omp.wsloop linear(%[[X]]#0 = %[[LINEAR_EXPR]] : !fir.ref) {{.*}} - !$omp do linear(x:a+4) - do i = 1, 10 - y = x + 2 - end do - !$omp end do -end subroutine diff --git a/flang/test/Lower/do_concurrent_delayed_locality.f90 b/flang/test/Lower/do_concurrent_delayed_locality.f90 index 039b17808d19..6cae0eb46db1 100644 --- a/flang/test/Lower/do_concurrent_delayed_locality.f90 +++ b/flang/test/Lower/do_concurrent_delayed_locality.f90 @@ -1,4 +1,4 @@ -! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s +! RUN: %flang_fc1 -emit-hlfir -mmlir --enable-delayed-privatization-staging=true -o - %s | FileCheck %s subroutine do_concurrent_with_locality_specs implicit none diff --git a/flang/test/Lower/do_concurrent_local_assoc_entity.f90 b/flang/test/Lower/do_concurrent_local_assoc_entity.f90 index 67f080eb2c1c..a3d0c34ed856 100644 --- a/flang/test/Lower/do_concurrent_local_assoc_entity.f90 +++ b/flang/test/Lower/do_concurrent_local_assoc_entity.f90 @@ -1,4 +1,4 @@ -! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s +! RUN: %flang_fc1 -emit-hlfir -mmlir --enable-delayed-privatization-staging=true -o - %s | FileCheck %s subroutine local_assoc implicit none diff --git a/flang/test/Lower/do_concurrent_local_default_init.f90 b/flang/test/Lower/do_concurrent_local_default_init.f90 index 798cbb335c8c..d64321385474 100644 --- a/flang/test/Lower/do_concurrent_local_default_init.f90 +++ b/flang/test/Lower/do_concurrent_local_default_init.f90 @@ -1,5 +1,5 @@ ! Test default initialization of DO CONCURRENT LOCAL() entities. -! RUN: bbc -emit-hlfir -I nowhere -o - %s | FileCheck %s +! RUN: bbc -emit-hlfir --enable-delayed-privatization-staging=true -I nowhere -o - %s | FileCheck %s subroutine test_ptr(p) interface diff --git a/flang/test/Lower/loops.f90 b/flang/test/Lower/loops.f90 index 64f14ff97227..60df27a591dc 100644 --- a/flang/test/Lower/loops.f90 +++ b/flang/test/Lower/loops.f90 @@ -1,4 +1,4 @@ -! RUN: bbc -emit-fir -hlfir=false --enable-delayed-privatization=false -o - %s | FileCheck %s +! RUN: bbc -emit-fir -hlfir=false -o - %s | FileCheck %s ! CHECK-LABEL: loop_test subroutine loop_test diff --git a/flang/test/Lower/loops3.f90 b/flang/test/Lower/loops3.f90 index 34d7bcfb7d7a..84db1972cca1 100644 --- a/flang/test/Lower/loops3.f90 +++ b/flang/test/Lower/loops3.f90 @@ -1,5 +1,5 @@ ! Test do concurrent reduction -! RUN: bbc -emit-fir -hlfir=false --enable-delayed-privatization=false -o - %s | FileCheck %s +! RUN: bbc -emit-fir -hlfir=false -o - %s | FileCheck %s ! CHECK-LABEL: loop_test subroutine loop_test diff --git a/flang/test/Lower/volatile-openmp.f90 b/flang/test/Lower/volatile-openmp.f90 index 28f0bf78f33c..2e05b652822b 100644 --- a/flang/test/Lower/volatile-openmp.f90 +++ b/flang/test/Lower/volatile-openmp.f90 @@ -23,11 +23,11 @@ end ! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QFEcontainer) : !fir.ref>>}>> ! CHECK: %[[VAL_12:.*]] = fir.volatile_cast %[[VAL_11]] : (!fir.ref>>}>>) -> !fir.ref>>}>, volatile> ! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEcontainer"} : (!fir.ref>>}>, volatile>) -> (!fir.ref>>}>, volatile>, !fir.ref>>}>, volatile>) -! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFE.c.t) : !fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>> +! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFE.c.t) : !fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>> ! CHECK: %[[VAL_15:.*]] = fir.shape_shift %[[VAL_0]], %[[VAL_1]] : (index, index) -> !fir.shapeshift<1> -! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_15]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.c.t"} : (!fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.shapeshift<1>) -> (!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>) -! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFE.dt.t) : !fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>> -! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.dt.t"} : (!fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>) -> (!fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>, !fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>) +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_15]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.c.t"} : (!fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.shapeshift<1>) -> (!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.ref>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>) +! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFE.dt.t) : !fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>> +! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.dt.t"} : (!fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>) -> (!fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>, !fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{{[<]?}}{genre:i8,__padding0:!fir.array<7xi8>,value:i64}{{[>]?}}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}{{[>]?}}>>>>,bounds:!fir.box,value:i64}{{[>]?}}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}{{[>]?}}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}>>) ! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_13]]#0{"array"} {fortran_attrs = #fir.var_attrs} : (!fir.ref>>}>, volatile>) -> !fir.ref>>, volatile> ! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref>>, volatile> ! CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_20]], %[[VAL_0]] : (!fir.box>>, index) -> (index, index, index) diff --git a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 new file mode 100644 index 000000000000..df85942ec15a --- /dev/null +++ b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 @@ -0,0 +1,53 @@ +! REQUIRES: openmp_runtime + +! RUN: %flang_fc1 %openmp_flags -fopenmp-version=52 -fdebug-dump-parse-tree %s | FileCheck %s +! RUN: %flang_fc1 %openmp_flags -fdebug-unparse -fopenmp-version=52 %s | FileCheck %s --check-prefix="UNPARSE" + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !$omp declare target enter(func1) indirect(.true.) + !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1' + !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4' + !CHECK-NEXT: | | | | | | LiteralConstant -> LogicalLiteralConstant + !CHECK-NEXT: | | | | | | | bool = 'true' + character(1) :: i + i = 'a' + return + end function + + function func2() result(i) + !$omp declare target enter(func2) indirect + !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2' + !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> + character(1) :: i + i = 'b' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1, ptr2=>func2 + character(1) :: val1, val2 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + !$omp target map(from: val2) + val2 = ptr2() + !$omp end target + +end program + +!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4) +!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() diff --git a/flang/test/Preprocessing/bug518.F b/flang/test/Preprocessing/bug518.F index 346e04cc56d3..0b680dd5751b 100644 --- a/flang/test/Preprocessing/bug518.F +++ b/flang/test/Preprocessing/bug518.F @@ -1,4 +1,4 @@ -! RUN: %flang -fc1 -fdebug-unparse %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s ! CHECK: k=1_4 k= 1_99999999 &4 diff --git a/flang/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext b/flang/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext new file mode 100644 index 000000000000..2650fb5ebfd3 --- /dev/null +++ b/flang/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext @@ -0,0 +1,18 @@ +# IR level Instrumentation Flag +:ir +_QQmain +# Func Hash: +146835646621254984 +# Num Counters: +2 +# Counter Values: +100 +1 + +main +# Func Hash: +742261418966908927 +# Num Counters: +1 +# Counter Values: +1 \ No newline at end of file diff --git a/flang/test/Profile/Inputs/gcc-flag-compatibility_IR_entry.proftext b/flang/test/Profile/Inputs/gcc-flag-compatibility_IR_entry.proftext new file mode 100644 index 000000000000..c4a2a26557e8 --- /dev/null +++ b/flang/test/Profile/Inputs/gcc-flag-compatibility_IR_entry.proftext @@ -0,0 +1,11 @@ +# IR level Instrumentation Flag +:ir +:entry_first +_QQmain +# Func Hash: +146835646621254984 +# Num Counters: +2 +# Counter Values: +100 +1 \ No newline at end of file diff --git a/flang/test/Profile/gcc-flag-compatibility.f90 b/flang/test/Profile/gcc-flag-compatibility.f90 new file mode 100644 index 000000000000..4490c45232d2 --- /dev/null +++ b/flang/test/Profile/gcc-flag-compatibility.f90 @@ -0,0 +1,32 @@ +! Tests for -fprofile-generate and -fprofile-use flag compatibility. These two +! flags behave similarly to their GCC counterparts: +! +! -fprofile-generate Generates the profile file ./default.profraw +! -fprofile-use=/file Uses the profile file /file + +! On AIX, -flto used to be required with -fprofile-generate. gcc-flag-compatibility-aix.c is used to do the testing on AIX with -flto +! RUN: %flang %s -c -S -o - -emit-llvm -fprofile-generate | FileCheck -check-prefix=PROFILE-GEN %s +! PROFILE-GEN: @__profc_{{_?}}main = {{(private|internal)}} global [1 x i64] zeroinitializer, section +! PROFILE-GEN: @__profd_{{_?}}main = + +! Check that -fprofile-use=some/path/file.prof reads some/path/file.prof +! This uses LLVM IR format profile. +! RUN: rm -rf %t.dir +! RUN: mkdir -p %t.dir/some/path +! RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility_IR.proftext -o %t.dir/some/path/file.prof +! RUN: %flang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof | FileCheck -check-prefix=PROFILE-USE-IR1 %s +! RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility_IR_entry.proftext -o %t.dir/some/path/file.prof +! RUN: %flang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof | FileCheck -check-prefix=PROFILE-USE-IR2 %s +! PROFILE-USE-IR1: = !{!"branch_weights", i32 100, i32 1} +! PROFILE-USE-IR2: = !{!"branch_weights", i32 1, i32 100} + +program main + implicit none + integer :: i + integer :: X = 0 + + do i = 0, 99 + X = X + i + end do + +end program main diff --git a/flang/test/Semantics/OpenMP/allocate-align01.f90 b/flang/test/Semantics/OpenMP/allocate-align01.f90 index 4974f5e18397..bc17d7047bbb 100644 --- a/flang/test/Semantics/OpenMP/allocate-align01.f90 +++ b/flang/test/Semantics/OpenMP/allocate-align01.f90 @@ -1,6 +1,6 @@ ! REQUIRES: openmp_runtime -! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=51 +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=52 ! OpenMP Version 5.2 ! The allocate clause's allocator modifier must be of type allocator_handle ! and the align modifier must be constant, positive integer expression diff --git a/flang/test/Semantics/OpenMP/allocate01.f90 b/flang/test/Semantics/OpenMP/allocate01.f90 index 8a680eee743e..b205b2c79d65 100644 --- a/flang/test/Semantics/OpenMP/allocate01.f90 +++ b/flang/test/Semantics/OpenMP/allocate01.f90 @@ -1,6 +1,6 @@ ! REQUIRES: openmp_runtime -! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=52 ! OpenMP Version 5.0 ! 2.11.3 allocate Directive ! The allocate directive must appear in the same scope as the declarations of diff --git a/flang/test/Semantics/OpenMP/allocate02.f90 b/flang/test/Semantics/OpenMP/allocate02.f90 index 80ef60b31e70..8f0579e810bb 100644 --- a/flang/test/Semantics/OpenMP/allocate02.f90 +++ b/flang/test/Semantics/OpenMP/allocate02.f90 @@ -16,11 +16,9 @@ use omp_lib !ERROR: At most one ALLOCATOR clause can appear on the ALLOCATE directive !$omp allocate(x, y) allocator(omp_default_mem_alloc) allocator(omp_default_mem_alloc) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate(darray) allocator(omp_default_mem_alloc) allocate ( darray(a, b) ) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !ERROR: At most one ALLOCATOR clause can appear on the ALLOCATE directive !$omp allocate(darray) allocator(omp_default_mem_alloc) allocator(omp_default_mem_alloc) allocate ( darray(a, b) ) diff --git a/flang/test/Semantics/OpenMP/allocate03.f90 b/flang/test/Semantics/OpenMP/allocate03.f90 index b8c6b8e5dee7..e35115f3897c 100644 --- a/flang/test/Semantics/OpenMP/allocate03.f90 +++ b/flang/test/Semantics/OpenMP/allocate03.f90 @@ -18,7 +18,6 @@ use omp_lib !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear on the ALLOCATE directive !$omp allocate(my_var%array) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear on the ALLOCATE directive !$omp allocate(darray, my_var%array) allocator(omp_default_mem_alloc) allocate ( darray(a, b) ) diff --git a/flang/test/Semantics/OpenMP/allocate05.f90 b/flang/test/Semantics/OpenMP/allocate05.f90 index 2c81c4dbc82c..a787e8bb32a4 100644 --- a/flang/test/Semantics/OpenMP/allocate05.f90 +++ b/flang/test/Semantics/OpenMP/allocate05.f90 @@ -13,13 +13,11 @@ use omp_lib real, dimension (:,:), allocatable :: darray !$omp target - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate allocator(omp_default_mem_alloc) allocate ( darray(a, b) ) !$omp end target !$omp target - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !ERROR: ALLOCATE directives that appear in a TARGET region must specify an allocator clause !$omp allocate allocate ( darray(a, b) ) diff --git a/flang/test/Semantics/OpenMP/allocate06.f90 b/flang/test/Semantics/OpenMP/allocate06.f90 index 7196bcac2b9b..e14134cd0730 100644 --- a/flang/test/Semantics/OpenMP/allocate06.f90 +++ b/flang/test/Semantics/OpenMP/allocate06.f90 @@ -14,7 +14,6 @@ use omp_lib !ERROR: List items specified in the ALLOCATE directive must not have the ALLOCATABLE attribute unless the directive is associated with an ALLOCATE statement !$omp allocate(darray) allocator(omp_default_mem_alloc) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate(darray) allocator(omp_default_mem_alloc) allocate(darray(a, b)) diff --git a/flang/test/Semantics/OpenMP/allocate09.f90 b/flang/test/Semantics/OpenMP/allocate09.f90 index 645e97a3a33f..0f93a340fe1e 100644 --- a/flang/test/Semantics/OpenMP/allocate09.f90 +++ b/flang/test/Semantics/OpenMP/allocate09.f90 @@ -12,28 +12,23 @@ use omp_lib integer, dimension(:), allocatable :: a, b, c, d, e, f, & g, h, i, j, k, l - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate(a) allocator(omp_default_mem_alloc) allocate(a(1), b(2)) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate(c, d) allocator(omp_default_mem_alloc) allocate(c(3), d(4)) !$omp allocate(e) allocator(omp_default_mem_alloc) !$omp allocate(f, g) allocator(omp_default_mem_alloc) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate allocate(e(5), f(6), g(7)) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !ERROR: Object 'i' in ALLOCATE directive not found in corresponding ALLOCATE statement !$omp allocate(h, i) allocator(omp_default_mem_alloc) allocate(h(8)) !ERROR: Object 'j' in ALLOCATE directive not found in corresponding ALLOCATE statement !$omp allocate(j, k) allocator(omp_default_mem_alloc) - !WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. !$omp allocate(l) allocator(omp_default_mem_alloc) allocate(k(9), l(10)) diff --git a/flang/test/Semantics/OpenMP/atomic-update-only.f90 b/flang/test/Semantics/OpenMP/atomic-update-only.f90 index 28d0e264359c..3c027924a142 100644 --- a/flang/test/Semantics/OpenMP/atomic-update-only.f90 +++ b/flang/test/Semantics/OpenMP/atomic-update-only.f90 @@ -30,7 +30,8 @@ subroutine f03 integer :: x, y !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable x cannot be a proper subexpression of an argument (here: (x+y)) in the update operation + !ERROR: The atomic variable x should appear as an argument of the top-level + operator x = (x + y) + 1 end diff --git a/flang/test/Semantics/OpenMP/atomic03.f90 b/flang/test/Semantics/OpenMP/atomic03.f90 index b3a3c0d5e7a1..691a483e6e80 100644 --- a/flang/test/Semantics/OpenMP/atomic03.f90 +++ b/flang/test/Semantics/OpenMP/atomic03.f90 @@ -25,19 +25,19 @@ program OmpAtomic y = MIN(y, 8) !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator + !ERROR: The atomic variable z should appear as an argument of the top-level AND operator z = IAND(y, 4) !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator + !ERROR: The atomic variable z should appear as an argument of the top-level OR operator z = IOR(y, 5) !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator + !ERROR: The atomic variable z should appear as an argument of the top-level NEQV/EOR operator z = IEOR(y, 6) !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator + !ERROR: The atomic variable z should appear as an argument of the top-level MAX operator z = MAX(y, 7, b, c) !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator + !ERROR: The atomic variable z should appear as an argument of the top-level MIN operator z = MIN(y, 8, a, d) !$omp atomic @@ -58,19 +58,19 @@ program OmpAtomic y = MIN(y, 8) !$omp atomic update - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator + !ERROR: The atomic variable z should appear as an argument of the top-level AND operator z = IAND(y, 4) !$omp atomic update - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator + !ERROR: The atomic variable z should appear as an argument of the top-level OR operator z = IOR(y, 5) !$omp atomic update - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator + !ERROR: The atomic variable z should appear as an argument of the top-level NEQV/EOR operator z = IEOR(y, 6) !$omp atomic update - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator + !ERROR: The atomic variable z should appear as an argument of the top-level MAX operator z = MAX(y, 7) !$omp atomic update - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator + !ERROR: The atomic variable z should appear as an argument of the top-level MIN operator z = MIN(y, 8) !$omp atomic update @@ -90,7 +90,7 @@ subroutine conflicting_types() type(simple) ::s z = 1 !$omp atomic - !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator + !ERROR: The atomic variable z should appear as an argument of the top-level AND operator z = IAND(s%z, 4) end subroutine @@ -103,22 +103,22 @@ subroutine more_invalid_atomic_update_stmts() type(some_type) :: s !$omp atomic update - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MIN operator + !ERROR: The atomic variable a should be exactly one of the arguments of the top-level MIN operator a = min(a, a, b) !$omp atomic - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator + !ERROR: The atomic variable a should be exactly one of the arguments of the top-level MAX operator a = max(b, a, b, a) !$omp atomic a = min(b, a, b) !$omp atomic - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator + !ERROR: The atomic variable a should be exactly one of the arguments of the top-level MAX operator a = max(b, a, b, a, b) !$omp atomic update - !ERROR: The atomic variable y should occur exactly once among the arguments of the top-level MIN operator + !ERROR: The atomic variable y should appear as an argument of the top-level MIN operator y = min(z, x) !$omp atomic @@ -126,7 +126,7 @@ subroutine more_invalid_atomic_update_stmts() !$omp atomic update !ERROR: Atomic variable k should be a scalar - !ERROR: The atomic variable k should occur exactly once among the arguments of the top-level MAX operator + !ERROR: The atomic variable k should appear as an argument of the top-level MAX operator k = max(x, y) !$omp atomic diff --git a/flang/test/Semantics/OpenMP/atomic04.f90 b/flang/test/Semantics/OpenMP/atomic04.f90 index 0f69befed141..fb87ca518661 100644 --- a/flang/test/Semantics/OpenMP/atomic04.f90 +++ b/flang/test/Semantics/OpenMP/atomic04.f90 @@ -17,10 +17,10 @@ program OmpAtomic !$omp atomic x = 1 + x !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable x should appear as an argument of the top-level + operator x = y + 1 !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable x should appear as an argument of the top-level + operator x = 1 + y !$omp atomic @@ -28,10 +28,10 @@ program OmpAtomic !$omp atomic x = 1 - x !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator + !ERROR: The atomic variable x should appear as an argument of the top-level - operator x = y - 1 !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator + !ERROR: The atomic variable x should appear as an argument of the top-level - operator x = 1 - y !$omp atomic @@ -50,10 +50,10 @@ program OmpAtomic !$omp atomic x = 1/x !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator + !ERROR: The atomic variable x should appear as an argument of the top-level / operator x = y/1 !$omp atomic - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator + !ERROR: The atomic variable x should appear as an argument of the top-level / operator x = 1/y !$omp atomic @@ -61,7 +61,7 @@ program OmpAtomic !$omp atomic m = n .AND. m !$omp atomic - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator + !ERROR: The atomic variable m should appear as an argument of the top-level AND operator m = n .AND. l !$omp atomic @@ -69,7 +69,7 @@ program OmpAtomic !$omp atomic m = n .OR. m !$omp atomic - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator + !ERROR: The atomic variable m should appear as an argument of the top-level OR operator m = n .OR. l !$omp atomic @@ -77,7 +77,7 @@ program OmpAtomic !$omp atomic m = n .EQV. m !$omp atomic - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator + !ERROR: The atomic variable m should appear as an argument of the top-level EQV operator m = n .EQV. l !$omp atomic @@ -85,7 +85,7 @@ program OmpAtomic !$omp atomic m = n .NEQV. m !$omp atomic - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator + !ERROR: The atomic variable m should appear as an argument of the top-level NEQV/EOR operator m = n .NEQV. l !$omp atomic update @@ -93,10 +93,10 @@ program OmpAtomic !$omp atomic update x = 1 + x !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable x should appear as an argument of the top-level + operator x = y + 1 !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable x should appear as an argument of the top-level + operator x = 1 + y !$omp atomic update @@ -104,10 +104,10 @@ program OmpAtomic !$omp atomic update x = 1 - x !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator + !ERROR: The atomic variable x should appear as an argument of the top-level - operator x = y - 1 !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator + !ERROR: The atomic variable x should appear as an argument of the top-level - operator x = 1 - y !$omp atomic update @@ -126,10 +126,10 @@ program OmpAtomic !$omp atomic update x = 1/x !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator + !ERROR: The atomic variable x should appear as an argument of the top-level / operator x = y/1 !$omp atomic update - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator + !ERROR: The atomic variable x should appear as an argument of the top-level / operator x = 1/y !$omp atomic update @@ -137,7 +137,7 @@ program OmpAtomic !$omp atomic update m = n .AND. m !$omp atomic update - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator + !ERROR: The atomic variable m should appear as an argument of the top-level AND operator m = n .AND. l !$omp atomic update @@ -145,7 +145,7 @@ program OmpAtomic !$omp atomic update m = n .OR. m !$omp atomic update - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator + !ERROR: The atomic variable m should appear as an argument of the top-level OR operator m = n .OR. l !$omp atomic update @@ -153,7 +153,7 @@ program OmpAtomic !$omp atomic update m = n .EQV. m !$omp atomic update - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator + !ERROR: The atomic variable m should appear as an argument of the top-level EQV operator m = n .EQV. l !$omp atomic update @@ -161,7 +161,7 @@ program OmpAtomic !$omp atomic update m = n .NEQV. m !$omp atomic update - !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator + !ERROR: The atomic variable m should appear as an argument of the top-level NEQV/EOR operator m = n .NEQV. l end program OmpAtomic @@ -184,27 +184,30 @@ subroutine more_invalid_atomic_update_stmts() x = 1 !$omp atomic update - !ERROR: Within atomic operation a and a*b access the same storage + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a*b) in the update operation a = a * b + a !$omp atomic - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level * operator + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (a+9_4)) in the update operation + !ERROR: The atomic variable a should appear as an argument of the top-level * operator a = b * (a + 9) !$omp atomic update - !ERROR: Within atomic operation a and (a+b) access the same storage + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (a+b)) in the update operation a = a * (a + b) !$omp atomic - !ERROR: Within atomic operation a and (b+a) access the same storage + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (b+a)) in the update operation a = (b + a) * a !$omp atomic - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a*b) in the update operation + !ERROR: The atomic variable a should appear as an argument of the top-level + operator a = a * b + c !$omp atomic update - !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a+b) in the update operation + !ERROR: The atomic variable a should appear as an argument of the top-level + operator a = a + b + c !$omp atomic @@ -219,11 +222,12 @@ subroutine more_invalid_atomic_update_stmts() !$omp atomic update !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) - !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator + !ERROR: The atomic variable x cannot be a proper subexpression of an argument (here: x*y) in the update operation + !ERROR: The atomic variable x should appear as an argument of the top-level / operator x = x * y / z !$omp atomic - !ERROR: The atomic variable p%m should occur exactly once among the arguments of the top-level + operator + !ERROR: The atomic variable p%m should appear as an argument of the top-level + operator p%m = x + y !$omp atomic update diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 5e0d91914c44..6989a183e83e 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -1,6 +1,6 @@ ! REQUIRES: openmp_runtime -! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags %openmp_module_flag -fopenmp-version=51 +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags %openmp_module_flag -fopenmp-version=52 use omp_lib ! Check OpenMP clause validity for the following directives: ! @@ -502,6 +502,7 @@ use omp_lib !$omp taskyield !$omp barrier !$omp taskwait + !WARNING: SOURCE dependence type is deprecated in OpenMP v5.2 !ERROR: The SINK and SOURCE dependence types can only be used with the ORDERED directive, used here in the TASKWAIT construct !$omp taskwait depend(source) ! !$omp taskwait depend(sink:i-1) @@ -509,12 +510,18 @@ use omp_lib ! !$omp target update from(arrayA) to(arrayB) ! !$omp target exit data map(from:arrayA) map(delete:arrayB) !$omp flush (c) + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !$omp flush acq_rel + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !$omp flush release + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !$omp flush acquire + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !ERROR: If memory-order-clause is RELEASE, ACQUIRE, or ACQ_REL, list items must not be specified on the FLUSH directive !$omp flush release (c) + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !$omp flush seq_cst + !WARNING: The syntax "FLUSH clause (object, ...)" has been deprecated, use "FLUSH(object, ...) clause" instead !ERROR: RELAXED clause is not allowed on the FLUSH directive !$omp flush relaxed diff --git a/flang/test/Semantics/OpenMP/depend-substring.f90 b/flang/test/Semantics/OpenMP/depend-substring.f90 new file mode 100644 index 000000000000..23d6bb4c0b7b --- /dev/null +++ b/flang/test/Semantics/OpenMP/depend-substring.f90 @@ -0,0 +1,65 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenmp +! Test for parsing confusion between array indexing and string subscripts + +! This is okay: selects the whole substring +subroutine substring_0(c) + character(:), pointer :: c + !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2. + !$omp task depend(out:c(:)) + !$omp end task +end + +! This is okay: selects from the second character onwards +subroutine substring_1(c) + character(:), pointer :: c + !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2. + !$omp task depend(out:c(2:)) + !$omp end task +end + +! This is okay: selects the first 2 characters +subroutine substring_2(c) + character(:), pointer :: c + !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2. + !$omp task depend(out:c(:2)) + !$omp end task +end + +! Error +subroutine substring_3(c) + character(:), pointer :: c + !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2. + !ERROR: Substrings must be in the form parent-string(lb:ub) + !$omp task depend(out:c(2)) + !$omp end task +end + +! This is okay: interpreted as indexing into the array not as a substring +subroutine substring_3b(c) + character(:), pointer :: c(:) + !$omp task depend(out:c(2)) + !$omp end task +end + +! This is okay: no indexing or substring at all +subroutine substring_4(c) + character(:), pointer :: c + !$omp task depend(out:c) + !$omp end task +end + +! This is not okay: substrings can't have a stride +subroutine substring_5(c) + character(:), pointer :: c + !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2. + !ERROR: Cannot specify a step for a substring + !$omp task depend(out:c(1:20:5)) + !$omp end task +end + +! This is okay: interpreted as indexing the array +subroutine substring_5b(c) + character(:), pointer :: c(:) + !$omp task depend(out:c(1:20:5)) + !$omp end task +end diff --git a/flang/test/Semantics/OpenMP/deprecation.f90 b/flang/test/Semantics/OpenMP/deprecation.f90 index e04f43026bbc..df15c3bcc0b1 100644 --- a/flang/test/Semantics/OpenMP/deprecation.f90 +++ b/flang/test/Semantics/OpenMP/deprecation.f90 @@ -1,4 +1,4 @@ -! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Werror +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Werror -fopenmp-version=52 ! Check for deprecation of master directive and its combined/composite variants diff --git a/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 b/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 new file mode 100644 index 000000000000..bb1929249183 --- /dev/null +++ b/flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 @@ -0,0 +1,39 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp + +integer :: i, j +!$omp parallel do collapse(2) +do i = 1, 1 + ! ERROR: DO CONCURRENT loops cannot form part of a loop nest. + do concurrent (j = 1:2) + print *, j + end do +end do + +!$omp parallel do +do i = 1, 1 + ! This should not lead to an error because it is not part of a loop nest: + do concurrent (j = 1:2) + print *, j + end do +end do + +!$omp parallel do +! ERROR: DO CONCURRENT loops cannot form part of a loop nest. +do concurrent (j = 1:2) + print *, j +end do + +!$omp loop +! Do concurrent is explicitly allowed inside of omp loop +do concurrent (j = 1:2) + print *, j +end do + +! ERROR: DO CONCURRENT loops cannot be used with the COLLAPSE clause. +!$omp loop collapse(2) +do i = 1, 1 + do concurrent (j = 1:2) + print *, j + end do +end do +end diff --git a/flang/test/Semantics/OpenMP/flush02.f90 b/flang/test/Semantics/OpenMP/flush02.f90 index 615332c6cf31..a7b170d58db5 100644 --- a/flang/test/Semantics/OpenMP/flush02.f90 +++ b/flang/test/Semantics/OpenMP/flush02.f90 @@ -78,7 +78,6 @@ use omp_lib !$omp parallel num_threads(4) array = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/) - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master !$omp flush (array) !$omp end master diff --git a/flang/test/Semantics/OpenMP/implicit-dsa.f90 b/flang/test/Semantics/OpenMP/implicit-dsa.f90 index 4a07e256e2bb..1ee777d6b972 100644 --- a/flang/test/Semantics/OpenMP/implicit-dsa.f90 +++ b/flang/test/Semantics/OpenMP/implicit-dsa.f90 @@ -141,7 +141,7 @@ subroutine implicit_dsa_test6 !$omp end task end subroutine -! Test taskgroup - it uses the same scope as task. +! Test taskgroup. !DEF: /implicit_dsa_test7 (Subroutine) Subprogram subroutine implicit_dsa_test7 !DEF: /implicit_dsa_test7/x ObjectEntity INTEGER(4) @@ -150,8 +150,8 @@ subroutine implicit_dsa_test7 !$omp task !$omp taskgroup - !DEF: /implicit_dsa_test7/OtherConstruct1/x (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4) - !DEF: /implicit_dsa_test7/OtherConstruct1/y (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4) + !DEF: /implicit_dsa_test7/OtherConstruct1/OtherConstruct1/x HostAssoc INTEGER(4) + !DEF: /implicit_dsa_test7/OtherConstruct1/OtherConstruct1/y HostAssoc INTEGER(4) x = y !$omp end taskgroup !$omp end task diff --git a/flang/test/Semantics/OpenMP/nested-barrier.f90 b/flang/test/Semantics/OpenMP/nested-barrier.f90 index 5f51363d59e5..8565a09a18cd 100644 --- a/flang/test/Semantics/OpenMP/nested-barrier.f90 +++ b/flang/test/Semantics/OpenMP/nested-barrier.f90 @@ -75,7 +75,6 @@ program omp_nest_barrier end do !$omp end critical - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master do i = 1, 10 k = k + 1 @@ -108,7 +107,6 @@ program omp_nest_barrier end do !$omp end ordered - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master do i = 1, 10 !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. diff --git a/flang/test/Semantics/OpenMP/nested-master.f90 b/flang/test/Semantics/OpenMP/nested-master.f90 index d51e366eb584..7e4bb32bb7be 100644 --- a/flang/test/Semantics/OpenMP/nested-master.f90 +++ b/flang/test/Semantics/OpenMP/nested-master.f90 @@ -9,7 +9,6 @@ program omp_nest_master !$omp do do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master j = j -1 @@ -17,7 +16,6 @@ program omp_nest_master end do !$omp sections - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master do i = 1, 10 @@ -27,7 +25,6 @@ program omp_nest_master !$omp end sections !$omp single - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master do i = 1, 10 @@ -41,7 +38,6 @@ program omp_nest_master !$omp task do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master j = j -1 @@ -52,7 +48,6 @@ program omp_nest_master !$omp taskloop do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master j = j -1 @@ -63,7 +58,6 @@ program omp_nest_master !$omp target parallel do simd do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master @@ -75,7 +69,6 @@ program omp_nest_master !$omp critical do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master j = j -1 !$omp end master @@ -85,7 +78,6 @@ program omp_nest_master !$omp ordered do i = 1, 10 k = k + 1 - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master j = j -1 !$omp end master @@ -99,7 +91,6 @@ program omp_nest_master !$omp distribute do k =1, 10 print *, "hello" - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master j = j -1 !$omp end master @@ -116,7 +107,6 @@ program omp_nest_master !$omp distribute do k =1, 10 print *, "hello" - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master j = j -1 !$omp end master @@ -133,7 +123,6 @@ program omp_nest_master !$omp distribute do k =1, 10 print *, "hello" - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master j = j -1 @@ -151,7 +140,6 @@ program omp_nest_master !$omp distribute do k =1, 10 print *, "hello" - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$omp master j = j -1 diff --git a/flang/test/Semantics/OpenMP/nested-teams.f90 b/flang/test/Semantics/OpenMP/nested-teams.f90 index 974172ee9717..3c193ee00b95 100644 --- a/flang/test/Semantics/OpenMP/nested-teams.f90 +++ b/flang/test/Semantics/OpenMP/nested-teams.f90 @@ -42,7 +42,6 @@ program main !$omp end teams end do - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$omp master !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams diff --git a/flang/test/Semantics/OpenMP/ordered-simd.f90 b/flang/test/Semantics/OpenMP/ordered-simd.f90 index c90ffb3bd1c5..50560139ea24 100644 --- a/flang/test/Semantics/OpenMP/ordered-simd.f90 +++ b/flang/test/Semantics/OpenMP/ordered-simd.f90 @@ -95,7 +95,6 @@ SUBROUTINE ORDERED_BAD(N) !$OMP CRITICAL C = C - A * B - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$OMP MASTER DO I = 1,N !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region. @@ -108,7 +107,6 @@ SUBROUTINE ORDERED_BAD(N) !$OMP ORDERED C = C - A * B - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !$OMP MASTER DO I = 1,N !ERROR: `ORDERED` region may not be closely nested inside of `CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region. @@ -121,7 +119,6 @@ SUBROUTINE ORDERED_BAD(N) !$OMP TASK C = C - A * B - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$OMP MASTER DO I = 1,N @@ -136,7 +133,6 @@ SUBROUTINE ORDERED_BAD(N) !$OMP TASKLOOP DO J= 1,N C = C - A * B - !WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region. !$OMP MASTER DO I = 1,N diff --git a/flang/test/Semantics/OpenMP/parallel-master-goto.f90 b/flang/test/Semantics/OpenMP/parallel-master-goto.f90 new file mode 100644 index 000000000000..01d14aaa46d3 --- /dev/null +++ b/flang/test/Semantics/OpenMP/parallel-master-goto.f90 @@ -0,0 +1,14 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenmp +! Regression test for #143229 + +!$omp parallel +do i = 1, 2 +!ERROR: invalid branch into an OpenMP structured block +!ERROR: invalid branch leaving an OpenMP structured block + goto 10 +end do +!$omp master +10 print *, i +!$omp end master +!$omp end parallel +end diff --git a/flang/test/Semantics/OpenMP/parallel-sections01.f90 b/flang/test/Semantics/OpenMP/parallel-sections01.f90 index 6c5a053bf49c..19448258af76 100644 --- a/flang/test/Semantics/OpenMP/parallel-sections01.f90 +++ b/flang/test/Semantics/OpenMP/parallel-sections01.f90 @@ -35,6 +35,8 @@ program OmpConstructSections01 !$omp section print *, "This is a single statement structured block" !$omp section + !ERROR: invalid branch into an OpenMP structured block + !ERROR: invalid branch leaving an OpenMP structured block open (10, file="random-file-name.txt", err=30) !ERROR: invalid branch into an OpenMP structured block !ERROR: invalid branch leaving an OpenMP structured block diff --git a/flang/test/Semantics/OpenMP/requires-atomic01.f90 b/flang/test/Semantics/OpenMP/requires-atomic01.f90 deleted file mode 100644 index e8817c3f5ef6..000000000000 --- a/flang/test/Semantics/OpenMP/requires-atomic01.f90 +++ /dev/null @@ -1,121 +0,0 @@ -! RUN: %flang_fc1 -fopenmp -fopenmp-version=50 -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s -! Ensure that requires atomic_default_mem_order is used to update atomic -! operations with no explicit memory order set. -program requires - implicit none - !$omp requires atomic_default_mem_order(seq_cst) - integer :: i, j - - ! ---------------------------------------------------------------------------- - ! READ - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Read - ! CHECK: OmpClause -> SeqCst - !$omp atomic read - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Read - !$omp atomic relaxed read - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Read - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - !$omp atomic read relaxed - i = j - - ! ---------------------------------------------------------------------------- - ! WRITE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Write - ! CHECK: OmpClause -> SeqCst - !$omp atomic write - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Write - !$omp atomic relaxed write - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Write - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - !$omp atomic write relaxed - i = j - - ! ---------------------------------------------------------------------------- - ! UPDATE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Update - ! CHECK: OmpClause -> SeqCst - !$omp atomic update - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Update - !$omp atomic relaxed update - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Update - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - !$omp atomic update relaxed - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> SeqCst - !$omp atomic - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - !$omp atomic relaxed - i = i + j - - ! ---------------------------------------------------------------------------- - ! CAPTURE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Capture - ! CHECK: OmpClause -> SeqCst - !$omp atomic capture - i = j - j = j + 1 - !$omp end atomic - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Capture - !$omp atomic relaxed capture - i = j - j = j + 1 - !$omp end atomic - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Capture - ! CHECK-NOT: OmpClause -> SeqCst - ! CHECK: OmpClause -> Relaxed - !$omp atomic capture relaxed - i = j - j = j + 1 - !$omp end atomic -end program requires diff --git a/flang/test/Semantics/OpenMP/requires-atomic02.f90 b/flang/test/Semantics/OpenMP/requires-atomic02.f90 deleted file mode 100644 index a3724a83456f..000000000000 --- a/flang/test/Semantics/OpenMP/requires-atomic02.f90 +++ /dev/null @@ -1,121 +0,0 @@ -! RUN: %flang_fc1 -fopenmp -fopenmp-version=50 -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s -! Ensure that requires atomic_default_mem_order is used to update atomic -! operations with no explicit memory order set. ACQ_REL clause tested here. -program requires - implicit none - !$omp requires atomic_default_mem_order(acq_rel) - integer :: i, j - - ! ---------------------------------------------------------------------------- - ! READ - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Read - ! CHECK: OmpClause -> AcqRel - !$omp atomic read - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Read - !$omp atomic relaxed read - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Read - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - !$omp atomic read relaxed - i = j - - ! ---------------------------------------------------------------------------- - ! WRITE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Write - ! CHECK: OmpClause -> AcqRel - !$omp atomic write - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Write - !$omp atomic relaxed write - i = j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Write - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - !$omp atomic write relaxed - i = j - - ! ---------------------------------------------------------------------------- - ! UPDATE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Update - ! CHECK: OmpClause -> AcqRel - !$omp atomic update - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Update - !$omp atomic relaxed update - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Update - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - !$omp atomic update relaxed - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> AcqRel - !$omp atomic - i = i + j - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - !$omp atomic relaxed - i = i + j - - ! ---------------------------------------------------------------------------- - ! CAPTURE - ! ---------------------------------------------------------------------------- - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK: OmpClause -> Capture - ! CHECK: OmpClause -> AcqRel - !$omp atomic capture - i = j - j = j + 1 - !$omp end atomic - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Relaxed - ! CHECK: OmpClause -> Capture - !$omp atomic relaxed capture - i = j - j = j + 1 - !$omp end atomic - - ! CHECK-LABEL: OpenMPAtomicConstruct - ! CHECK-NOT: OmpClause -> AcqRel - ! CHECK: OmpClause -> Capture - ! CHECK: OmpClause -> Relaxed - !$omp atomic capture relaxed - i = j - j = j + 1 - !$omp end atomic -end program requires diff --git a/flang/test/Semantics/OpenMP/sections-goto.f90 b/flang/test/Semantics/OpenMP/sections-goto.f90 new file mode 100644 index 000000000000..9fa9df9f50b9 --- /dev/null +++ b/flang/test/Semantics/OpenMP/sections-goto.f90 @@ -0,0 +1,11 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenmp +! Regression test for #143231 + +!$omp sections +! ERROR: invalid branch into an OpenMP structured block +! ERROR: invalid branch leaving an OpenMP structured block +goto 10 +!$omp section +10 print *, "Invalid jump" +!$omp end sections +end diff --git a/flang/test/Semantics/OpenMP/sections02.f90 b/flang/test/Semantics/OpenMP/sections02.f90 index ee29922a72c0..8144b491071d 100644 --- a/flang/test/Semantics/OpenMP/sections02.f90 +++ b/flang/test/Semantics/OpenMP/sections02.f90 @@ -19,6 +19,8 @@ program OmpConstructSections01 !$omp section print *, "This is a single statement structured block" !$omp section + !ERROR: invalid branch into an OpenMP structured block + !ERROR: invalid branch leaving an OpenMP structured block open (10, file="random-file-name.txt", err=30) !ERROR: invalid branch into an OpenMP structured block !ERROR: invalid branch leaving an OpenMP structured block diff --git a/flang/test/Semantics/allocate11.f90 b/flang/test/Semantics/allocate11.f90 index 1b7495e9fc07..8aeb069df09f 100644 --- a/flang/test/Semantics/allocate11.f90 +++ b/flang/test/Semantics/allocate11.f90 @@ -163,6 +163,7 @@ subroutine C938_C947(var2, ptr, ptr2, fptr, my_team, srca) allocate(var2(2)[5:*], MOLD=my_team) !ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray allocate(var2(2)[5:*], MOLD=ptr) + !ERROR: Allocation has extent 2 on dimension 1, but SOURCE= has extent 9 !ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray allocate(var2(2)[5:*], SOURCE=ptr2) !ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray diff --git a/flang/test/Semantics/cuf21.cuf b/flang/test/Semantics/cuf21.cuf index 077657c8a52d..db32f1dbd0e7 100644 --- a/flang/test/Semantics/cuf21.cuf +++ b/flang/test/Semantics/cuf21.cuf @@ -13,18 +13,21 @@ contains implicit none logical, intent(in), value :: back real(4) :: mval - - call maxlocUpdate(mval, back) - + block + integer(8) :: xloc + call maxlocUpdate(mval, xloc, back) + end block end subroutine maxlocPartialMaskR_32F1D - attributes(device) subroutine maxlocUpdateR_32F(mval, back) + attributes(device) subroutine maxlocUpdateR_32F(mval, xloc, back) real(4) :: mval + integer(8) :: xloc logical :: back end subroutine maxlocUpdateR_32F - attributes(device) subroutine maxlocUpdateR_64F(mval, back) + attributes(device) subroutine maxlocUpdateR_64F(mval, xloc, back) real(8) :: mval + integer(8) :: xloc logical :: back end subroutine maxlocUpdateR_64F end module diff --git a/flang/test/Semantics/indirect01.f90 b/flang/test/Semantics/indirect01.f90 new file mode 100644 index 000000000000..59850662275d --- /dev/null +++ b/flang/test/Semantics/indirect01.f90 @@ -0,0 +1,34 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK: The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive. + !$omp declare target indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/flang/test/Semantics/indirect02.f90 b/flang/test/Semantics/indirect02.f90 new file mode 100644 index 000000000000..273f8856626b --- /dev/null +++ b/flang/test/Semantics/indirect02.f90 @@ -0,0 +1,36 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s --check-prefix="CHECK-50" +! RUN: not flang -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s --check-prefix="CHECK-52" + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK-50: INDIRECT clause is not allowed on directive DECLARE TARGET in OpenMP v5.0, try -fopenmp-version=51 + !CHECK-52: not yet implemented: Unhandled clause INDIRECT in DECLARE TARGET construct + !$omp declare target enter(func1) indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/flang/test/Semantics/modfile71.F90 b/flang/test/Semantics/modfile71.F90 index 7c3c7f5b4895..7f32eb18c6f8 100644 --- a/flang/test/Semantics/modfile71.F90 +++ b/flang/test/Semantics/modfile71.F90 @@ -1,6 +1,7 @@ -!RUN: %flang_fc1 -fsyntax-only -fhermetic-module-files -DSTEP=1 %s -!RUN: %flang_fc1 -fsyntax-only -DSTEP=2 %s -!RUN: not %flang_fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang_fc1 -fsyntax-only -fhermetic-module-files -DSTEP=1 -J%t %s +!RUN: %flang_fc1 -fsyntax-only -DSTEP=2 -J%t %s +!RUN: not %flang_fc1 -fsyntax-only -pedantic -J%t %s 2>&1 | FileCheck %s ! Tests that a module captured in a hermetic module file is compatible when ! USE'd with a module of the same name USE'd directly. diff --git a/flang/test/Semantics/modfile75.F90 b/flang/test/Semantics/modfile75.F90 index aba00ffac848..8f7adafe7204 100644 --- a/flang/test/Semantics/modfile75.F90 +++ b/flang/test/Semantics/modfile75.F90 @@ -1,4 +1,5 @@ -!RUN: %flang -c -fhermetic-module-files -DWHICH=1 %s && %flang -c -fhermetic-module-files -DWHICH=2 %s && %flang_fc1 -fdebug-unparse %s | FileCheck %s +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang -c -fhermetic-module-files -DWHICH=1 -J%t %s && %flang -c -fhermetic-module-files -DWHICH=2 -J%t %s && %flang_fc1 -fdebug-unparse -J%t %s | FileCheck %s #if WHICH == 1 module modfile75a diff --git a/flang/test/Semantics/modfile76.F90 b/flang/test/Semantics/modfile76.F90 new file mode 100644 index 000000000000..c7ae91bd42be --- /dev/null +++ b/flang/test/Semantics/modfile76.F90 @@ -0,0 +1,25 @@ +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang_fc1 -fsyntax-only -fhermetic-module-files -DSTEP=1 -J%t %s +!RUN: %flang_fc1 -fsyntax-only -J%t %s + +! Tests that a BIND(C) variable in a module A captured in a hermetic module +! file USE'd in a module B is not creating bogus complaints about BIND(C) name +! conflict when both module A and B are later accessed. + +#if STEP == 1 +module modfile76a + integer, bind(c) :: x +end + +module modfile76b + use modfile76a ! capture hermetically +end + +#else +subroutine test + use modfile76a + use modfile76b + implicit none + print *, x +end subroutine +#endif diff --git a/flang/test/Semantics/modfile77.F90 b/flang/test/Semantics/modfile77.F90 new file mode 100644 index 000000000000..9ad615c16c43 --- /dev/null +++ b/flang/test/Semantics/modfile77.F90 @@ -0,0 +1,38 @@ +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang -c -fhermetic-module-files -DWHICH=1 -J%t %s && %flang -c -fhermetic-module-files -DWHICH=2 -J%t %s && %flang -c -fhermetic-module-files -J%t %s && cat %t/modfile77c.mod | FileCheck %s + +#if WHICH == 1 +module modfile77a + interface gen + procedure proc + end interface + contains + subroutine proc + print *, 'ok' + end +end +#elif WHICH == 2 +module modfile77b + use modfile77a +end +#else +module modfile77c + use modfile77a + use modfile77b +end +#endif + +!CHECK: module modfile77c +!CHECK: use modfile77a,only:proc +!CHECK: use modfile77a,only:gen +!CHECK: interface gen +!CHECK: end interface +!CHECK: end +!CHECK: module modfile77a +!CHECK: interface gen +!CHECK: procedure::proc +!CHECK: end interface +!CHECK: contains +!CHECK: subroutine proc() +!CHECK: end +!CHECK: end diff --git a/flang/test/Semantics/modfile78.F90 b/flang/test/Semantics/modfile78.F90 new file mode 100644 index 000000000000..19b9ac39de93 --- /dev/null +++ b/flang/test/Semantics/modfile78.F90 @@ -0,0 +1,34 @@ +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang -c -fhermetic-module-files -DWHICH=1 -J%t %s && %flang -c -fhermetic-module-files -DWHICH=2 -J%t %s && %flang -c -fhermetic-module-files -J%t %s && cat %t/modfile78c.mod | FileCheck %s + +#if WHICH == 1 +module modfile78a + integer :: global_variable = 0 +end +#elif WHICH == 2 +module modfile78b + use modfile78a + contains + subroutine test + end +end +#else +module modfile78c + use modfile78a + use modfile78b +end +#endif + +!CHECK: module modfile78c +!CHECK: use modfile78a,only:global_variable +!CHECK: use modfile78b,only:test +!CHECK: end +!CHECK: module modfile78a +!CHECK: integer(4)::global_variable +!CHECK: end +!CHECK: module modfile78b +!CHECK: use modfile78a,only:global_variable +!CHECK: contains +!CHECK: subroutine test() +!CHECK: end +!CHECK: end diff --git a/flang/test/Semantics/modfile79.F90 b/flang/test/Semantics/modfile79.F90 new file mode 100644 index 000000000000..ae156527b3bf --- /dev/null +++ b/flang/test/Semantics/modfile79.F90 @@ -0,0 +1,34 @@ +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang -c -DWHICH=1 -J%t %s && FileCheck %s <%t/modfile79a.mod && %flang -c -fhermetic-module-files -DWHICH=2 -J%t %s && %flang -c -J%t %s && FileCheck %s <%t/modfile79a.mod + +!Ensure that writing modfile79c.mod doesn't cause a spurious +!regeneration of modfile79a.mod from its copy in the hermetic +!module file modfile79b.mod. +!CHECK: !mod$ v1 sum:93ec75fe672c5b6c +!CHECK-NEXT: module modfile79a + +#if WHICH == 1 +module modfile79a + interface foo + module procedure foo + end interface + contains + subroutine foo + end +end +#elif WHICH == 2 +module modfile79b + use modfile79a + interface bar + procedure foo + end interface +end +#else +module modfile79c + use modfile79b + contains + subroutine test + call bar + end +end +#endif diff --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90 index d228cd2a84ca..bb20c546e026 100644 --- a/flang/test/Semantics/typeinfo01.f90 +++ b/flang/test/Semantics/typeinfo01.f90 @@ -8,7 +8,7 @@ module m01 end type !CHECK: Module scope: m01 !CHECK: .c.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.n,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())] -!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .n.n, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: CHARACTER(1_8,1) init:"n" !CHECK: .n.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: CHARACTER(2_8,1) init:"t1" !CHECK: DerivedType scope: t1 @@ -23,8 +23,8 @@ module m02 end type !CHECK: .c.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:1_8 init:[component::component(name=.n.parent,genre=1_1,category=6_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.parent,lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.cn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=4_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())] !CHECK: .c.parent, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.pn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())] -!CHECK: .dt.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.child,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.child,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) -!CHECK: .dt.parent, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.parent,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.parent,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.child,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.child,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) +!CHECK: .dt.parent, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.parent,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.parent,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) end module module m03 @@ -35,7 +35,7 @@ module m03 type(kpdt(4)) :: x !CHECK: .c.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.a,genre=1_1,category=2_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())] !CHECK: .dt.kpdt, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.kpdt,uninstantiated=NULL(),kindparameter=.kp.kpdt,lenparameterkind=NULL()) -!CHECK: .dt.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.4,lenparameterkind=NULL(),component=.c.kpdt.4,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.4,lenparameterkind=NULL(),component=.c.kpdt.4,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .kp.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::4_8] end module @@ -49,7 +49,7 @@ module m04 subroutine s1(x) class(tbps), intent(in) :: x end subroutine -!CHECK: .dt.tbps, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.tbps,name=.n.tbps,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.tbps, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.tbps,name=.n.tbps,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .v.tbps, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:1_8 init:[binding::binding(proc=s1,name=.n.b1),binding(proc=s1,name=.n.b2)] end module @@ -61,7 +61,7 @@ module m05 subroutine s1(x) class(t), intent(in) :: x end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .p.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(procptrcomponent) shape: 0_8:0_8 init:[procptrcomponent::procptrcomponent(name=.n.p1,offset=0_8,initialization=s1)] end module @@ -85,8 +85,8 @@ module m06 class(t), intent(in) :: y end subroutine !CHECK: .c.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.t,genre=1_1,category=6_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.t,lenvalue=NULL(),bounds=NULL(),initialization=NULL())] -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) -!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=.s.t2,specialbitset=2_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) +!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=.s.t2,specialbitset=2_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) !CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)] !CHECK: .s.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s2)] !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)] @@ -113,8 +113,8 @@ module m06a class(t2), intent(in) :: y end subroutine !CHECK: .c.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.t,genre=1_1,category=6_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.t,lenvalue=NULL(),bounds=NULL(),initialization=NULL())] -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) -!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=.s.t2,specialbitset=2_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) +!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=.s.t2,specialbitset=2_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) !CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)] !CHECK: .s.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s2)] !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)] @@ -132,7 +132,7 @@ module m07 class(t), intent(out) :: x class(t), intent(in) :: y end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) !CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)] !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)] end module @@ -155,8 +155,8 @@ module m08 subroutine s4(x) type(t), contiguous :: x(:,:,:) end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=7296_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) -!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=1_1,proc=s4)] +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=7296_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=1_1) +!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,istypebound=0_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=0_1,isargcontiguousset=1_1,proc=s4)] end module module m09 @@ -197,8 +197,8 @@ module m09 integer, intent(out) :: iostat character(len=*), intent(inout) :: iomsg end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) -!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wu)] +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) +!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,istypebound=2_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=3_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=4_1,isargcontiguousset=0_1,proc=wu)] !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:3_8 init:[binding::binding(proc=rf,name=.n.rf),binding(proc=ru,name=.n.ru),binding(proc=wf,name=.n.wf),binding(proc=wu,name=.n.wu)] end module @@ -246,7 +246,7 @@ module m10 integer, intent(out) :: iostat character(len=*), intent(inout) :: iomsg end subroutine -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wu)] end module @@ -263,7 +263,7 @@ module m11 !CHECK: .c.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=2_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=2_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=.di.t.pointer),component(name=.n.chauto,genre=4_1,category=4_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.automatic,genre=4_1,category=2_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.automatic,initialization=NULL())] !CHECK: .di.t.pointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(.dp.t.pointer) init:.dp.t.pointer(pointer=target) !CHECK: .dp.t.pointer (CompilerCreated): DerivedType components: pointer -!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t,component=.c.t,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) +!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t,component=.c.t,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .lpk.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1] !CHECK: DerivedType scope: .dp.t.pointer size=24 alignment=8 instantiation of .dp.t.pointer !CHECK: pointer, POINTER size=24 offset=0: ObjectEntity type: REAL(4) diff --git a/flang/test/Semantics/typeinfo03.f90 b/flang/test/Semantics/typeinfo03.f90 index f0c0a817da4a..e2552d0a21d6 100644 --- a/flang/test/Semantics/typeinfo03.f90 +++ b/flang/test/Semantics/typeinfo03.f90 @@ -6,4 +6,4 @@ module m class(*), pointer :: sp, ap(:) end type end module -!CHECK: .dt.haspointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.haspointer,sizeinbytes=104_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.haspointer,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.haspointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.haspointer,sizeinbytes=104_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.haspointer,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) diff --git a/flang/test/Semantics/typeinfo04.f90 b/flang/test/Semantics/typeinfo04.f90 index de8464321a40..94dd2199db35 100644 --- a/flang/test/Semantics/typeinfo04.f90 +++ b/flang/test/Semantics/typeinfo04.f90 @@ -7,18 +7,18 @@ module m contains final :: final end type -!CHECK: .dt.finalizable, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.finalizable,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.finalizable,specialbitset=128_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) +!CHECK: .dt.finalizable, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.finalizable,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.finalizable,specialbitset=128_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=1_1) type, abstract :: t1 end type -!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t1,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t1,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) type, abstract :: t2 real, allocatable :: a(:) end type -!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t2,sizeinbytes=48_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) +!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t2,sizeinbytes=48_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) type, abstract :: t3 type(finalizable) :: x end type -!CHECK: .dt.t3, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t3,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t3,procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) +!CHECK: .dt.t3, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t3,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t3,procptr=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=1_1) contains impure elemental subroutine final(x) type(finalizable), intent(in out) :: x diff --git a/flang/test/Semantics/typeinfo05.f90 b/flang/test/Semantics/typeinfo05.f90 index 2a7f12a153eb..df1aecf3821d 100644 --- a/flang/test/Semantics/typeinfo05.f90 +++ b/flang/test/Semantics/typeinfo05.f90 @@ -7,10 +7,10 @@ program main type t1 type(t2), pointer :: b end type t1 -!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) type :: t2 type(t1) :: a end type t2 -! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) end program main diff --git a/flang/test/Semantics/typeinfo06.f90 b/flang/test/Semantics/typeinfo06.f90 index 2385709a8eb4..22f37b1a4369 100644 --- a/flang/test/Semantics/typeinfo06.f90 +++ b/flang/test/Semantics/typeinfo06.f90 @@ -7,10 +7,10 @@ program main type t1 type(t2), allocatable :: b end type t1 -!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) type :: t2 type(t1) :: a end type t2 -! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) +! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) end program main diff --git a/flang/test/Semantics/typeinfo07.f90 b/flang/test/Semantics/typeinfo07.f90 index e8766d9811db..ab20d6f60110 100644 --- a/flang/test/Semantics/typeinfo07.f90 +++ b/flang/test/Semantics/typeinfo07.f90 @@ -16,7 +16,7 @@ type(t_container_extension) :: wrapper end type end -! CHECK: .dt.t_container, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) -! CHECK: .dt.t_container_extension, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) -! CHECK: .dt.t_container_not_polymorphic, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) -! CHECK: .dt.t_container_wrapper, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) +! CHECK: .dt.t_container, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=0_1) +! CHECK: .dt.t_container_extension, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=0_1) +! CHECK: .dt.t_container_not_polymorphic, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) +! CHECK: .dt.t_container_wrapper, SAVE, TARGET (CompilerCreated, ReadOnly): {{.*}}noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=0_1) diff --git a/flang/test/Semantics/typeinfo08.f90 b/flang/test/Semantics/typeinfo08.f90 index 689cf469dee3..391a66f3d666 100644 --- a/flang/test/Semantics/typeinfo08.f90 +++ b/flang/test/Semantics/typeinfo08.f90 @@ -13,7 +13,7 @@ end module !CHECK: Module scope: m size=0 alignment=1 sourceRange=113 bytes !CHECK: .c.s, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.t1,genre=1_1,category=6_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),lenvalue=NULL(),bounds=NULL(),initialization=NULL())] -!CHECK: .dt.s, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.s,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.s,component=.c.s,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +!CHECK: .dt.s, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.s,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.s,component=.c.s,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) !CHECK: .lpk.s, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::4_1] !CHECK: .n.s, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: CHARACTER(1_8,1) init:"s" !CHECK: .n.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: CHARACTER(2_8,1) init:"t1" diff --git a/flang/test/Semantics/typeinfo11.f90 b/flang/test/Semantics/typeinfo11.f90 index 92efc8f9ea54..08e0b95abb76 100644 --- a/flang/test/Semantics/typeinfo11.f90 +++ b/flang/test/Semantics/typeinfo11.f90 @@ -14,4 +14,4 @@ end type type(t2) x end -!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1) +!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=0_1) diff --git a/flang/test/Semantics/typeinfo12.f90 b/flang/test/Semantics/typeinfo12.f90 new file mode 100644 index 000000000000..6b23b63d28b1 --- /dev/null +++ b/flang/test/Semantics/typeinfo12.f90 @@ -0,0 +1,67 @@ +!RUN: bbc --dump-symbols %s | FileCheck %s +!Check "nodefinedassignment" settings. + +module m01 + + type hasAsst1 + contains + procedure asst1 + generic :: assignment(=) => asst1 + end type +!CHECK: .dt.hasasst1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.hasasst1,name=.n.hasasst1,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.hasasst1,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) + + type hasAsst2 ! no defined assignment relevant to the runtime + end type + interface assignment(=) + procedure asst2 + end interface +!CHECK: .dt.hasasst2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.hasasst2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type test1 + type(hasAsst1) c + end type +!CHECK: .dt.test1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test1,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) + + type test2 + type(hasAsst2) c + end type +!CHECK: .dt.test2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type test3 + type(hasAsst1), pointer :: p + end type +!CHECK: .dt.test3, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test3,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test3,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type test4 + type(hasAsst2), pointer :: p + end type +!CHECK: .dt.test4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test4,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test4,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type, extends(hasAsst1) :: test5 + end type +!CHECK: .dt.test5, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.test5,name=.n.test5,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test5,procptr=NULL(),special=.s.test5,specialbitset=4_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=0_1) + + type, extends(hasAsst2) :: test6 + end type +!CHECK: .dt.test6, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test6,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test6,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type test7 + type(test7), allocatable :: c + end type +!CHECK: .dt.test7, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test7,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test7,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1,nodefinedassignment=1_1) + + type test8 + class(test8), allocatable :: c + end type +!CHECK: .dt.test8, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.test8,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.test8,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=0_1,nodefinedassignment=0_1) + + contains + impure elemental subroutine asst1(left, right) + class(hasAsst1), intent(out) :: left + class(hasAsst1), intent(in) :: right + end + impure elemental subroutine asst2(left, right) + class(hasAsst2), intent(out) :: left + class(hasAsst2), intent(in) :: right + end +end diff --git a/flang/test/Semantics/typeinfo13.f90 b/flang/test/Semantics/typeinfo13.f90 index cf4abf9e3818..ad824ad3590a 100644 --- a/flang/test/Semantics/typeinfo13.f90 +++ b/flang/test/Semantics/typeinfo13.f90 @@ -22,5 +22,5 @@ module m end end -!CHECK: .s.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=override)] +!CHECK: .s.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=1_1,istypebound=2_1,isargcontiguousset=0_1,proc=override)] !CHECK: .v.child, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:1_8 init:[binding::binding(proc=baseassign,name=.n.baseassign),binding(proc=override,name=.n.override)] diff --git a/flang/test/Transforms/do-concurrent-localizer-dealloc-region.fir b/flang/test/Transforms/do-concurrent-localizer-dealloc-region.fir new file mode 100644 index 000000000000..b59ffdfb34ad --- /dev/null +++ b/flang/test/Transforms/do-concurrent-localizer-dealloc-region.fir @@ -0,0 +1,126 @@ +// Tests converting `fir.local` ops that have `dealloc` regions. + +// RUN: fir-opt --split-input-file --simplify-fir-operations %s | FileCheck %s + +fir.local {type = local} @_QFlocalizer_with_dealloc_regionEa_private_box_Uxi32 : !fir.box> init { +^bb0(%arg0: !fir.ref>>, %arg1: !fir.ref>>): + %c0 = arith.constant 0 : index + %0 = fir.load %arg0 : !fir.ref>> + %1:3 = fir.box_dims %0, %c0 : (!fir.box>, index) -> (index, index, index) + %2 = fir.shape %1#1 : (index) -> !fir.shape<1> + %3 = fir.allocmem !fir.array, %1#1 {bindc_name = ".tmp", uniq_name = ""} + %4 = fir.declare %3(%2) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> !fir.heap> + %5 = fir.embox %4(%2) : (!fir.heap>, !fir.shape<1>) -> !fir.box> + %6 = fir.shape_shift %1#0, %1#1 : (index, index) -> !fir.shapeshift<1> + %7 = fir.rebox %5(%6) : (!fir.box>, !fir.shapeshift<1>) -> !fir.box> + fir.store %7 to %arg1 : !fir.ref>> + fir.yield(%arg1 : !fir.ref>>) +} dealloc { +^bb0(%arg0: !fir.ref>>): + %c0_i64 = arith.constant 0 : i64 + %0 = fir.load %arg0 : !fir.ref>> + %1 = fir.box_addr %0 : (!fir.box>) -> !fir.ref> + %2 = fir.convert %1 : (!fir.ref>) -> i64 + %3 = arith.cmpi ne, %2, %c0_i64 : i64 + fir.if %3 { + %4 = fir.convert %1 : (!fir.ref>) -> !fir.heap> + fir.freemem %4 : !fir.heap> + } + fir.yield +} + +func.func @_QPlocalizer_with_dealloc_region(%arg0: !fir.ref {fir.bindc_name = "n"}) { + %c42_i32 = arith.constant 42 : i32 + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.alloca !fir.box> + %1 = fir.dummy_scope : !fir.dscope + %2 = fir.declare %arg0 dummy_scope %1 {uniq_name = "_QFlocalizer_with_dealloc_regionEn"} : (!fir.ref, !fir.dscope) -> !fir.ref + %3 = fir.load %2 : !fir.ref + %4 = fir.convert %3 : (i32) -> index + %5 = arith.cmpi sgt, %4, %c0 : index + %6 = arith.select %5, %4, %c0 : index + %7 = fir.alloca !fir.array, %6 {bindc_name = "a", uniq_name = "_QFlocalizer_with_dealloc_regionEa"} + %8 = fir.shape %6 : (index) -> !fir.shape<1> + %9 = fir.declare %7(%8) {uniq_name = "_QFlocalizer_with_dealloc_regionEa"} : (!fir.ref>, !fir.shape<1>) -> !fir.ref> + %10 = fir.embox %9(%8) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + fir.store %10 to %0 : !fir.ref>> + fir.do_concurrent { + %11 = fir.alloca i32 {bindc_name = "i"} + %12 = fir.declare %11 {uniq_name = "_QFlocalizer_with_dealloc_regionEi"} : (!fir.ref) -> !fir.ref + fir.do_concurrent.loop (%arg1) = (%c1) to (%4) step (%c1) local(@_QFlocalizer_with_dealloc_regionEa_private_box_Uxi32 %0 -> %arg2 : !fir.ref>>) { + %13 = fir.convert %arg1 : (index) -> i32 + fir.store %13 to %12 : !fir.ref + %14 = fir.declare %arg2 {uniq_name = "_QFlocalizer_with_dealloc_regionEa"} : (!fir.ref>>) -> !fir.ref>> + %15 = fir.load %14 : !fir.ref>> + %16 = fir.load %12 : !fir.ref + %17 = fir.convert %16 : (i32) -> i64 + %18:3 = fir.box_dims %15, %c0 : (!fir.box>, index) -> (index, index, index) + %19 = fir.shift %18#0 : (index) -> !fir.shift<1> + %20 = fir.array_coor %15(%19) %17 : (!fir.box>, !fir.shift<1>, i64) -> !fir.ref + fir.store %c42_i32 to %20 : !fir.ref + } + } + return +} + +// CHECK-LABEL: func.func @_QPlocalizer_with_dealloc_region( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 42 : i32 +// CHECK: %[[VAL_4:.*]] = fir.alloca i32 {bindc_name = "i"} +// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]] {uniq_name = "_QFlocalizer_with_dealloc_regionEi"} : (!fir.ref) -> !fir.ref +// CHECK: %[[VAL_6:.*]] = fir.alloca !fir.box> +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]] = fir.declare %[[ARG0]] dummy_scope %[[VAL_7]] {uniq_name = "_QFlocalizer_with_dealloc_regionEn"} : (!fir.ref, !fir.dscope) -> !fir.ref +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_8]] : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_1]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_1]] : index +// CHECK: %[[VAL_13:.*]] = fir.alloca !fir.array, %[[VAL_12]] {bindc_name = "a", uniq_name = "_QFlocalizer_with_dealloc_regionEa"} +// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_15:.*]] = fir.declare %[[VAL_13]](%[[VAL_14]]) {uniq_name = "_QFlocalizer_with_dealloc_regionEa"} : (!fir.ref>, !fir.shape<1>) -> !fir.ref> +// CHECK: %[[VAL_16:.*]] = fir.embox %[[VAL_15]](%[[VAL_14]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +// CHECK: fir.store %[[VAL_16]] to %[[VAL_6]] : !fir.ref>> +// CHECK: fir.do_loop %[[VAL_17:.*]] = %[[VAL_2]] to %[[VAL_10]] step %[[VAL_2]] unordered { + +// Local allocation +// CHECK: %[[VAL_18:.*]] = fir.alloca !fir.box> + +// `init` region body +// CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_6]] : !fir.ref>> +// CHECK: %[[VAL_20:.*]]:3 = fir.box_dims %[[VAL_19]], %[[VAL_1]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_21:.*]] = fir.shape %[[VAL_20]]#1 : (index) -> !fir.shape<1> +// CHECK: %[[VAL_22:.*]] = fir.allocmem !fir.array, %[[VAL_20]]#1 {bindc_name = ".tmp", uniq_name = ""} +// CHECK: %[[VAL_23:.*]] = fir.declare %[[VAL_22]](%[[VAL_21]]) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> !fir.heap> +// CHECK: %[[VAL_24:.*]] = fir.embox %[[VAL_23]](%[[VAL_21]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> +// CHECK: %[[VAL_25:.*]] = fir.shape_shift %[[VAL_20]]#0, %[[VAL_20]]#1 : (index, index) -> !fir.shapeshift<1> +// CHECK: %[[VAL_26:.*]] = fir.rebox %[[VAL_24]](%[[VAL_25]]) : (!fir.box>, !fir.shapeshift<1>) -> !fir.box> +// CHECK: fir.store %[[VAL_26]] to %[[VAL_18]] : !fir.ref>> + +// Loop body +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_17]] : (index) -> i32 +// CHECK: fir.store %[[VAL_27]] to %[[VAL_5]] : !fir.ref +// CHECK: %[[VAL_28:.*]] = fir.declare %[[VAL_18]] {uniq_name = "_QFlocalizer_with_dealloc_regionEa"} : (!fir.ref>>) -> !fir.ref>> +// CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_28]] : !fir.ref>> +// CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_5]] : !fir.ref +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i32) -> i64 +// CHECK: %[[VAL_32:.*]]:3 = fir.box_dims %[[VAL_29]], %[[VAL_1]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_33:.*]] = fir.shift %[[VAL_32]]#0 : (index) -> !fir.shift<1> +// CHECK: %[[VAL_34:.*]] = fir.array_coor %[[VAL_29]](%[[VAL_33]]) %[[VAL_31]] : (!fir.box>, !fir.shift<1>, i64) -> !fir.ref +// CHECK: fir.store %[[VAL_3]] to %[[VAL_34]] : !fir.ref + +// `dealloc` region +// CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_18]] : !fir.ref>> +// CHECK: %[[VAL_36:.*]] = fir.box_addr %[[VAL_35]] : (!fir.box>) -> !fir.ref> +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_36]] : (!fir.ref>) -> i64 +// CHECK: %[[VAL_38:.*]] = arith.cmpi ne, %[[VAL_37]], %[[VAL_0]] : i64 +// CHECK: fir.if %[[VAL_38]] { +// CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_36]] : (!fir.ref>) -> !fir.heap> +// CHECK: fir.freemem %[[VAL_39]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } diff --git a/flang/test/Transforms/do-concurrent-localizer-init-region.fir b/flang/test/Transforms/do-concurrent-localizer-init-region.fir new file mode 100644 index 000000000000..ebb56aec278f --- /dev/null +++ b/flang/test/Transforms/do-concurrent-localizer-init-region.fir @@ -0,0 +1,102 @@ +// Tests converting `fir.local` ops that have `init` regions. + +// RUN: fir-opt --split-input-file --simplify-fir-operations %s | FileCheck %s + +fir.local {type = local_init} @_QFlocalizer_with_init_regionEp_firstprivate_box_ptr_Uxi32 : !fir.box>> init { +^bb0(%arg0: !fir.ref>>>, %arg1: !fir.ref>>>): + %c0 = arith.constant 0 : index + %0 = fir.shape %c0 : (index) -> !fir.shape<1> + %1 = fir.zero_bits !fir.ptr> + %2 = fir.embox %1(%0) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> + fir.store %2 to %arg1 : !fir.ref>>> + fir.yield(%arg1 : !fir.ref>>>) +} copy { +^bb0(%arg0: !fir.ref>>>, %arg1: !fir.ref>>>): + %0 = fir.load %arg0 : !fir.ref>>> + fir.store %0 to %arg1 : !fir.ref>>> + fir.yield(%arg1 : !fir.ref>>>) +} + +func.func @_QPlocalizer_with_init_region() { + %c42_i32 = arith.constant 42 : i32 + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "n", uniq_name = "_QFlocalizer_with_init_regionEn"} + %2 = fir.declare %1 {uniq_name = "_QFlocalizer_with_init_regionEn"} : (!fir.ref) -> !fir.ref + %3 = fir.alloca !fir.box>> {bindc_name = "p", uniq_name = "_QFlocalizer_with_init_regionEp"} + %4 = fir.zero_bits !fir.ptr> + %5 = fir.shape %c0 : (index) -> !fir.shape<1> + %6 = fir.embox %4(%5) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> + fir.store %6 to %3 : !fir.ref>>> + %7 = fir.declare %3 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocalizer_with_init_regionEp"} : (!fir.ref>>>) -> !fir.ref>>> + %8 = fir.load %2 : !fir.ref + %9 = fir.convert %8 : (i32) -> index + + fir.do_concurrent { + %10 = fir.alloca i32 {bindc_name = "i"} + %11 = fir.declare %10 {uniq_name = "_QFlocalizer_with_init_regionEi"} : (!fir.ref) -> !fir.ref + fir.do_concurrent.loop (%arg0) = (%c1) to (%9) step (%c1) local(@_QFlocalizer_with_init_regionEp_firstprivate_box_ptr_Uxi32 %7 -> %arg1 : !fir.ref>>>) { + %12 = fir.convert %arg0 : (index) -> i32 + fir.store %12 to %11 : !fir.ref + %13 = fir.declare %arg1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocalizer_with_init_regionEp"} : (!fir.ref>>>) -> !fir.ref>>> + %14 = fir.load %13 : !fir.ref>>> + %15 = fir.load %11 : !fir.ref + %16 = fir.convert %15 : (i32) -> i64 + %17:3 = fir.box_dims %14, %c0 : (!fir.box>>, index) -> (index, index, index) + %18 = fir.shift %17#0 : (index) -> !fir.shift<1> + %19 = fir.array_coor %14(%18) %16 : (!fir.box>>, !fir.shift<1>, i64) -> !fir.ref + fir.store %c42_i32 to %19 : !fir.ref + } + } + + return +} + +// CHECK-LABEL: func.func @_QPlocalizer_with_init_region() { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 42 : i32 +// CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i"} +// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_3]] {uniq_name = "_QFlocalizer_with_init_regionEi"} : (!fir.ref) -> !fir.ref +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]] = fir.alloca i32 {bindc_name = "n", uniq_name = "_QFlocalizer_with_init_regionEn"} +// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_6]] {uniq_name = "_QFlocalizer_with_init_regionEn"} : (!fir.ref) -> !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box>> {bindc_name = "p", uniq_name = "_QFlocalizer_with_init_regionEp"} +// CHECK: %[[VAL_9:.*]] = fir.zero_bits !fir.ptr> +// CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_11:.*]] = fir.embox %[[VAL_9]](%[[VAL_10]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +// CHECK: fir.store %[[VAL_11]] to %[[VAL_8]] : !fir.ref>>> +// CHECK: %[[VAL_12:.*]] = fir.declare %[[VAL_8]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocalizer_with_init_regionEp"} : (!fir.ref>>>) -> !fir.ref>>> +// CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_7]] : !fir.ref +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> index +// CHECK: fir.do_loop %[[VAL_15:.*]] = %[[VAL_1]] to %[[VAL_14]] step %[[VAL_1]] unordered { + +// Local allocation +// CHECK: %[[VAL_16:.*]] = fir.alloca !fir.box>> + +// `init` region body +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_18:.*]] = fir.zero_bits !fir.ptr> +// CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_18]](%[[VAL_17]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +// CHECK: fir.store %[[VAL_19]] to %[[VAL_16]] : !fir.ref>>> + +// `copy` region body +// CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_12]] : !fir.ref>>> +// CHECK: fir.store %[[VAL_20]] to %[[VAL_16]] : !fir.ref>>> + +// loop body +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_15]] : (index) -> i32 +// CHECK: fir.store %[[VAL_21]] to %[[VAL_4]] : !fir.ref +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_16]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFlocalizer_with_init_regionEp"} : (!fir.ref>>>) -> !fir.ref>>> +// CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]] : !fir.ref>>> +// CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_4]] : !fir.ref +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (i32) -> i64 +// CHECK: %[[VAL_26:.*]]:3 = fir.box_dims %[[VAL_23]], %[[VAL_0]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_27:.*]] = fir.shift %[[VAL_26]]#0 : (index) -> !fir.shift<1> +// CHECK: %[[VAL_28:.*]] = fir.array_coor %[[VAL_23]](%[[VAL_27]]) %[[VAL_25]] : (!fir.box>>, !fir.shift<1>, i64) -> !fir.ref +// CHECK: fir.store %[[VAL_2]] to %[[VAL_28]] : !fir.ref +// CHECK: } +// CHECK: return +// CHECK: } + diff --git a/flang/test/Transforms/lower-repack-arrays.fir b/flang/test/Transforms/lower-repack-arrays.fir index 012e957173ac..458869cce45f 100644 --- a/flang/test/Transforms/lower-repack-arrays.fir +++ b/flang/test/Transforms/lower-repack-arrays.fir @@ -22,7 +22,7 @@ func.func @_QPtest1(%arg0: !fir.box> {fir.bindc_name = "x"}) // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -52,7 +52,7 @@ func.func @_QPtest1(%arg0: !fir.box> {fir.bindc_name = "x"}) // CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>) -> index // CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>) -> index // CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index -// CHECK: fir.if %[[VAL_33]] { +// CHECK: fir.if %[[VAL_33]] weights([0, 1]) { // CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>) -> !fir.box @@ -87,7 +87,7 @@ func.func @_QPtest1_whole(%arg0: !fir.box> {fir.bindc_name = // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -117,7 +117,7 @@ func.func @_QPtest1_whole(%arg0: !fir.box> {fir.bindc_name = // CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>) -> index // CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>) -> index // CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index -// CHECK: fir.if %[[VAL_33]] { +// CHECK: fir.if %[[VAL_33]] weights([0, 1]) { // CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>) -> !fir.box @@ -150,7 +150,7 @@ func.func @_QPtest1_in(%arg0: !fir.box> {fir.bindc_name = "x // CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> // CHECK: %[[VAL_11:.*]] = fir.is_present %[[VAL_10]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_12:.*]] = arith.andi %[[VAL_9]], %[[VAL_11]] : i1 -// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (!fir.box>) { +// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] weights([0, 1]) -> (!fir.box>) { // CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_14]]#1, %[[VAL_15]]#1 : (index, index) -> !fir.shape<2> @@ -180,7 +180,7 @@ func.func @_QPtest1_in(%arg0: !fir.box> {fir.bindc_name = "x // CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.heap>) -> index // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>) -> index // CHECK: %[[VAL_32:.*]] = arith.cmpi ne, %[[VAL_29]], %[[VAL_31]] : index -// CHECK: fir.if %[[VAL_32]] { +// CHECK: fir.if %[[VAL_32]] weights([0, 1]) { // CHECK: fir.freemem %[[VAL_28]] : !fir.heap> // CHECK: } // CHECK: } @@ -209,7 +209,7 @@ func.func @_QPtest1_out(%arg0: !fir.box> {fir.bindc_name = " // CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> // CHECK: %[[VAL_11:.*]] = fir.is_present %[[VAL_10]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_12:.*]] = arith.andi %[[VAL_9]], %[[VAL_11]] : i1 -// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (!fir.box>) { +// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] weights([0, 1]) -> (!fir.box>) { // CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_14]]#1, %[[VAL_15]]#1 : (index, index) -> !fir.shape<2> @@ -234,7 +234,7 @@ func.func @_QPtest1_out(%arg0: !fir.box> {fir.bindc_name = " // CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.heap>) -> index // CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (!fir.heap>) -> index // CHECK: %[[VAL_28:.*]] = arith.cmpi ne, %[[VAL_25]], %[[VAL_27]] : index -// CHECK: fir.if %[[VAL_28]] { +// CHECK: fir.if %[[VAL_28]] weights([0, 1]) { // CHECK: %[[VAL_29:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_7]] : (!fir.box>) -> !fir.box @@ -280,7 +280,7 @@ func.func @_QPtest2(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.box // CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_18:.*]] = fir.is_present %[[VAL_17]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_19:.*]] = arith.andi %[[VAL_16]], %[[VAL_18]] : i1 -// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] -> (!fir.box>>) { +// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_22:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_21]]#1, %[[VAL_22]]#1 : (index, index) -> !fir.shape<2> @@ -310,7 +310,7 @@ func.func @_QPtest2(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.box // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (!fir.heap>>) -> index // CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index // CHECK: %[[VAL_39:.*]] = arith.cmpi ne, %[[VAL_36]], %[[VAL_38]] : index -// CHECK: fir.if %[[VAL_39]] { +// CHECK: fir.if %[[VAL_39]] weights([0, 1]) { // CHECK: %[[VAL_40:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_14]] : (!fir.box>>) -> !fir.box @@ -356,7 +356,7 @@ func.func @_QPtest2_stack(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !f // CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_18:.*]] = fir.is_present %[[VAL_17]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_19:.*]] = arith.andi %[[VAL_16]], %[[VAL_18]] : i1 -// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] -> (!fir.box>>) { +// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_22:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_21]]#1, %[[VAL_22]]#1 : (index, index) -> !fir.shape<2> @@ -386,7 +386,7 @@ func.func @_QPtest2_stack(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !f // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (!fir.heap>>) -> index // CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index // CHECK: %[[VAL_39:.*]] = arith.cmpi ne, %[[VAL_36]], %[[VAL_38]] : index -// CHECK: fir.if %[[VAL_39]] { +// CHECK: fir.if %[[VAL_39]] weights([0, 1]) { // CHECK: %[[VAL_40:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_14]] : (!fir.box>>) -> !fir.box @@ -420,7 +420,7 @@ func.func @_QPtest3(%arg0: !fir.box>> {fir.bindc_n // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box>>) -> index @@ -451,7 +451,7 @@ func.func @_QPtest3(%arg0: !fir.box>> {fir.bindc_n // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index // CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index -// CHECK: fir.if %[[VAL_34]] { +// CHECK: fir.if %[[VAL_34]] weights([0, 1]) { // CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box @@ -486,7 +486,7 @@ func.func @_QPtest3_stack(%arg0: !fir.box>> {fir.b // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box>>) -> index @@ -517,7 +517,7 @@ func.func @_QPtest3_stack(%arg0: !fir.box>> {fir.b // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index // CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index -// CHECK: fir.if %[[VAL_34]] { +// CHECK: fir.if %[[VAL_34]] weights([0, 1]) { // CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box @@ -553,7 +553,7 @@ func.func @_QPtest4(%arg0: !fir.box>> {fir.bindc_ // CHECK: %[[VAL_12:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_12]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_14:.*]] = arith.andi %[[VAL_11]], %[[VAL_13]] : i1 -// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_16]]#1, %[[VAL_17]]#1 : (index, index) -> !fir.shape<2> @@ -583,7 +583,7 @@ func.func @_QPtest4(%arg0: !fir.box>> {fir.bindc_ // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index // CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index -// CHECK: fir.if %[[VAL_34]] { +// CHECK: fir.if %[[VAL_34]] weights([0, 1]) { // CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_9]] : (!fir.box>>) -> !fir.box @@ -620,7 +620,7 @@ func.func @_QPtest4_stack(%arg0: !fir.box>> {fir. // CHECK: %[[VAL_12:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_12]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_14:.*]] = arith.andi %[[VAL_11]], %[[VAL_13]] : i1 -// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_16]]#1, %[[VAL_17]]#1 : (index, index) -> !fir.shape<2> @@ -650,7 +650,7 @@ func.func @_QPtest4_stack(%arg0: !fir.box>> {fir. // CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index // CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index -// CHECK: fir.if %[[VAL_34]] { +// CHECK: fir.if %[[VAL_34]] weights([0, 1]) { // CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_9]] : (!fir.box>>) -> !fir.box @@ -684,7 +684,7 @@ func.func @_QPtest5(%arg0: !fir.box>> {fir.bind // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -714,7 +714,7 @@ func.func @_QPtest5(%arg0: !fir.box>> {fir.bind // CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>>) -> index // CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index -// CHECK: fir.if %[[VAL_33]] { +// CHECK: fir.if %[[VAL_33]] weights([0, 1]) { // CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box @@ -749,7 +749,7 @@ func.func @_QPtest5_stack(%arg0: !fir.box>> {fi // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.box>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -779,7 +779,7 @@ func.func @_QPtest5_stack(%arg0: !fir.box>> {fi // CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>>) -> index // CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>>) -> index // CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index -// CHECK: fir.if %[[VAL_33]] { +// CHECK: fir.if %[[VAL_33]] weights([0, 1]) { // CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} // CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box @@ -814,7 +814,7 @@ func.func @_QPtest6(%arg0: !fir.class>> {fir.bi // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[ARG0]] : (!fir.class>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.class>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.class>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_3]] : (!fir.class>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_2]] : (!fir.class>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -853,7 +853,7 @@ func.func @_QPtest6(%arg0: !fir.class>> {fir.bi // CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index // CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.heap>>) -> index // CHECK: %[[VAL_41:.*]] = arith.cmpi ne, %[[VAL_39]], %[[VAL_40]] : index -// CHECK: fir.if %[[VAL_41]] { +// CHECK: fir.if %[[VAL_41]] weights([0, 1]) { // CHECK: %[[VAL_42:.*]] = fir.address_of(@{{_QQcl.*}}) : !fir.ref> // CHECK: %[[VAL_43:.*]] = fir.convert %[[ARG0]] : (!fir.class>>) -> !fir.box // CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_8]] : (!fir.class>>) -> !fir.box @@ -890,7 +890,7 @@ func.func @_QPtest6_stack(%arg0: !fir.class>> { // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[ARG0]] : (!fir.class>>) -> !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.class>>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.class>>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_3]] : (!fir.class>>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_2]] : (!fir.class>>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -929,7 +929,7 @@ func.func @_QPtest6_stack(%arg0: !fir.class>> { // CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index // CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.heap>>) -> index // CHECK: %[[VAL_41:.*]] = arith.cmpi ne, %[[VAL_39]], %[[VAL_40]] : index -// CHECK: fir.if %[[VAL_41]] { +// CHECK: fir.if %[[VAL_41]] weights([0, 1]) { // CHECK: %[[VAL_42:.*]] = fir.address_of(@{{_QQcl.*}}) : !fir.ref> // CHECK: %[[VAL_43:.*]] = fir.convert %[[ARG0]] : (!fir.class>>) -> !fir.box // CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_8]] : (!fir.class>>) -> !fir.box @@ -965,7 +965,7 @@ func.func @_QPtest7(%arg0: !fir.class> {fir.bindc_name = "x // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[ARG0]] : (!fir.class>) -> !fir.ref>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.class>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.class>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_3]] : (!fir.class>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_2]] : (!fir.class>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -1004,7 +1004,7 @@ func.func @_QPtest7(%arg0: !fir.class> {fir.bindc_name = "x // CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>) -> index // CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.heap>) -> index // CHECK: %[[VAL_41:.*]] = arith.cmpi ne, %[[VAL_39]], %[[VAL_40]] : index -// CHECK: fir.if %[[VAL_41]] { +// CHECK: fir.if %[[VAL_41]] weights([0, 1]) { // CHECK: %[[VAL_42:.*]] = fir.address_of(@{{_QQcl.*}}) : !fir.ref> // CHECK: %[[VAL_43:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box // CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_8]] : (!fir.class>) -> !fir.box @@ -1041,7 +1041,7 @@ func.func @_QPtest7_stack(%arg0: !fir.class> {fir.bindc_nam // CHECK: %[[VAL_11:.*]] = fir.box_addr %[[ARG0]] : (!fir.class>) -> !fir.ref>> // CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 // CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 -// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.class>) { +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] weights([0, 1]) -> (!fir.class>) { // CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_3]] : (!fir.class>, index) -> (index, index, index) // CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[ARG0]], %[[VAL_2]] : (!fir.class>, index) -> (index, index, index) // CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> @@ -1080,7 +1080,7 @@ func.func @_QPtest7_stack(%arg0: !fir.class> {fir.bindc_nam // CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>) -> index // CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.heap>) -> index // CHECK: %[[VAL_41:.*]] = arith.cmpi ne, %[[VAL_39]], %[[VAL_40]] : index -// CHECK: fir.if %[[VAL_41]] { +// CHECK: fir.if %[[VAL_41]] weights([0, 1]) { // CHECK: %[[VAL_42:.*]] = fir.address_of(@{{_QQcl.*}}) : !fir.ref> // CHECK: %[[VAL_43:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box // CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_8]] : (!fir.class>) -> !fir.box diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index c80872108ac8..015c86604a1f 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -434,6 +434,8 @@ static llvm::LogicalResult convertFortranSourceToMLIR( loweringOptions.setStackRepackArrays(stackRepackArrays); loweringOptions.setRepackArrays(repackArrays); loweringOptions.setRepackArraysWhole(repackArraysWhole); + if (enableCUDA) + loweringOptions.setCUDARuntimeCheck(true); std::vector envDefaults = {}; Fortran::frontend::TargetOptions targetOpts; Fortran::frontend::CodeGenOptions cgOpts; diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index f21fc2fba730..9907adfc55a5 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -135,6 +135,7 @@ endif() option(LLVM_LIBC_FULL_BUILD "Build and test LLVM libc as if it is the full libc" ${default_to_full_build}) option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON) option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF) +option(LLVM_LIBC_ALL_HEADERS "Outputs all functions in header files, regardless of whether they are enabled on this target" OFF) option(LIBC_CONFIG_PATH "The path to user provided folder that configures the build for the target system." OFF) diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index 0facb0b9be0c..82d06e2b9eb5 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -106,6 +106,10 @@ function(_get_compile_options_from_config output_var) list(APPEND config_options "-DLIBC_MATH=${LIBC_CONF_MATH_OPTIMIZATIONS}") endif() + if(LIBC_CONF_ERRNO_MODE) + list(APPEND config_options "-DLIBC_ERRNO_MODE=${LIBC_CONF_ERRNO_MODE}") + endif() + set(${output_var} ${config_options} PARENT_SCOPE) endfunction(_get_compile_options_from_config) diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake index 99f90244e013..01c288f0b919 100644 --- a/libc/cmake/modules/LLVMLibCHeaderRules.cmake +++ b/libc/cmake/modules/LLVMLibCHeaderRules.cmake @@ -97,8 +97,13 @@ function(add_gen_header target_name) set(out_file ${LIBC_INCLUDE_DIR}/${relative_path}) set(dep_file "${out_file}.d") set(yaml_file ${CMAKE_SOURCE_DIR}/${ADD_GEN_HDR_YAML_FILE}) + + if(LLVM_LIBC_ALL_HEADERS) + set(entry_points "") + else() + set(entry_points "${TARGET_ENTRYPOINT_NAME_LIST}") + endif() - set(entry_points "${TARGET_ENTRYPOINT_NAME_LIST}") list(TRANSFORM entry_points PREPEND "--entry-point=") add_custom_command( diff --git a/libc/config/config.json b/libc/config/config.json index bfe956855cb5..d53b2936edb0 100644 --- a/libc/config/config.json +++ b/libc/config/config.json @@ -2,7 +2,7 @@ "errno": { "LIBC_CONF_ERRNO_MODE": { "value": "LIBC_ERRNO_MODE_DEFAULT", - "doc": "The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM." + "doc": "The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, LIBC_ERRNO_MODE_SYSTEM, and LIBC_ERRNO_MODE_SYSTEM_INLINE." } }, "printf": { diff --git a/libc/config/darwin/aarch64/config.json b/libc/config/darwin/aarch64/config.json new file mode 100644 index 000000000000..c82f13e5cbf7 --- /dev/null +++ b/libc/config/darwin/aarch64/config.json @@ -0,0 +1,8 @@ +{ + "setjmp": { + "LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER": { + "value": false, + "doc": "Avoid setjmp saving the value of x18, and longjmp restoring it. The Apple AArch64 ABI specifies that this register is reserved and should not be used" + } + } +} diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt index 308fc49d681d..437eca79a76f 100644 --- a/libc/config/darwin/aarch64/entrypoints.txt +++ b/libc/config/darwin/aarch64/entrypoints.txt @@ -101,6 +101,17 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.free ) +if(LLVM_LIBC_FULL_BUILD) + list(APPEND TARGET_LIBC_ENTRYPOINTS + # setjmp.h entrypoints + libc.src.setjmp.longjmp + libc.src.setjmp.setjmp + libc.src.setjmp.siglongjmp + libc.src.setjmp.sigsetjmp + ) +endif() + + set(TARGET_LIBM_ENTRYPOINTS # complex.h entrypoints libc.src.complex.creal diff --git a/libc/config/darwin/aarch64/headers.txt b/libc/config/darwin/aarch64/headers.txt index 86e714597232..8f3d6029c9b6 100644 --- a/libc/config/darwin/aarch64/headers.txt +++ b/libc/config/darwin/aarch64/headers.txt @@ -7,6 +7,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.inttypes libc.include.limits libc.include.math + libc.include.setjmp libc.include.stdlib libc.include.string libc.include.strings diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 520046f768b5..9e042cd4a8ac 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -245,6 +245,9 @@ set(TARGET_LIBC_ENTRYPOINTS # https://github.com/llvm/llvm-project/issues/80060 # libc.src.sys.epoll.epoll_pwait2 + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mincore @@ -969,6 +972,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.getc_unlocked libc.src.stdio.getchar libc.src.stdio.getchar_unlocked + libc.src.stdio.perror libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 7432a7e912e8..1161ae260be2 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -172,6 +172,9 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.free libc.src.stdlib.malloc + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.mmap libc.src.sys.mman.munmap diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 0b645a2d2fb8..db8f8a7cf0b7 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -246,6 +246,9 @@ set(TARGET_LIBC_ENTRYPOINTS # https://github.com/llvm/llvm-project/issues/80060 # libc.src.sys.epoll.epoll_pwait2 + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mincore @@ -1095,6 +1098,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.getc_unlocked libc.src.stdio.getchar libc.src.stdio.getchar_unlocked + libc.src.stdio.perror libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 959bdbf08dbe..4d94f10196fd 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -246,6 +246,9 @@ set(TARGET_LIBC_ENTRYPOINTS # https://github.com/llvm/llvm-project/issues/80060 # libc.src.sys.epoll.epoll_pwait2 + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mincore @@ -364,6 +367,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.wchar.btowc libc.src.wchar.wcslen libc.src.wchar.wctob + libc.src.wchar.wmemmove libc.src.wchar.wmemset libc.src.wchar.wcschr libc.src.wchar.wcsncmp @@ -1113,6 +1117,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.getc_unlocked libc.src.stdio.getchar libc.src.stdio.getchar_unlocked + libc.src.stdio.perror libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts @@ -1239,6 +1244,10 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.sys.socket.recv libc.src.sys.socket.recvfrom libc.src.sys.socket.recvmsg + + # wchar.h entrypoints + libc.src.wchar.mbrtowc + libc.src.wchar.wcrtomb ) endif() diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst index 8d53390ae19b..109412225634 100644 --- a/libc/docs/configure.rst +++ b/libc/docs/configure.rst @@ -29,7 +29,7 @@ to learn about the defaults for your platform and target. - ``LIBC_CONF_ENABLE_STRONG_STACK_PROTECTOR``: Enable -fstack-protector-strong to defend against stack smashing attack. - ``LIBC_CONF_KEEP_FRAME_POINTER``: Keep frame pointer in functions for better debugging experience. * **"errno" options** - - ``LIBC_CONF_ERRNO_MODE``: The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM. + - ``LIBC_CONF_ERRNO_MODE``: The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, LIBC_ERRNO_MODE_SYSTEM, and LIBC_ERRNO_MODE_SYSTEM_INLINE. * **"general" options** - ``LIBC_ADD_NULL_CHECKS``: Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior. * **"math" options** diff --git a/libc/docs/dev/code_style.rst b/libc/docs/dev/code_style.rst index 0bd3a69ae3ff..86247966552f 100644 --- a/libc/docs/dev/code_style.rst +++ b/libc/docs/dev/code_style.rst @@ -101,7 +101,7 @@ test infrastructure itself can be affected. To avoid perturbing the unit test infrastructure around the setting of ``errno``, the following rules are to be followed: -#. A special macro named ``libc_errno`` defined in ``src/errno/libc_errno.h`` +#. A special macro named ``libc_errno`` defined in ``src/__support/libc_errno.h`` should be used when setting ``errno`` from libc runtime code. For example, code to set ``errno`` to ``EINVAL`` should be: @@ -117,7 +117,7 @@ followed: `ErrorOr `_ to return error values. -#. The header file ``src/errno/libc_errno.h`` is shipped as part of the target +#. The header file ``src/__support/libc_errno.h`` is shipped as part of the target corresponding to the ``errno`` entrypoint ``libc.src.errno.errno``. We do not in general allow dependencies between entrypoints. However, the ``errno`` entrypoint is the only exceptional entrypoint on which other entrypoints diff --git a/libc/fuzzing/stdio/CMakeLists.txt b/libc/fuzzing/stdio/CMakeLists.txt index 8f89baa70200..401785a30469 100644 --- a/libc/fuzzing/stdio/CMakeLists.txt +++ b/libc/fuzzing/stdio/CMakeLists.txt @@ -4,6 +4,7 @@ add_libc_fuzzer( printf_parser_fuzz.cpp DEPENDS libc.src.stdio.printf_core.parser + libc.src.errno.errno # needed for the strerror conversion ) add_libc_fuzzer( diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt index 209fcb965242..052a773a4fce 100644 --- a/libc/hdr/CMakeLists.txt +++ b/libc/hdr/CMakeLists.txt @@ -126,6 +126,15 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_epoll_macros ) +add_proxy_header_library( + sys_ioctl_macros + HDRS + sys_ioctl_macros.h + FULL_BUILD_DEPENDS + libc.include.sys_ioctl + libc.include.llvm-libc-macros.sys_ioctl_macros +) + add_proxy_header_library( sys_stat_macros HDRS @@ -212,6 +221,8 @@ add_proxy_header_library( add_header_library(wchar_overlay HDRS wchar_overlay.h) +add_header_library(uchar_overlay HDRS uchar_overlay.h) + add_proxy_header_library( wchar_macros HDRS diff --git a/libc/hdr/sys_ioctl_macros.h b/libc/hdr/sys_ioctl_macros.h new file mode 100644 index 000000000000..935d43627346 --- /dev/null +++ b/libc/hdr/sys_ioctl_macros.h @@ -0,0 +1,22 @@ +//===-- Definition of macros from sys/ioctl.h -----------------------------===// +// +// 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_LIBC_HDR_SYS_IOCTL_MACROS_H +#define LLVM_LIBC_HDR_SYS_IOCTL_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/sys-ioctl-macros.h" + +#else // Overlay mode + +#include + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_SYS_IOCTL_MACROS_H diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt index 5f6197c93d44..e4b3cb0faa82 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -1,3 +1,33 @@ +add_proxy_header_library( + char8_t + HDRS + char8_t.h + DEPENDS + libc.hdr.uchar_overlay + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.char8_t + libc.include.uchar +) + +add_proxy_header_library( + char32_t + HDRS + char32_t.h + DEPENDS + libc.hdr.uchar_overlay + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.char32_t + libc.include.uchar +) + +add_proxy_header_library( + mbstate_t + HDRS + mbstate_t.h + DEPENDS + libc.include.llvm-libc-types.mbstate_t +) + add_proxy_header_library( div_t HDRS diff --git a/libc/hdr/types/char32_t.h b/libc/hdr/types/char32_t.h new file mode 100644 index 000000000000..94fe5747d341 --- /dev/null +++ b/libc/hdr/types/char32_t.h @@ -0,0 +1,22 @@ +//===-- Definition of char32_t.h ------------------------------------------===// +// +// 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_LIBC_HDR_TYPES_CHAR32_T_H +#define LLVM_LIBC_HDR_TYPES_CHAR32_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/char32_t.h" + +#else // overlay mode + +#include "hdr/uchar_overlay.h" + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_CHAR32_T_H diff --git a/libc/hdr/types/char8_t.h b/libc/hdr/types/char8_t.h new file mode 100644 index 000000000000..4d71e3dd8909 --- /dev/null +++ b/libc/hdr/types/char8_t.h @@ -0,0 +1,14 @@ +//===-- Definition of char8_t.h -------------------------------------------===// +// +// 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_LIBC_HDR_TYPES_CHAR8_T_H +#define LLVM_LIBC_HDR_TYPES_CHAR8_T_H + +#include "include/llvm-libc-types/char8_t.h" + +#endif // LLVM_LIBC_HDR_TYPES_CHAR8_T_H diff --git a/libc/hdr/types/mbstate_t.h b/libc/hdr/types/mbstate_t.h new file mode 100644 index 000000000000..d8fadceaaac8 --- /dev/null +++ b/libc/hdr/types/mbstate_t.h @@ -0,0 +1,22 @@ +//===-- Definition of macros from mbstate_t.h -----------------------------===// +// +// 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_LIBC_HDR_TYPES_MBSTATE_T_H +#define LLVM_LIBC_HDR_TYPES_MBSTATE_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/mbstate_t.h" + +#else // Overlay mode + +#error "Cannot overlay mbstate_t" + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_MBSTATE_T_H diff --git a/libc/hdr/uchar_overlay.h b/libc/hdr/uchar_overlay.h new file mode 100644 index 000000000000..44ed3d48c6c1 --- /dev/null +++ b/libc/hdr/uchar_overlay.h @@ -0,0 +1,69 @@ +//===-- Including uchar.h in overlay mode ---------------------------------===// +// +// 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_LIBC_HDR_UCHAR_OVERLAY_H +#define LLVM_LIBC_HDR_UCHAR_OVERLAY_H + +#ifdef LIBC_FULL_BUILD +#error "This header should only be included in overlay mode" +#endif + +// Overlay mode + +// glibc header might provide extern inline definitions for few +// functions, causing external alias errors. They are guarded by +// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES` +// macro by defining `__NO_INLINE__` before including . +// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled +// with `_FORTIFY_SOURCE`. + +#ifdef _FORTIFY_SOURCE +#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif + +#ifndef __NO_INLINE__ +#define __NO_INLINE__ 1 +#define LIBC_SET_NO_INLINE +#endif + +#ifdef __USE_EXTERN_INLINES +#define LIBC_OLD_USE_EXTERN_INLINES +#undef __USE_EXTERN_INLINES +#endif + +#ifdef __USE_FORTIFY_LEVEL +#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL 0 +#endif + +#include + +#ifdef LIBC_OLD_FORTIFY_SOURCE +#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE +#undef LIBC_OLD_FORTIFY_SOURCE +#endif + +#ifdef LIBC_SET_NO_INLINE +#undef __NO_INLINE__ +#undef LIBC_SET_NO_INLINE +#endif + +#ifdef LIBC_OLD_USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL +#undef LIBC_OLD_USE_FORTIFY_LEVEL +#endif + +#ifdef LIBC_OLD_USE_EXTERN_INLINES +#define __USE_EXTERN_INLINES +#undef LIBC_OLD_USE_EXTERN_INLINES +#endif + +#endif // LLVM_LIBC_HDR_UCHAR_OVERLAY_H diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 7209e10c68b8..55268d19529c 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -255,6 +255,7 @@ add_header_macro( time.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.null_macro .llvm-libc-macros.time_macros .llvm-libc-types.clock_t .llvm-libc-types.time_t @@ -329,6 +330,7 @@ add_header_macro( stdio.h DEPENDS .llvm-libc-macros.file_seek_macros + .llvm-libc-macros.null_macro .llvm-libc-macros.stdio_macros .llvm-libc-types.FILE .llvm-libc-types.cookie_io_functions_t @@ -343,6 +345,7 @@ add_header_macro( ../libc/include/stdlib.yaml stdlib.h DEPENDS + .llvm-libc-macros.null_macro .llvm-libc-macros.stdlib_macros .llvm-libc-types.__atexithandler_t .llvm-libc-types.__qsortcompare_t @@ -709,6 +712,7 @@ add_header_macro( wchar.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.null_macro .llvm-libc-macros.wchar_macros .llvm-libc-types.mbstate_t .llvm-libc-types.size_t @@ -723,6 +727,7 @@ add_header_macro( DEPENDS .llvm_libc_common_h .llvm-libc-macros.locale_macros + .llvm-libc-macros.null_macro .llvm-libc-types.locale_t .llvm-libc-types.struct_lconv ) diff --git a/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h index 5eb779aeeca5..41226080084c 100644 --- a/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h +++ b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h @@ -15,5 +15,6 @@ // around the definitions of macros like _IO, _IOR, _IOW, and _IOWR that I don't // think is worth digging into right now. #define TIOCGETD 0x5424 +#define FIONREAD 0x541B #endif // LLVM_LIBC_MACROS_LINUX_SYS_IOCTL_MACROS_H diff --git a/libc/include/llvm-libc-types/char8_t.h b/libc/include/llvm-libc-types/char8_t.h index ddadab1afa21..a343be77d810 100644 --- a/libc/include/llvm-libc-types/char8_t.h +++ b/libc/include/llvm-libc-types/char8_t.h @@ -9,8 +9,7 @@ #ifndef LLVM_LIBC_TYPES_CHAR8_T_H #define LLVM_LIBC_TYPES_CHAR8_T_H -#if !defined(__cplusplus) && defined(__STDC_VERSION__) && \ - __STDC_VERSION__ >= 202311L +#if !(defined(__cplusplus) && defined(__cpp_char8_t)) typedef unsigned char char8_t; #endif diff --git a/libc/include/llvm-libc-types/mbstate_t.h b/libc/include/llvm-libc-types/mbstate_t.h index 540d50975a26..009fe57da50e 100644 --- a/libc/include/llvm-libc-types/mbstate_t.h +++ b/libc/include/llvm-libc-types/mbstate_t.h @@ -9,8 +9,12 @@ #ifndef LLVM_LIBC_TYPES_MBSTATE_T_H #define LLVM_LIBC_TYPES_MBSTATE_T_H -// TODO: Complete this once we implement functions that operate on this type. +#include "../llvm-libc-macros/stdint-macros.h" + typedef struct { + uint32_t __field1; + uint8_t __field2; + uint8_t __field3; } mbstate_t; #endif // LLVM_LIBC_TYPES_MBSTATE_T_H diff --git a/libc/include/llvm-libc-types/size_t.h b/libc/include/llvm-libc-types/size_t.h index 3b31b0820f23..26ae68abe0ee 100644 --- a/libc/include/llvm-libc-types/size_t.h +++ b/libc/include/llvm-libc-types/size_t.h @@ -9,11 +9,6 @@ #ifndef LLVM_LIBC_TYPES_SIZE_T_H #define LLVM_LIBC_TYPES_SIZE_T_H -// Since __need_size_t is defined, we get the definition of size_t from the -// standalone C header stddef.h. Also, because __need_size_t is defined, -// including stddef.h will pull only the type size_t and nothing else. -#define __need_size_t -#include -#undef __need_size_t +typedef __SIZE_TYPE__ size_t; #endif // LLVM_LIBC_TYPES_SIZE_T_H diff --git a/libc/include/llvm-libc-types/ssize_t.h b/libc/include/llvm-libc-types/ssize_t.h index 41e4b6d2c500..8f579e2749ba 100644 --- a/libc/include/llvm-libc-types/ssize_t.h +++ b/libc/include/llvm-libc-types/ssize_t.h @@ -9,6 +9,6 @@ #ifndef LLVM_LIBC_TYPES_SSIZE_T_H #define LLVM_LIBC_TYPES_SSIZE_T_H -typedef __INT64_TYPE__ ssize_t; +typedef __PTRDIFF_TYPE__ ssize_t; #endif // LLVM_LIBC_TYPES_SSIZE_T_H diff --git a/libc/include/locale.yaml b/libc/include/locale.yaml index 6c71b70e59f0..4566984ad83a 100644 --- a/libc/include/locale.yaml +++ b/libc/include/locale.yaml @@ -1,5 +1,8 @@ header: locale.h header_template: locale.h.def +macros: + - macro_name: NULL + macro_header: null-macro.h types: - type_name: locale_t - type_name: struct_lconv diff --git a/libc/include/math.yaml b/libc/include/math.yaml index 466c08ade6fc..11bead074595 100644 --- a/libc/include/math.yaml +++ b/libc/include/math.yaml @@ -734,7 +734,7 @@ functions: - type: float128 - type: float128 - type: float128 - guards: LIBC_TYPES_HAS_FLOAT128 + guard: LIBC_TYPES_HAS_FLOAT128 - name: ffmal standards: - stdc diff --git a/libc/include/stdio.yaml b/libc/include/stdio.yaml index 2619984cca26..2a0c56370998 100644 --- a/libc/include/stdio.yaml +++ b/libc/include/stdio.yaml @@ -1,6 +1,8 @@ header: stdio.h header_template: stdio.h.def macros: + - macro_name: NULL + macro_header: null-macro.h - macro_name: stdout macro_value: stdout - macro_name: stdin @@ -247,6 +249,12 @@ functions: - POSIX return_type: int arguments: [] + - name: perror + standards: + - stdc + return_type: void + arguments: + - type: const char * - name: printf standards: - stdc diff --git a/libc/include/stdlib.yaml b/libc/include/stdlib.yaml index f7155ba27a16..3b2ff13c684b 100644 --- a/libc/include/stdlib.yaml +++ b/libc/include/stdlib.yaml @@ -4,7 +4,9 @@ standards: - stdc merge_yaml_files: - stdlib-malloc.yaml -macros: [] +macros: + - macro_name: NULL + macro_header: null-macro.h types: - type_name: __atexithandler_t - type_name: __qsortcompare_t diff --git a/libc/include/string.h.def b/libc/include/string.h.def index 1bd2687db2be..339d005e43a4 100644 --- a/libc/include/string.h.def +++ b/libc/include/string.h.def @@ -11,8 +11,6 @@ #include "__llvm-libc-common.h" -#include "llvm-libc-macros/null-macro.h" - %%public_api() #endif // LLVM_LIBC_STRING_H diff --git a/libc/include/string.yaml b/libc/include/string.yaml index 9f72b8db6c1e..736deceb453d 100644 --- a/libc/include/string.yaml +++ b/libc/include/string.yaml @@ -1,6 +1,8 @@ header: string.h header_template: string.h.def -macros: [] +macros: + - macro_name: NULL + macro_header: null-macro.h types: - type_name: locale_t - type_name: size_t diff --git a/libc/include/time.yaml b/libc/include/time.yaml index 7bb25dbe85ac..3b9d77c0aaae 100644 --- a/libc/include/time.yaml +++ b/libc/include/time.yaml @@ -1,6 +1,8 @@ header: time.h header_template: time.h.def -macros: [] +macros: + - macro_name: NULL + macro_header: null-macro.h types: - type_name: struct_timeval - type_name: clockid_t diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 877be48b6a10..64eb38171066 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -1,6 +1,8 @@ header: wchar.h header_template: wchar.h.def -macros: [] +macros: + - macro_name: NULL + macro_header: null-macro.h types: - type_name: size_t - type_name: wint_t @@ -27,6 +29,15 @@ functions: return_type: wint_t arguments: - type: int + - name: mbrtowc + standards: + - stdc + return_type: size_t + arguments: + - type: wchar_t *__restrict + - type: const char *__restrict + - type: size_t + - type: mbstate_t *__restrict - name: wmemset standards: - stdc @@ -107,24 +118,32 @@ functions: - stdc return_type: wchar_t * arguments: - - type: __restrict wchar_t * - - type: const __restrict wchar_t * + - type: wchar_t *__restrict + - type: const wchar_t *__restrict + - type: size_t + - name: wmemmove + standards: + - stdc + return_type: wchar_t * + arguments: + - type: wchar_t * + - type: const wchar_t * - type: size_t - name: wcsncpy standards: - stdc return_type: wchar_t * arguments: - - type: __restrict wchar_t * - - type: const __restrict wchar_t * + - type: wchar_t *__restrict + - type: const wchar_t *__restrict - type: size_t - name: wcscat standards: - stdc return_type: wchar_t * arguments: - - type: __restrict wchar_t * - - type: const __restrict wchar_t * + - type: wchar_t *__restrict + - type: const wchar_t *__restrict - name: wcsstr standards: - stdc @@ -137,13 +156,21 @@ functions: - stdc return_type: wchar_t * arguments: - - type: __restrict wchar_t * - - type: const __restrict wchar_t * + - type: wchar_t *__restrict + - type: const wchar_t *__restrict - type: size_t + - name: wcrtomb + standards: + - stdc + return_type: size_t + arguments: + - type: char *__restrict + - type: wchar_t + - type: mbstate_t *__restrict - name: wcscpy standards: - stdc return_type: wchar_t * arguments: - - type: __restrict wchar_t * - - type: const __restrict wchar_t * + - type: wchar_t *__restrict + - type: const wchar_t *__restrict diff --git a/libc/shared/fp_bits.h b/libc/shared/fp_bits.h index 2898c508b777..e6bb1e17b80c 100644 --- a/libc/shared/fp_bits.h +++ b/libc/shared/fp_bits.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SHARED_FP_BITS_H #define LLVM_LIBC_SHARED_FP_BITS_H +#include "libc_common.h" #include "src/__support/FPUtil/FPBits.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/shared/libc_common.h b/libc/shared/libc_common.h new file mode 100644 index 000000000000..c4560bbb0276 --- /dev/null +++ b/libc/shared/libc_common.h @@ -0,0 +1,26 @@ +//===-- Common defines for sharing LLVM libc with LLVM projects -*- 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_LIBC_SHARED_LIBC_COMMON_H +#define LLVM_LIBC_SHARED_LIBC_COMMON_H + +// Use system errno. +#ifdef LIBC_ERRNO_MODE +#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE +#error \ + "LIBC_ERRNO_MODE was set to something different from LIBC_ERRNO_MODE_SYSTEM_INLINE." +#endif // LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE +#else +#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM_INLINE +#endif // LIBC_ERRNO_MODE + +#ifndef LIBC_NAMESPACE +#define LIBC_NAMESPACE __llvm_libc +#endif // LIBC_NAMESPACE + +#endif // LLVM_LIBC_SHARED_LIBC_COMMON_H diff --git a/libc/shared/math.h b/libc/shared/math.h new file mode 100644 index 000000000000..4ddc29c7ae83 --- /dev/null +++ b/libc/shared/math.h @@ -0,0 +1,16 @@ +//===-- Floating point math functions ---------------------------*- 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_LIBC_SHARED_MATH_H +#define LLVM_LIBC_SHARED_MATH_H + +#include "libc_common.h" + +#include "math/expf.h" + +#endif // LLVM_LIBC_SHARED_MATH_H diff --git a/libc/shared/math/expf.h b/libc/shared/math/expf.h new file mode 100644 index 000000000000..a4e8b0751bb4 --- /dev/null +++ b/libc/shared/math/expf.h @@ -0,0 +1,23 @@ +//===-- Shared expf function ------------------------------------*- 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_LIBC_SHARED_MATH_EXPF_H +#define LLVM_LIBC_SHARED_MATH_EXPF_H + +#include "shared/libc_common.h" +#include "src/__support/math/expf.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::expf; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_EXPF_H diff --git a/libc/shared/rpc_server.h b/libc/shared/rpc_server.h index 5509094b944a..46e35f13f0ea 100644 --- a/libc/shared/rpc_server.h +++ b/libc/shared/rpc_server.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SHARED_RPC_SERVER_H #define LLVM_LIBC_SHARED_RPC_SERVER_H +#include "libc_common.h" #include "src/__support/RPC/rpc_server.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/shared/str_to_float.h b/libc/shared/str_to_float.h index b133a28e26ef..dcc6027d6c77 100644 --- a/libc/shared/str_to_float.h +++ b/libc/shared/str_to_float.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SHARED_STR_TO_FLOAT_H #define LLVM_LIBC_SHARED_STR_TO_FLOAT_H +#include "libc_common.h" #include "src/__support/str_to_float.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/shared/str_to_integer.h b/libc/shared/str_to_integer.h index 15bee698d5a6..6ed38c932662 100644 --- a/libc/shared/str_to_integer.h +++ b/libc/shared/str_to_integer.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SHARED_STR_TO_INTEGER_H #define LLVM_LIBC_SHARED_STR_TO_INTEGER_H +#include "libc_common.h" #include "src/__support/str_to_integer.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt index f92499fdbf45..7e85136c0885 100644 --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -1,6 +1,15 @@ add_subdirectory(CPP) add_subdirectory(macros) +add_header_library( + libc_errno + HDRS + libc_errno.h + DEPENDS + libc.hdr.errno_macros + libc.src.__support.macros.config +) + add_header_library( block HDRS @@ -381,3 +390,11 @@ add_subdirectory(HashTable) add_subdirectory(fixed_point) add_subdirectory(time) + +# Requires access to uchar header which is not on macos +# Therefore, cannot currently build this on macos in overlay mode +if(NOT(LIBC_TARGET_OS_IS_DARWIN)) + add_subdirectory(wchar) +endif() + +add_subdirectory(math) diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h index 4c8f34a435bd..76910880eb81 100644 --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -12,10 +12,11 @@ #include "hdr/fenv_macros.h" #include "hdr/math_macros.h" #include "hdr/types/fenv_t.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/architectures.h" -#include "src/errno/libc_errno.h" #if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP) #if defined(__APPLE__) @@ -71,27 +72,40 @@ LIBC_INLINE int set_env(const fenv_t *) { return 0; } namespace LIBC_NAMESPACE_DECL { namespace fputil { -LIBC_INLINE int clear_except_if_required(int excepts) { +LIBC_INLINE static int clear_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) return clear_except(excepts); +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE int set_except_if_required(int excepts) { +LIBC_INLINE static int set_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) return set_except(excepts); +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE int raise_except_if_required(int excepts) { +LIBC_INLINE static int raise_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) +#ifdef LIBC_TARGET_ARCH_IS_X86_64 + return raise_except(excepts); +#else // !LIBC_TARGET_ARCH_IS_X86 return raise_except(excepts); +#endif // LIBC_TARGET_ARCH_IS_X86 + +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE void set_errno_if_required(int err) { +LIBC_INLINE static void set_errno_if_required([[maybe_unused]] int err) { +#ifndef LIBC_MATH_HAS_NO_ERRNO if (math_errhandling & MATH_ERRNO) libc_errno = err; +#endif // LIBC_MATH_HAS_NO_ERRNO } } // namespace fputil diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h index 6c3e1520e5af..4c77d3c541cd 100644 --- a/libc/src/__support/FPUtil/dyadic_float.h +++ b/libc/src/__support/FPUtil/dyadic_float.h @@ -465,7 +465,10 @@ template struct DyadicFloat { // exponents coming in to this function _shouldn't_ be that large). The // result should always end up as a positive size_t. size_t shift = -static_cast(exponent); - new_mant >>= shift; + if (shift >= Bits) + new_mant = 0; + else + new_mant >>= shift; round_dir = rounding_direction(mantissa, shift, sign); if (round_dir > 0) ++new_mant; diff --git a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h index b77178ea69ea..560727c22978 100644 --- a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h +++ b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h @@ -239,7 +239,7 @@ LIBC_INLINE int set_except(int excepts) { return 0; } -LIBC_INLINE int raise_except(int excepts) { +template LIBC_INLINE int raise_except(int excepts) { uint16_t status_value = internal::get_status_value_for_except(excepts); // We set the status flag for exception one at a time and call the @@ -256,13 +256,16 @@ LIBC_INLINE int raise_except(int excepts) { // when raising the next exception. auto raise_helper = [](uint16_t singleExceptFlag) { - internal::X87StateDescriptor state; + if constexpr (!SKIP_X87_FPU) { + internal::X87StateDescriptor state; + internal::get_x87_state_descriptor(state); + state.status_word |= singleExceptFlag; + internal::write_x87_state_descriptor(state); + } + uint32_t mxcsr = 0; - internal::get_x87_state_descriptor(state); mxcsr = internal::get_mxcsr(); - state.status_word |= singleExceptFlag; mxcsr |= singleExceptFlag; - internal::write_x87_state_descriptor(state); internal::write_mxcsr(mxcsr); internal::fwait(); }; diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp index 21b0106f7010..aea8862c15f7 100644 --- a/libc/src/__support/File/dir.cpp +++ b/libc/src/__support/File/dir.cpp @@ -11,8 +11,8 @@ #include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/CPP/new.h" #include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" // For error macros #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" // For error macros namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp index 528542cccf32..303852dbbb71 100644 --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -13,8 +13,8 @@ #include "hdr/types/off_t.h" #include "src/__support/CPP/new.h" #include "src/__support/CPP/span.h" +#include "src/__support/libc_errno.h" // For error macros #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" // For error macros namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp index 824c1f200e8c..4594dadf1ccd 100644 --- a/libc/src/__support/File/linux/file.cpp +++ b/libc/src/__support/File/linux/file.cpp @@ -15,12 +15,12 @@ #include "src/__support/File/linux/lseekImpl.h" #include "src/__support/OSUtil/fcntl.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" // For error macros #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" // For error macros #include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall -#include // For S_IS*, S_IF*, and S_IR* flags. -#include // For syscall numbers +#include // For S_IS*, S_IF*, and S_IR* flags. +#include // For syscall numbers namespace LIBC_NAMESPACE_DECL { @@ -128,10 +128,11 @@ ErrorOr create_file_from_fd(int fd, const char *mode) { return Error(EINVAL); } - int fd_flags = internal::fcntl(fd, F_GETFL); - if (fd_flags == -1) { + auto result = internal::fcntl(fd, F_GETFL); + if (!result.has_value()) { return Error(EBADF); } + int fd_flags = result.value(); using OpenMode = File::OpenMode; if (((fd_flags & O_ACCMODE) == O_RDONLY && @@ -145,8 +146,9 @@ ErrorOr create_file_from_fd(int fd, const char *mode) { if ((modeflags & static_cast(OpenMode::APPEND)) && !(fd_flags & O_APPEND)) { do_seek = true; - if (internal::fcntl(fd, F_SETFL, - reinterpret_cast(fd_flags | O_APPEND)) == -1) { + if (!internal::fcntl(fd, F_SETFL, + reinterpret_cast(fd_flags | O_APPEND)) + .has_value()) { return Error(EBADF); } } diff --git a/libc/src/__support/File/linux/lseekImpl.h b/libc/src/__support/File/linux/lseekImpl.h index a034913d9f6e..300e5c5dd55b 100644 --- a/libc/src/__support/File/linux/lseekImpl.h +++ b/libc/src/__support/File/linux/lseekImpl.h @@ -13,8 +13,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" #include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For uint64_t. #include // For syscall numbers. diff --git a/libc/src/__support/GPU/allocator.cpp b/libc/src/__support/GPU/allocator.cpp index 135ced3df704..66ab155e5c29 100644 --- a/libc/src/__support/GPU/allocator.cpp +++ b/libc/src/__support/GPU/allocator.cpp @@ -129,6 +129,14 @@ static inline constexpr T round_up(const T x) { return (x + N) & ~(N - 1); } +// Perform a lane parallel memset on a uint32_t pointer. +void uniform_memset(uint32_t *s, uint32_t c, uint32_t n, uint64_t uniform) { + uint64_t mask = gpu::get_lane_mask(); + uint32_t workers = cpp::popcount(uniform); + for (uint32_t i = impl::lane_count(mask & uniform); i < n; i += workers) + s[i] = c; +} + } // namespace impl /// A slab allocator used to hand out identically sized slabs of memory. @@ -157,10 +165,15 @@ struct Slab { Header *header = reinterpret_cast
(memory); header->chunk_size = chunk_size; header->global_index = global_index; + } - // This memset is expensive and likely not necessary for the current 'kfd' - // driver. Until zeroed pages are exposed by the API we must be careful. - __builtin_memset(get_bitfield(), 0, bitfield_bytes(chunk_size)); + // Set the necessary bitfield bytes to zero in parallel using many lanes. This + // must be called before the bitfield can be accessed safely, memory is not + // guaranteed to be zero initialized in the current implementation. + void initialize(uint64_t uniform) { + uint32_t size = (bitfield_bytes(get_chunk_size()) + sizeof(uint32_t) - 1) / + sizeof(uint32_t); + impl::uniform_memset(get_bitfield(), 0, size, uniform); } // Get the number of chunks that can theoretically fit inside this slab. @@ -283,7 +296,7 @@ struct Slab { /// A wait-free guard around a pointer resource to be created dynamically if /// space is available and freed once there are no more users. -template struct GuardPtr { +struct GuardPtr { private: struct RefCounter { // Indicates that the object is in its deallocation phase and thus invalid. @@ -339,32 +352,25 @@ private: cpp::Atomic counter{0}; }; - cpp::Atomic ptr{nullptr}; + cpp::Atomic ptr{nullptr}; RefCounter ref{}; // Should be called be a single lane for each different pointer. template - T *try_lock_impl(uint32_t n, uint64_t &count, Args &&...args) { - T *expected = ptr.load(cpp::MemoryOrder::RELAXED); + Slab *try_lock_impl(uint32_t n, uint64_t &count, Args &&...args) { + Slab *expected = ptr.load(cpp::MemoryOrder::RELAXED); if (!expected && - ptr.compare_exchange_strong(expected, reinterpret_cast(SENTINEL), - cpp::MemoryOrder::RELAXED, - cpp::MemoryOrder::RELAXED)) { + ptr.compare_exchange_strong( + expected, reinterpret_cast(SENTINEL), + cpp::MemoryOrder::RELAXED, cpp::MemoryOrder::RELAXED)) { count = cpp::numeric_limits::max(); - void *raw = impl::rpc_allocate(sizeof(T)); + void *raw = impl::rpc_allocate(sizeof(Slab)); if (!raw) return nullptr; - T *mem = new (raw) T(cpp::forward(args)...); - - cpp::atomic_thread_fence(cpp::MemoryOrder::RELEASE); - ptr.store(mem, cpp::MemoryOrder::RELAXED); - cpp::atomic_thread_fence(cpp::MemoryOrder::ACQUIRE); - if (!ref.acquire(n, count)) - ref.reset(n, count); - return mem; + return new (raw) Slab(cpp::forward(args)...); } - if (!expected || expected == reinterpret_cast(SENTINEL)) + if (!expected || expected == reinterpret_cast(SENTINEL)) return nullptr; if (!ref.acquire(n, count)) @@ -374,15 +380,25 @@ private: return ptr.load(cpp::MemoryOrder::RELAXED); } + // Finalize the associated memory and signal that it is ready to use by + // resetting the counter. + void finalize(Slab *mem, uint32_t n, uint64_t &count) { + cpp::atomic_thread_fence(cpp::MemoryOrder::RELEASE); + ptr.store(mem, cpp::MemoryOrder::RELAXED); + cpp::atomic_thread_fence(cpp::MemoryOrder::ACQUIRE); + if (!ref.acquire(n, count)) + ref.reset(n, count); + } + public: // Attempt to lock access to the pointer, potentially creating it if empty. // The uniform mask represents which lanes share the same pointer. For each // uniform value we elect a leader to handle it on behalf of the other lanes. template - T *try_lock(uint64_t lane_mask, uint64_t uniform, uint64_t &count, - Args &&...args) { + Slab *try_lock(uint64_t lane_mask, uint64_t uniform, uint64_t &count, + Args &&...args) { count = 0; - T *result = nullptr; + Slab *result = nullptr; if (gpu::get_lane_id() == uint32_t(cpp::countr_zero(uniform))) result = try_lock_impl(cpp::popcount(uniform), count, cpp::forward(args)...); @@ -392,6 +408,14 @@ public: if (!result) return nullptr; + // We defer storing the newly allocated slab until now so that we can use + // multiple lanes to initialize it and release it for use. + if (count == cpp::numeric_limits::max()) { + result->initialize(uniform); + if (gpu::get_lane_id() == uint32_t(cpp::countr_zero(uniform))) + finalize(result, cpp::popcount(uniform), count); + } + if (count != cpp::numeric_limits::max()) count = count - cpp::popcount(uniform) + impl::lane_count(uniform) + 1; @@ -403,8 +427,8 @@ public: cpp::atomic_thread_fence(cpp::MemoryOrder::RELEASE); if (gpu::get_lane_id() == uint32_t(cpp::countr_zero(mask)) && ref.release(cpp::popcount(mask))) { - T *p = ptr.load(cpp::MemoryOrder::RELAXED); - p->~T(); + Slab *p = ptr.load(cpp::MemoryOrder::RELAXED); + p->~Slab(); impl::rpc_free(p); cpp::atomic_thread_fence(cpp::MemoryOrder::RELEASE); ptr.store(nullptr, cpp::MemoryOrder::RELAXED); @@ -417,7 +441,7 @@ public: }; // The global array used to search for a valid slab to allocate from. -static GuardPtr slots[ARRAY_SIZE] = {}; +static GuardPtr slots[ARRAY_SIZE] = {}; // Tries to find a slab in the table that can support the given chunk size. static Slab *find_slab(uint32_t chunk_size) { diff --git a/libc/src/__support/HashTable/CMakeLists.txt b/libc/src/__support/HashTable/CMakeLists.txt index 3c487e4f2926..698b8d0dfa68 100644 --- a/libc/src/__support/HashTable/CMakeLists.txt +++ b/libc/src/__support/HashTable/CMakeLists.txt @@ -15,7 +15,8 @@ if (NOT ${getrandom_index} EQUAL -1) message(STATUS "Using getrandom for hashtable randomness") set(randomness_compile_flags -DLIBC_HASHTABLE_USE_GETRANDOM) set(randomness_extra_depends - libc.src.sys.random.getrandom libc.src.errno.errno) + libc.src.__support.OSUtil.linux.getrandom + libc.hdr.errno_macros) endif() @@ -32,9 +33,8 @@ add_header_library( libc.src.__support.macros.attributes libc.src.__support.macros.optimization libc.src.__support.memory_size - libc.src.string.memset - libc.src.string.strcmp - libc.src.string.strlen + libc.src.string.memory_utils.inline_strcmp + libc.src.string.string_utils ) add_header_library( diff --git a/libc/src/__support/HashTable/randomness.h b/libc/src/__support/HashTable/randomness.h index 244dd41be3ee..7e54c9aa6ad1 100644 --- a/libc/src/__support/HashTable/randomness.h +++ b/libc/src/__support/HashTable/randomness.h @@ -14,8 +14,8 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #if defined(LIBC_HASHTABLE_USE_GETRANDOM) -#include "src/errno/libc_errno.h" -#include "src/sys/random/getrandom.h" +#include "hdr/errno_macros.h" +#include "src/__support/OSUtil/linux/getrandom.h" #endif namespace LIBC_NAMESPACE_DECL { @@ -35,20 +35,18 @@ LIBC_INLINE uint64_t next_random_seed() { entropy[0] = reinterpret_cast(&entropy); entropy[1] = reinterpret_cast(&state); #if defined(LIBC_HASHTABLE_USE_GETRANDOM) - int errno_backup = libc_errno; size_t count = sizeof(entropy); uint8_t *buffer = reinterpret_cast(entropy); while (count > 0) { - ssize_t len = getrandom(buffer, count, 0); - if (len == -1) { - if (libc_errno == ENOSYS) + auto len = internal::getrandom(buffer, count, 0); + if (!len.has_value()) { + if (len.error() == ENOSYS) break; continue; } - count -= len; - buffer += len; + count -= len.value(); + buffer += len.value(); } - libc_errno = errno_backup; #endif state.update(&entropy, sizeof(entropy)); } diff --git a/libc/src/__support/HashTable/table.h b/libc/src/__support/HashTable/table.h index 13badb90dbfd..10dd9711afbf 100644 --- a/libc/src/__support/HashTable/table.h +++ b/libc/src/__support/HashTable/table.h @@ -18,9 +18,8 @@ #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/memory_size.h" -#include "src/string/memset.h" -#include "src/string/strcmp.h" -#include "src/string/strlen.h" +#include "src/string/memory_utils/inline_strcmp.h" +#include "src/string/string_utils.h" #include #include @@ -158,7 +157,9 @@ private: for (size_t i : masks) { size_t index = (pos + i) & entries_mask; ENTRY &entry = this->entry(index); - if (LIBC_LIKELY(entry.key != nullptr && strcmp(entry.key, key) == 0)) + auto comp = [](char l, char r) -> int { return l - r; }; + if (LIBC_LIKELY(entry.key != nullptr && + inline_strcmp(entry.key, key, comp) == 0)) return index; } BitMask available = ctrls.mask_available(); @@ -176,7 +177,7 @@ private: LIBC_INLINE uint64_t oneshot_hash(const char *key) const { LIBC_NAMESPACE::internal::HashState hasher = state; - hasher.update(key, strlen(key)); + hasher.update(key, internal::string_length(key)); return hasher.finish(); } @@ -282,8 +283,8 @@ public: table->entries_mask = entries - 1u; table->available_slots = entries / 8 * 7; table->state = HashState{randomness}; - memset(&table->control(0), 0x80, ctrl_sizes); - memset(mem, 0, table->offset_from_entries()); + __builtin_memset(&table->control(0), 0x80, ctrl_sizes); + __builtin_memset(mem, 0, table->offset_from_entries()); } return table; } diff --git a/libc/src/__support/OSUtil/fcntl.h b/libc/src/__support/OSUtil/fcntl.h index 46f7d2813239..3983d78f7f89 100644 --- a/libc/src/__support/OSUtil/fcntl.h +++ b/libc/src/__support/OSUtil/fcntl.h @@ -8,12 +8,18 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H +#include "hdr/types/mode_t.h" +#include "src/__support/error_or.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace internal { -int fcntl(int fd, int cmd, void *arg = nullptr); +ErrorOr fcntl(int fd, int cmd, void *arg = nullptr); + +ErrorOr open(const char *path, int flags, mode_t mode_flags = 0); + +ErrorOr close(int fd); } // namespace internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt index b9704d42cd33..f303e54ce7b3 100644 --- a/libc/src/__support/OSUtil/linux/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt @@ -16,7 +16,6 @@ add_object_library( .${LIBC_TARGET_ARCHITECTURE}.linux_${LIBC_TARGET_ARCHITECTURE}_util libc.src.__support.common libc.src.__support.CPP.string_view - libc.src.errno.errno libc.hdr.fcntl_macros libc.hdr.types.struct_flock libc.hdr.types.struct_flock64 @@ -25,6 +24,19 @@ add_object_library( libc.include.sys_syscall ) +add_header_library( + getrandom + HDRS + getrandom.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.hdr.types.ssize_t + libc.include.sys_syscall +) + add_header_library( vdso_sym HDRS diff --git a/libc/src/__support/OSUtil/linux/fcntl.cpp b/libc/src/__support/OSUtil/linux/fcntl.cpp index 4742b2a00220..bb76eee90efd 100644 --- a/libc/src/__support/OSUtil/linux/fcntl.cpp +++ b/libc/src/__support/OSUtil/linux/fcntl.cpp @@ -8,23 +8,24 @@ #include "src/__support/OSUtil/fcntl.h" +#include "hdr/errno_macros.h" #include "hdr/fcntl_macros.h" +#include "hdr/types/mode_t.h" #include "hdr/types/off_t.h" #include "hdr/types/struct_f_owner_ex.h" #include "hdr/types/struct_flock.h" #include "hdr/types/struct_flock64.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/error_or.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { namespace internal { -int fcntl(int fd, int cmd, void *arg) { +ErrorOr fcntl(int fd, int cmd, void *arg) { #if SYS_fcntl constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl; #elif defined(SYS_fcntl64) @@ -33,8 +34,7 @@ int fcntl(int fd, int cmd, void *arg) { #error "fcntl and fcntl64 syscalls not available." #endif - int new_cmd = cmd; - switch (new_cmd) { + switch (cmd) { case F_OFD_SETLKW: { struct flock *flk = reinterpret_cast(arg); // convert the struct to a flock64 @@ -45,8 +45,11 @@ int fcntl(int fd, int cmd, void *arg) { flk64.l_len = flk->l_len; flk64.l_pid = flk->l_pid; // create a syscall - return LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, new_cmd, - &flk64); + int ret = + LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, cmd, &flk64); + if (ret < 0) + return Error(-ret); + return ret; } case F_OFD_GETLK: case F_OFD_SETLK: { @@ -59,60 +62,80 @@ int fcntl(int fd, int cmd, void *arg) { flk64.l_len = flk->l_len; flk64.l_pid = flk->l_pid; // create a syscall - int retVal = LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, - new_cmd, &flk64); + int ret = + LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, cmd, &flk64); // On failure, return - if (retVal == -1) - return -1; + if (ret < 0) + return Error(-1); // Check for overflow, i.e. the offsets are not the same when cast // to off_t from off64_t. if (static_cast(flk64.l_len) != flk64.l_len || - static_cast(flk64.l_start) != flk64.l_start) { - libc_errno = EOVERFLOW; - return -1; - } + static_cast(flk64.l_start) != flk64.l_start) + return Error(EOVERFLOW); + // Now copy back into flk, in case flk64 got modified flk->l_type = flk64.l_type; flk->l_whence = flk64.l_whence; flk->l_start = static_castl_start)>(flk64.l_start); flk->l_len = static_castl_len)>(flk64.l_len); flk->l_pid = flk64.l_pid; - return retVal; + return ret; } case F_GETOWN: { struct f_owner_ex fex; int ret = LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, F_GETOWN_EX, &fex); - if (ret >= 0) - return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; - libc_errno = -ret; - return -1; + if (ret < 0) + return Error(-ret); + return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; } #ifdef SYS_fcntl64 case F_GETLK: { if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) - new_cmd = F_GETLK64; + cmd = F_GETLK64; break; } case F_SETLK: { if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) - new_cmd = F_SETLK64; + cmd = F_SETLK64; break; } case F_SETLKW: { if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) - new_cmd = F_SETLKW64; + cmd = F_SETLKW64; break; } #endif } - int retVal = LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, new_cmd, - reinterpret_cast(arg)); - if (retVal >= 0) { - return retVal; - } - libc_errno = -retVal; - return -1; + + // default, but may use rewritten cmd from above. + int ret = LIBC_NAMESPACE::syscall_impl(FCNTL_SYSCALL_ID, fd, cmd, + reinterpret_cast(arg)); + if (ret < 0) + return Error(-ret); + return ret; +} + +ErrorOr open(const char *path, int flags, mode_t mode_flags) { +#ifdef SYS_open + int fd = LIBC_NAMESPACE::syscall_impl(SYS_open, path, flags, mode_flags); +#else + int fd = LIBC_NAMESPACE::syscall_impl(SYS_openat, AT_FDCWD, path, flags, + mode_flags); +#endif + if (fd < 0) + return Error(-fd); + + return fd; +} + +ErrorOr close(int fd) { + int ret = LIBC_NAMESPACE::syscall_impl(SYS_close, fd); + + if (ret < 0) + return Error(-ret); + + return ret; } } // namespace internal diff --git a/libc/src/__support/OSUtil/linux/getrandom.h b/libc/src/__support/OSUtil/linux/getrandom.h new file mode 100644 index 000000000000..793639472fee --- /dev/null +++ b/libc/src/__support/OSUtil/linux/getrandom.h @@ -0,0 +1,35 @@ +//===------------ Implementation of getrandom function ----------*- 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_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H + +#include "hdr/types/ssize_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +LIBC_INLINE static ErrorOr getrandom(void *buf, size_t buflen, + unsigned int flags) { + ssize_t ret = + LIBC_NAMESPACE::syscall_impl(SYS_getrandom, buf, buflen, flags); + if (ret < 0) { + return Error(-static_cast(ret)); + } + return ret; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H diff --git a/libc/src/__support/OSUtil/linux/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp index 8c9bd3e1bcc7..e4e53c3c2a0f 100644 --- a/libc/src/__support/OSUtil/linux/vdso.cpp +++ b/libc/src/__support/OSUtil/linux/vdso.cpp @@ -11,9 +11,9 @@ #include "src/__support/CPP/array.h" #include "src/__support/CPP/optional.h" #include "src/__support/CPP/string_view.h" +#include "src/__support/libc_errno.h" #include "src/__support/threads/callonce.h" #include "src/__support/threads/linux/futex_word.h" -#include "src/errno/libc_errno.h" #include "src/sys/auxv/getauxval.h" #include diff --git a/libc/src/__support/StringUtil/tables/linux_extension_errors.h b/libc/src/__support/StringUtil/tables/linux_extension_errors.h index 425590f6e91c..de637d60bea9 100644 --- a/libc/src/__support/StringUtil/tables/linux_extension_errors.h +++ b/libc/src/__support/StringUtil/tables/linux_extension_errors.h @@ -10,8 +10,8 @@ #define LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_LINUX_EXTENSION_ERRORS_H #include "src/__support/StringUtil/message_mapper.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/libc_errno.h b/libc/src/__support/libc_errno.h new file mode 100644 index 000000000000..ab5f6a9c4b9d --- /dev/null +++ b/libc/src/__support/libc_errno.h @@ -0,0 +1,108 @@ +//===-- Implementation header for libc_errno --------------------*- 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_LIBC_SRC___SUPPORT_LIBC_ERRNO_H +#define LLVM_LIBC_SRC___SUPPORT_LIBC_ERRNO_H + +// This header is to be consumed by internal implementations, in which all of +// them should refer to `libc_errno` instead of using `errno` directly from +// header. + +// Unit and hermetic tests should: +// - #include "src/__support/libc_errno.h" +// - NOT #include +// - Only use `libc_errno` in the code +// - Depend on libc.src.errno.errno + +// Integration tests should: +// - NOT #include "src/__support/libc_errno.h" +// - #include +// - Use regular `errno` in the code +// - Still depend on libc.src.errno.errno + +// libc uses a fallback default value, either system or thread local. +#define LIBC_ERRNO_MODE_DEFAULT 0 +// libc never stores a value; `errno` macro uses get link-time failure. +#define LIBC_ERRNO_MODE_UNDEFINED 1 +// libc maintains per-thread state (requires C++ `thread_local` support). +#define LIBC_ERRNO_MODE_THREAD_LOCAL 2 +// libc maintains shared state used by all threads, contrary to standard C +// semantics unless always single-threaded; nothing prevents data races. +#define LIBC_ERRNO_MODE_SHARED 3 +// libc doesn't maintain any internal state, instead the embedder must define +// `int *__llvm_libc_errno(void);` C function. +#define LIBC_ERRNO_MODE_EXTERNAL 4 +// libc uses system `` `errno` macro directly in the overlay mode; in +// fullbuild mode, effectively the same as `LIBC_ERRNO_MODE_EXTERNAL`. +// In this mode, the public C++ symbol `LIBC_NAMESPACE::libc_errno ` is still +// exported and get redirected to the system `errno` inside its implementation. + +// TODO: Investigate deprecating LIBC_ERRNO_MODE_SYSTEM in favor of +// LIBC_ERRNO_MODE_SYSTEM_INLINE. +// https://github.com/llvm/llvm-project/issues/143454 +#define LIBC_ERRNO_MODE_SYSTEM 5 +// In this mode, the libc_errno is simply a macro resolved to `errno` from the +// system header . There is no need to link against the +// `libc.src.errno.errno` object. +#define LIBC_ERRNO_MODE_SYSTEM_INLINE 6 + +#if !defined(LIBC_ERRNO_MODE) || LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_DEFAULT +#undef LIBC_ERRNO_MODE +#if defined(LIBC_FULL_BUILD) || !defined(LIBC_COPT_PUBLIC_PACKAGING) +#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_THREAD_LOCAL +#else +#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM +#endif +#endif // LIBC_ERRNO_MODE + +#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_DEFAULT && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_UNDEFINED && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_THREAD_LOCAL && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SHARED && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_EXTERNAL && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM && \ + LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE +#error LIBC_ERRNO_MODE must be one of the following values: \ +LIBC_ERRNO_MODE_DEFAULT, \ +LIBC_ERRNO_MODE_UNDEFINED, \ +LIBC_ERRNO_MODE_THREAD_LOCAL, \ +LIBC_ERRNO_MODE_SHARED, \ +LIBC_ERRNO_MODE_EXTERNAL, \ +LIBC_ERRNO_MODE_SYSTEM, \ +LIBC_ERRNO_MODE_SYSTEM_INLINE. +#endif + +#if LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SYSTEM_INLINE + +#include + +#define libc_errno errno + +#else // !LIBC_ERRNO_MODE_SYSTEM_INLINE + +#include "hdr/errno_macros.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +extern "C" int *__llvm_libc_errno() noexcept; + +struct Errno { + void operator=(int); + operator int(); +}; + +extern Errno libc_errno; + +} // namespace LIBC_NAMESPACE_DECL + +using LIBC_NAMESPACE::libc_errno; + +#endif // LIBC_ERRNO_MODE_SYSTEM_INLINE + +#endif // LLVM_LIBC_SRC___SUPPORT_LIBC_ERRNO_H diff --git a/libc/src/__support/macros/optimization.h b/libc/src/__support/macros/optimization.h index 253843e5e37a..db008d323b3a 100644 --- a/libc/src/__support/macros/optimization.h +++ b/libc/src/__support/macros/optimization.h @@ -63,4 +63,12 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #define LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT #endif +#if (LIBC_MATH & LIBC_MATH_NO_ERRNO) +#define LIBC_MATH_HAS_NO_ERRNO +#endif + +#if (LIBC_MATH & LIBC_MATH_NO_EXCEPT) +#define LIBC_MATH_HAS_NO_EXCEPT +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H diff --git a/libc/src/__support/macros/properties/cpu_features.h b/libc/src/__support/macros/properties/cpu_features.h index 3677e1fc3275..457a2b7869d4 100644 --- a/libc/src/__support/macros/properties/cpu_features.h +++ b/libc/src/__support/macros/properties/cpu_features.h @@ -61,15 +61,15 @@ #if defined(__riscv_flen) // https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc -#if (__riscv_flen & 0x10) +#if (__riscv_arch_test && __riscv_zfhmin) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_HALF #define LIBC_TARGET_CPU_HAS_FPU_HALF #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_HALF -#if (__riscv_flen & 0x20) +#if (__riscv_flen >= 32) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_FLOAT #define LIBC_TARGET_CPU_HAS_FPU_FLOAT #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_FLOAT -#if (__riscv_flen & 0x40) +#if (__riscv_flen >= 64) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt new file mode 100644 index 000000000000..66c1d19a1cab --- /dev/null +++ b/libc/src/__support/math/CMakeLists.txt @@ -0,0 +1,24 @@ +add_header_library( + exp_float_constants + HDRS + exp_float_constants.h + DEPENDS + libc.src.__support.macros.config +) + +add_header_library( + expf + HDRS + expf.h + DEPENDS + .exp_float_constants + libc.src.__support.common + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) diff --git a/libc/src/__support/math/exp_float_constants.h b/libc/src/__support/math/exp_float_constants.h new file mode 100644 index 000000000000..cabb227a034b --- /dev/null +++ b/libc/src/__support/math/exp_float_constants.h @@ -0,0 +1,145 @@ +//===-- Look-up tables for exp*f functions ----------------------*- 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_LIBC_SRC___SUPPORT_MATH_EXP_FLOAT_CONSTANTS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP_FLOAT_CONSTANTS_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +// Lookup table for exp(m) with m = -104, ..., 89. +// -104 = floor(log(single precision's min denormal)) +// 89 = ceil(log(single precision's max normal)) +// Table is generated with Sollya as follow: +// > display = hexadecimal; +// > for i from -104 to 89 do { D(exp(i)); }; +static constexpr double EXP_M1[195] = { + 0x1.f1e6b68529e33p-151, 0x1.525be4e4e601dp-149, 0x1.cbe0a45f75eb1p-148, + 0x1.3884e838aea68p-146, 0x1.a8c1f14e2af5dp-145, 0x1.20a717e64a9bdp-143, + 0x1.8851d84118908p-142, 0x1.0a9bdfb02d240p-140, 0x1.6a5bea046b42ep-139, + 0x1.ec7f3b269efa8p-138, 0x1.4eafb87eab0f2p-136, 0x1.c6e2d05bbc000p-135, + 0x1.35208867c2683p-133, 0x1.a425b317eeacdp-132, 0x1.1d8508fa8246ap-130, + 0x1.840fbc08fdc8ap-129, 0x1.07b7112bc1ffep-127, 0x1.666d0dad2961dp-126, + 0x1.e726c3f64d0fep-125, 0x1.4b0dc07cabf98p-123, 0x1.c1f2daf3b6a46p-122, + 0x1.31c5957a47de2p-120, 0x1.9f96445648b9fp-119, 0x1.1a6baeadb4fd1p-117, + 0x1.7fd974d372e45p-116, 0x1.04da4d1452919p-114, 0x1.62891f06b3450p-113, + 0x1.e1dd273aa8a4ap-112, 0x1.4775e0840bfddp-110, 0x1.bd109d9d94bdap-109, + 0x1.2e73f53fba844p-107, 0x1.9b138170d6bfep-106, 0x1.175af0cf60ec5p-104, + 0x1.7baee1bffa80bp-103, 0x1.02057d1245cebp-101, 0x1.5eafffb34ba31p-100, + 0x1.dca23bae16424p-99, 0x1.43e7fc88b8056p-97, 0x1.b83bf23a9a9ebp-96, + 0x1.2b2b8dd05b318p-94, 0x1.969d47321e4ccp-93, 0x1.1452b7723aed2p-91, + 0x1.778fe2497184cp-90, 0x1.fe7116182e9ccp-89, 0x1.5ae191a99585ap-87, + 0x1.d775d87da854dp-86, 0x1.4063f8cc8bb98p-84, 0x1.b374b315f87c1p-83, + 0x1.27ec458c65e3cp-81, 0x1.923372c67a074p-80, 0x1.1152eaeb73c08p-78, + 0x1.737c5645114b5p-77, 0x1.f8e6c24b5592ep-76, 0x1.571db733a9d61p-74, + 0x1.d257d547e083fp-73, 0x1.3ce9b9de78f85p-71, 0x1.aebabae3a41b5p-70, + 0x1.24b6031b49bdap-68, 0x1.8dd5e1bb09d7ep-67, 0x1.0e5b73d1ff53dp-65, + 0x1.6f741de1748ecp-64, 0x1.f36bd37f42f3ep-63, 0x1.536452ee2f75cp-61, + 0x1.cd480a1b74820p-60, 0x1.39792499b1a24p-58, 0x1.aa0de4bf35b38p-57, + 0x1.2188ad6ae3303p-55, 0x1.898471fca6055p-54, 0x1.0b6c3afdde064p-52, + 0x1.6b7719a59f0e0p-51, 0x1.ee001eed62aa0p-50, 0x1.4fb547c775da8p-48, + 0x1.c8464f7616468p-47, 0x1.36121e24d3bbap-45, 0x1.a56e0c2ac7f75p-44, + 0x1.1e642baeb84a0p-42, 0x1.853f01d6d53bap-41, 0x1.0885298767e9ap-39, + 0x1.67852a7007e42p-38, 0x1.e8a37a45fc32ep-37, 0x1.4c1078fe9228ap-35, + 0x1.c3527e433fab1p-34, 0x1.32b48bf117da2p-32, 0x1.a0db0d0ddb3ecp-31, + 0x1.1b48655f37267p-29, 0x1.81056ff2c5772p-28, 0x1.05a628c699fa1p-26, + 0x1.639e3175a689dp-25, 0x1.e355bbaee85cbp-24, 0x1.4875ca227ec38p-22, + 0x1.be6c6fdb01612p-21, 0x1.2f6053b981d98p-19, 0x1.9c54c3b43bc8bp-18, + 0x1.18354238f6764p-16, 0x1.7cd79b5647c9bp-15, 0x1.02cf22526545ap-13, + 0x1.5fc21041027adp-12, 0x1.de16b9c24a98fp-11, 0x1.44e51f113d4d6p-9, + 0x1.b993fe00d5376p-8, 0x1.2c155b8213cf4p-6, 0x1.97db0ccceb0afp-5, + 0x1.152aaa3bf81ccp-3, 0x1.78b56362cef38p-2, 0x1.0000000000000p+0, + 0x1.5bf0a8b145769p+1, 0x1.d8e64b8d4ddaep+2, 0x1.415e5bf6fb106p+4, + 0x1.b4c902e273a58p+5, 0x1.28d389970338fp+7, 0x1.936dc5690c08fp+8, + 0x1.122885aaeddaap+10, 0x1.749ea7d470c6ep+11, 0x1.fa7157c470f82p+12, + 0x1.5829dcf950560p+14, 0x1.d3c4488ee4f7fp+15, 0x1.3de1654d37c9ap+17, + 0x1.b00b5916ac955p+18, 0x1.259ac48bf05d7p+20, 0x1.8f0ccafad2a87p+21, + 0x1.0f2ebd0a80020p+23, 0x1.709348c0ea4f9p+24, 0x1.f4f22091940bdp+25, + 0x1.546d8f9ed26e1p+27, 0x1.ceb088b68e804p+28, 0x1.3a6e1fd9eecfdp+30, + 0x1.ab5adb9c43600p+31, 0x1.226af33b1fdc1p+33, 0x1.8ab7fb5475fb7p+34, + 0x1.0c3d3920962c9p+36, 0x1.6c932696a6b5dp+37, 0x1.ef822f7f6731dp+38, + 0x1.50bba3796379ap+40, 0x1.c9aae4631c056p+41, 0x1.370470aec28edp+43, + 0x1.a6b765d8cdf6dp+44, 0x1.1f43fcc4b662cp+46, 0x1.866f34a725782p+47, + 0x1.0953e2f3a1ef7p+49, 0x1.689e221bc8d5bp+50, 0x1.ea215a1d20d76p+51, + 0x1.4d13fbb1a001ap+53, 0x1.c4b334617cc67p+54, 0x1.33a43d282a519p+56, + 0x1.a220d397972ebp+57, 0x1.1c25c88df6862p+59, 0x1.8232558201159p+60, + 0x1.0672a3c9eb871p+62, 0x1.64b41c6d37832p+63, 0x1.e4cf766fe49bep+64, + 0x1.49767bc0483e3p+66, 0x1.bfc951eb8bb76p+67, 0x1.304d6aeca254bp+69, + 0x1.9d97010884251p+70, 0x1.19103e4080b45p+72, 0x1.7e013cd114461p+73, + 0x1.03996528e074cp+75, 0x1.60d4f6fdac731p+76, 0x1.df8c5af17ba3bp+77, + 0x1.45e3076d61699p+79, 0x1.baed16a6e0da7p+80, 0x1.2cffdfebde1a1p+82, + 0x1.9919cabefcb69p+83, 0x1.160345c9953e3p+85, 0x1.79dbc9dc53c66p+86, + 0x1.00c810d464097p+88, 0x1.5d009394c5c27p+89, 0x1.da57de8f107a8p+90, + 0x1.425982cf597cdp+92, 0x1.b61e5ca3a5e31p+93, 0x1.29bb825dfcf87p+95, + 0x1.94a90db0d6fe2p+96, 0x1.12fec759586fdp+98, 0x1.75c1dc469e3afp+99, + 0x1.fbfd219c43b04p+100, 0x1.5936d44e1a146p+102, 0x1.d531d8a7ee79cp+103, + 0x1.3ed9d24a2d51bp+105, 0x1.b15cfe5b6e17bp+106, 0x1.268038c2c0e00p+108, + 0x1.9044a73545d48p+109, 0x1.1002ab6218b38p+111, 0x1.71b3540cbf921p+112, + 0x1.f6799ea9c414ap+113, 0x1.55779b984f3ebp+115, 0x1.d01a210c44aa4p+116, + 0x1.3b63da8e91210p+118, 0x1.aca8d6b0116b8p+119, 0x1.234de9e0c74e9p+121, + 0x1.8bec7503ca477p+122, 0x1.0d0eda9796b90p+124, 0x1.6db0118477245p+125, + 0x1.f1056dc7bf22dp+126, 0x1.51c2cc3433801p+128, 0x1.cb108ffbec164p+129, +}; + +// Lookup table for exp(m * 2^(-7)) with m = 0, ..., 127. +// Table is generated with Sollya as follow: +// > display = hexadecimal; +// > for i from 0 to 127 do { D(exp(i / 128)); }; +static constexpr double EXP_M2[128] = { + 0x1.0000000000000p0, 0x1.0202015600446p0, 0x1.04080ab55de39p0, + 0x1.06122436410ddp0, 0x1.08205601127edp0, 0x1.0a32a84e9c1f6p0, + 0x1.0c49236829e8cp0, 0x1.0e63cfa7ab09dp0, 0x1.1082b577d34edp0, + 0x1.12a5dd543ccc5p0, 0x1.14cd4fc989cd6p0, 0x1.16f9157587069p0, + 0x1.192937074e0cdp0, 0x1.1b5dbd3f68122p0, 0x1.1d96b0eff0e79p0, + 0x1.1fd41afcba45ep0, 0x1.2216045b6f5cdp0, 0x1.245c7613b8a9bp0, + 0x1.26a7793f60164p0, 0x1.28f7170a755fdp0, 0x1.2b4b58b372c79p0, + 0x1.2da4478b620c7p0, 0x1.3001ecf601af7p0, 0x1.32645269ea829p0, + 0x1.34cb8170b5835p0, 0x1.373783a722012p0, 0x1.39a862bd3c106p0, + 0x1.3c1e2876834aap0, 0x1.3e98deaa11dccp0, 0x1.41188f42c3e32p0, + 0x1.439d443f5f159p0, 0x1.462707b2bac21p0, 0x1.48b5e3c3e8186p0, + 0x1.4b49e2ae5ac67p0, 0x1.4de30ec211e60p0, 0x1.50817263c13cdp0, + 0x1.5325180cfacf7p0, 0x1.55ce0a4c58c7cp0, 0x1.587c53c5a7af0p0, + 0x1.5b2fff3210fd9p0, 0x1.5de9176045ff5p0, 0x1.60a7a734ab0e8p0, + 0x1.636bb9a983258p0, 0x1.663559cf1bc7cp0, 0x1.690492cbf9433p0, + 0x1.6bd96fdd034a2p0, 0x1.6eb3fc55b1e76p0, 0x1.719443a03acb9p0, + 0x1.747a513dbef6ap0, 0x1.776630c678bc1p0, 0x1.7a57ede9ea23ep0, + 0x1.7d4f946f0ba8dp0, 0x1.804d30347b546p0, 0x1.8350cd30ac390p0, + 0x1.865a7772164c5p0, 0x1.896a3b1f66a0ep0, 0x1.8c802477b0010p0, + 0x1.8f9c3fd29beafp0, 0x1.92be99a09bf00p0, 0x1.95e73e6b1b75ep0, + 0x1.99163ad4b1dccp0, 0x1.9c4b9b995509bp0, 0x1.9f876d8e8c566p0, + 0x1.a2c9bda3a3e78p0, 0x1.a61298e1e069cp0, 0x1.a9620c6cb3374p0, + 0x1.acb82581eee54p0, 0x1.b014f179fc3b8p0, 0x1.b3787dc80f95fp0, + 0x1.b6e2d7fa5eb18p0, 0x1.ba540dba56e56p0, 0x1.bdcc2cccd3c85p0, + 0x1.c14b431256446p0, 0x1.c4d15e873c193p0, 0x1.c85e8d43f7cd0p0, + 0x1.cbf2dd7d490f2p0, 0x1.cf8e5d84758a9p0, 0x1.d3311bc7822b4p0, + 0x1.d6db26d16cd67p0, 0x1.da8c8d4a66969p0, 0x1.de455df80e3c0p0, + 0x1.e205a7bdab73ep0, 0x1.e5cd799c6a54ep0, 0x1.e99ce2b397649p0, + 0x1.ed73f240dc142p0, 0x1.f152b7a07bb76p0, 0x1.f539424d90f5ep0, + 0x1.f927a1e24bb76p0, 0x1.fd1de6182f8c9p0, 0x1.008e0f64294abp1, + 0x1.02912df5ce72ap1, 0x1.049856cd84339p1, 0x1.06a39207f0a09p1, + 0x1.08b2e7d2035cfp1, 0x1.0ac6606916501p1, 0x1.0cde041b0e9aep1, + 0x1.0ef9db467dcf8p1, 0x1.1119ee5ac36b6p1, 0x1.133e45d82e952p1, + 0x1.1566ea50201d7p1, 0x1.1793e4652cc50p1, 0x1.19c53ccb3fc6bp1, + 0x1.1bfafc47bda73p1, 0x1.1e352bb1a74adp1, 0x1.2073d3f1bd518p1, + 0x1.22b6fe02a3b9cp1, 0x1.24feb2f105cb8p1, 0x1.274afbdbba4a6p1, + 0x1.299be1f3e7f1cp1, 0x1.2bf16e7d2a38cp1, 0x1.2e4baacdb6614p1, + 0x1.30aaa04e80d05p1, 0x1.330e587b62b28p1, 0x1.3576dce33feadp1, + 0x1.37e437282d4eep1, 0x1.3a5670ff972edp1, 0x1.3ccd9432682b4p1, + 0x1.3f49aa9d30590p1, 0x1.41cabe304cb34p1, 0x1.4450d8f00edd4p1, + 0x1.46dc04f4e5338p1, 0x1.496c4c6b832dap1, 0x1.4c01b9950a111p1, + 0x1.4e9c56c731f5dp1, 0x1.513c2e6c731d7p1, 0x1.53e14b042f9cap1, + 0x1.568bb722dd593p1, 0x1.593b7d72305bbp1, +}; + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP_FLOAT_CONSTANTS_H diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h new file mode 100644 index 000000000000..88c151492a04 --- /dev/null +++ b/libc/src/__support/math/expf.h @@ -0,0 +1,116 @@ +//===-- Implementation header for expf --------------------------*- 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_LIBC_SRC___SUPPORT_MATH_EXPF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_H + +#include "exp_float_constants.h" // Lookup tables EXP_M1 and EXP_M2. +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float expf(float x) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Exceptional values + if (LIBC_UNLIKELY(x_u == 0xc236'bd8cU)) { // x = -0x1.6d7b18p+5f + return 0x1.108a58p-66f - x * 0x1.0p-95f; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // When |x| >= 89, |x| < 2^-25, or x is nan + if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) { + // |x| < 2^-25 + if (xbits.get_biased_exponent() <= 101) { + return 1.0f + x; + } + + // When x < log(2^-150) or nan + if (xbits.uintval() >= 0xc2cf'f1b5U) { + // exp(-Inf) = 0 + if (xbits.is_inf()) + return 0.0f; + // exp(nan) = nan + if (xbits.is_nan()) + return x; + if (fputil::fenv_is_round_up()) + return FPBits::min_subnormal().get_val(); + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_UNDERFLOW); + return 0.0f; + } + // x >= 89 or nan + if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) { + // x is finite + if (xbits.uintval() < 0x7f80'0000U) { + int rounding = fputil::quick_get_round(); + if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) + return FPBits::max_normal().get_val(); + + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW); + } + // x is +inf or nan + return x + FPBits::inf().get_val(); + } + } + // For -104 < x < 89, to compute exp(x), we perform the following range + // reduction: find hi, mid, lo such that: + // x = hi + mid + lo, in which + // hi is an integer, + // mid * 2^7 is an integer + // -2^(-8) <= lo < 2^-8. + // In particular, + // hi + mid = round(x * 2^7) * 2^(-7). + // Then, + // exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo). + // We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2 + // respectively. exp(lo) is computed using a degree-4 minimax polynomial + // generated by Sollya. + + // x_hi = (hi + mid) * 2^7 = round(x * 2^7). + float kf = fputil::nearest_integer(x * 0x1.0p7f); + // Subtract (hi + mid) from x to get lo. + double xd = static_cast(fputil::multiply_add(kf, -0x1.0p-7f, x)); + int x_hi = static_cast(kf); + x_hi += 104 << 7; + // hi = x_hi >> 7 + double exp_hi = EXP_M1[x_hi >> 7]; + // mid * 2^7 = x_hi & 0x0000'007fU; + double exp_mid = EXP_M2[x_hi & 0x7f]; + // Degree-4 minimax polynomial generated by Sollya with the following + // commands: + // > display = hexadecimal; + // > Q = fpminimax(expm1(x)/x, 3, [|D...|], [-2^-8, 2^-8]); + // > Q; + double exp_lo = + fputil::polyeval(xd, 0x1p0, 0x1.ffffffffff777p-1, 0x1.000000000071cp-1, + 0x1.555566668e5e7p-3, 0x1.55555555ef243p-5); + return static_cast(exp_hi * exp_mid * exp_lo); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_H diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp index c531d74c5335..baad26aed685 100644 --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -14,9 +14,9 @@ #include "src/__support/OSUtil/syscall.h" // For syscall functions. #include "src/__support/common.h" #include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" // For error macros #include "src/__support/macros/config.h" #include "src/__support/threads/linux/futex_utils.h" // For FutexWordType -#include "src/errno/libc_errno.h" // For error macros #ifdef LIBC_TARGET_ARCH_IS_AARCH64 #include diff --git a/libc/src/__support/wchar/CMakeLists.txt b/libc/src/__support/wchar/CMakeLists.txt new file mode 100644 index 000000000000..6aade4ccc84a --- /dev/null +++ b/libc/src/__support/wchar/CMakeLists.txt @@ -0,0 +1,53 @@ +add_header_library( + mbstate + HDRS + mbstate.h + DEPENDS + libc.hdr.types.char32_t +) + +add_object_library( + character_converter + HDRS + character_converter.h + SRCS + character_converter.cpp + DEPENDS + libc.hdr.types.char8_t + libc.hdr.types.char32_t + libc.src.__support.error_or + libc.src.__support.math_extras + .mbstate +) + +add_object_library( + wcrtomb + HDRS + wcrtomb.h + SRCS + wcrtomb.cpp + DEPENDS + libc.hdr.types.char32_t + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.__support.error_or + libc.src.__support.common + .character_converter + .mbstate +) + +add_object_library( + mbrtowc + HDRS + mbrtowc.h + SRCS + mbrtowc.cpp + DEPENDS + libc.hdr.types.wchar_t + libc.hdr.types.size_t + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + .character_converter + .mbstate +) diff --git a/libc/src/__support/wchar/character_converter.cpp b/libc/src/__support/wchar/character_converter.cpp new file mode 100644 index 000000000000..1f81de4248ff --- /dev/null +++ b/libc/src/__support/wchar/character_converter.cpp @@ -0,0 +1,150 @@ +//===-- Implementation of a class for conversion --------------------------===// +// +// 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 "hdr/types/char32_t.h" +#include "hdr/types/char8_t.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/math_extras.h" +#include "src/__support/wchar/mbstate.h" + +#include "character_converter.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// This is for utf-8 bytes other than the first byte +constexpr size_t ENCODED_BITS_PER_UTF8 = 6; +// The number of bits per utf-8 byte that actually encode character +// Information not metadata (# of bits excluding the byte headers) +constexpr uint32_t MASK_ENCODED_BITS = + mask_trailing_ones(); + +CharacterConverter::CharacterConverter(mbstate *mbstate) { state = mbstate; } + +void CharacterConverter::clear() { + state->partial = 0; + state->bytes_stored = 0; + state->total_bytes = 0; +} + +bool CharacterConverter::isFull() { + return state->bytes_stored == state->total_bytes && state->total_bytes != 0; +} + +bool CharacterConverter::isEmpty() { return state->bytes_stored == 0; } + +int CharacterConverter::push(char8_t utf8_byte) { + uint8_t num_ones = static_cast(cpp::countl_one(utf8_byte)); + // Checking the first byte if first push + if (isEmpty()) { + // UTF-8 char has 1 byte total + if (num_ones == 0) { + state->total_bytes = 1; + } + // UTF-8 char has 2 through 4 bytes total + else if (num_ones >= 2 && num_ones <= 4) { + /* Since the format is 110xxxxx, 1110xxxx, and 11110xxx for 2, 3, and 4, + we will make the base mask with 7 ones and right shift it as necessary. */ + constexpr size_t SIGNIFICANT_BITS = 7; + char8_t base_mask = + static_cast(mask_trailing_ones()); + state->total_bytes = num_ones; + utf8_byte &= (base_mask >> num_ones); + } + // Invalid first byte + else { + // bytes_stored and total_bytes will always be 0 here + state->partial = static_cast(0); + return -1; + } + state->partial = static_cast(utf8_byte); + state->bytes_stored++; + return 0; + } + // Any subsequent push + // Adding 6 more bits so need to left shift + if (num_ones == 1 && !isFull()) { + char32_t byte = utf8_byte & MASK_ENCODED_BITS; + state->partial = state->partial << ENCODED_BITS_PER_UTF8; + state->partial |= byte; + state->bytes_stored++; + return 0; + } + // Invalid byte -> reset the state + clear(); + return -1; +} + +int CharacterConverter::push(char32_t utf32) { + // we can't be partially through a conversion when pushing a utf32 value + if (!isEmpty()) + return -1; + + state->partial = utf32; + + // determine number of utf-8 bytes needed to represent this utf32 value + constexpr char32_t MAX_VALUE_PER_UTF8_LEN[] = {0x7f, 0x7ff, 0xffff, 0x10ffff}; + constexpr int NUM_RANGES = 4; + for (uint8_t i = 0; i < NUM_RANGES; i++) { + if (state->partial <= MAX_VALUE_PER_UTF8_LEN[i]) { + state->total_bytes = i + 1; + state->bytes_stored = i + 1; + return 0; + } + } + + // `utf32` contains a value that is too large to actually represent a valid + // unicode character + clear(); + return -1; +} + +ErrorOr CharacterConverter::pop_utf32() { + // If pop is called too early, do not reset the state, use error to determine + // whether enough bytes have been pushed + if (!isFull()) + return Error(-1); + char32_t utf32 = state->partial; + // reset if successful pop + clear(); + return utf32; +} + +ErrorOr CharacterConverter::pop_utf8() { + if (isEmpty()) + return Error(-1); + + constexpr char8_t FIRST_BYTE_HEADERS[] = {0, 0xC0, 0xE0, 0xF0}; + constexpr char8_t CONTINUING_BYTE_HEADER = 0x80; + + char32_t output; + + // Shift to get the next 6 bits from the utf32 encoding + const size_t shift_amount = (state->bytes_stored - 1) * ENCODED_BITS_PER_UTF8; + if (isFull()) { + /* + Choose the correct set of most significant bits to encode the length + of the utf8 sequence. The remaining bits contain the most significant + bits of the unicode value of the character. + */ + output = FIRST_BYTE_HEADERS[state->total_bytes - 1] | + (state->partial >> shift_amount); + } else { + // Get the next 6 bits and format it like so: 10xxxxxx + output = CONTINUING_BYTE_HEADER | + ((state->partial >> shift_amount) & MASK_ENCODED_BITS); + } + + state->bytes_stored--; + return static_cast(output); +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/character_converter.h b/libc/src/__support/wchar/character_converter.h new file mode 100644 index 000000000000..be0e6129df23 --- /dev/null +++ b/libc/src/__support/wchar/character_converter.h @@ -0,0 +1,42 @@ +//===-- Definition of a class for mbstate_t and conversion -----*-- 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_LIBC_SRC___SUPPORT_CHARACTER_CONVERTER_H +#define LLVM_LIBC_SRC___SUPPORT_CHARACTER_CONVERTER_H + +#include "hdr/types/char32_t.h" +#include "hdr/types/char8_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +class CharacterConverter { +private: + mbstate *state; + +public: + CharacterConverter(mbstate *mbstate); + + void clear(); + bool isFull(); + bool isEmpty(); + + int push(char8_t utf8_byte); + int push(char32_t utf32); + + ErrorOr pop_utf8(); + ErrorOr pop_utf32(); +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CHARACTER_CONVERTER_H diff --git a/libc/src/__support/wchar/mbrtowc.cpp b/libc/src/__support/wchar/mbrtowc.cpp new file mode 100644 index 000000000000..954c7458f4df --- /dev/null +++ b/libc/src/__support/wchar/mbrtowc.cpp @@ -0,0 +1,49 @@ +//===-- Implementation for mbrtowc function ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/wchar/mbrtowc.h" +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, + size_t n, mbstate *__restrict ps) { + CharacterConverter char_conv(ps); + if (s == nullptr) + return 0; + size_t i = 0; + // Reading in bytes until we have a complete wc or error + for (; i < n && !char_conv.isFull(); ++i) { + int err = char_conv.push(static_cast(s[i])); + // Encoding error + if (err == -1) + return Error(-1); + } + auto wc = char_conv.pop_utf32(); + if (wc.has_value()) { + *pwc = wc.value(); + // null terminator -> return 0 + if (wc.value() == L'\0') + return 0; + return i; + } + // Incomplete but potentially valid + return -2; +} + +} // namespace internal + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/mbrtowc.h b/libc/src/__support/wchar/mbrtowc.h new file mode 100644 index 000000000000..37329ee61bea --- /dev/null +++ b/libc/src/__support/wchar/mbrtowc.h @@ -0,0 +1,29 @@ +//===-- Implementation header for mbrtowc function --------------*- 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_LIBC_SRC___SUPPORT_WCHAR_MBRTOWC +#define LLVM_LIBC_SRC___SUPPORT_WCHAR_MBRTOWC + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, + size_t n, mbstate *__restrict ps); + +} // namespace internal + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WCHAR_MBRTOWC diff --git a/libc/src/__support/wchar/mbstate.h b/libc/src/__support/wchar/mbstate.h new file mode 100644 index 000000000000..32304a521524 --- /dev/null +++ b/libc/src/__support/wchar/mbstate.h @@ -0,0 +1,37 @@ +//===-- Definition of mbstate-----------------------------------*-- 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_LIBC_SRC___SUPPORT_MBSTATE_H +#define LLVM_LIBC_SRC___SUPPORT_MBSTATE_H + +#include "hdr/types/char32_t.h" +#include "src/__support/common.h" +#include + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +struct mbstate { + // store a partial codepoint (in UTF-32) + char32_t partial = 0; + + /* + Progress towards a conversion + Increases with each push(...) until it reaches total_bytes + Decreases with each pop(...) until it reaches 0 + */ + uint8_t bytes_stored = 0; + + // Total number of bytes that will be needed to represent this character + uint8_t total_bytes = 0; +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MBSTATE_H diff --git a/libc/src/__support/wchar/wcrtomb.cpp b/libc/src/__support/wchar/wcrtomb.cpp new file mode 100644 index 000000000000..8ca3d17ad6ce --- /dev/null +++ b/libc/src/__support/wchar/wcrtomb.cpp @@ -0,0 +1,49 @@ +//===-- Implementation of wcrtomb -----------------------------------------===// +// +// 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 "src/__support/wchar/wcrtomb.h" +#include "src/__support/error_or.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +#include "hdr/types/char32_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr wcrtomb(char *__restrict s, wchar_t wc, + mbstate *__restrict ps) { + static_assert(sizeof(wchar_t) == 4); + + CharacterConverter cr(ps); + + if (s == nullptr) + return Error(-1); + + int status = cr.push(static_cast(wc)); + if (status != 0) + return Error(status); + + size_t count = 0; + while (!cr.isEmpty()) { + auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded + LIBC_ASSERT(utf8.has_value()); + + *s = utf8.value(); + s++; + count++; + } + return count; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/wcrtomb.h b/libc/src/__support/wchar/wcrtomb.h new file mode 100644 index 000000000000..bcd39a92a3b7 --- /dev/null +++ b/libc/src/__support/wchar/wcrtomb.h @@ -0,0 +1,26 @@ +//===-- Implementation header for wcrtomb ---------------------------------===// +// +// 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_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H +#define LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps); + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H diff --git a/libc/src/dirent/closedir.cpp b/libc/src/dirent/closedir.cpp index 1249ef94cf41..2f8f6f0c044d 100644 --- a/libc/src/dirent/closedir.cpp +++ b/libc/src/dirent/closedir.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/dir.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/dirent/opendir.cpp b/libc/src/dirent/opendir.cpp index fee14ef0f558..bf47d0edac18 100644 --- a/libc/src/dirent/opendir.cpp +++ b/libc/src/dirent/opendir.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/dir.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/dirent/readdir.cpp b/libc/src/dirent/readdir.cpp index ad460b5e80b8..f95f7c1ae864 100644 --- a/libc/src/dirent/readdir.cpp +++ b/libc/src/dirent/readdir.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/dir.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/errno/CMakeLists.txt b/libc/src/errno/CMakeLists.txt index 1d78a5eedff9..2852044e9416 100644 --- a/libc/src/errno/CMakeLists.txt +++ b/libc/src/errno/CMakeLists.txt @@ -1,28 +1,16 @@ # If we are in full build mode, we will provide the errno definition ourselves, # and if we are in overlay mode, we will just re-use the system's errno. -# We are passing LIBC_FULL_BUILD flag in full build mode so that the -# implementation of libc_errno will know if we are in full build mode or not. - -# TODO: Move LIBC_FULL_BUILD flag to _get_common_compile_options. -set(full_build_flag "") -if(LLVM_LIBC_FULL_BUILD) - set(full_build_flag "-DLIBC_FULL_BUILD") -endif() - -if(LIBC_CONF_ERRNO_MODE) - set(errno_config_copts "-DLIBC_ERRNO_MODE=${LIBC_CONF_ERRNO_MODE}") -endif() add_entrypoint_object( errno SRCS libc_errno.cpp HDRS - libc_errno.h # Include this - COMPILE_OPTIONS - ${full_build_flag} - ${errno_config_copts} + ../__support/libc_errno.h DEPENDS libc.hdr.errno_macros libc.src.__support.common + libc.src.__support.libc_errno + libc.src.__support.macros.attributes + libc.src.__support.macros.config ) diff --git a/libc/src/errno/libc_errno.cpp b/libc/src/errno/libc_errno.cpp index d1600d1b050e..8ff1eec1b103 100644 --- a/libc/src/errno/libc_errno.cpp +++ b/libc/src/errno/libc_errno.cpp @@ -6,51 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "libc_errno.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" -// libc uses a fallback default value, either system or thread local. -#define LIBC_ERRNO_MODE_DEFAULT 0 -// libc never stores a value; `errno` macro uses get link-time failure. -#define LIBC_ERRNO_MODE_UNDEFINED 1 -// libc maintains per-thread state (requires C++ `thread_local` support). -#define LIBC_ERRNO_MODE_THREAD_LOCAL 2 -// libc maintains shared state used by all threads, contrary to standard C -// semantics unless always single-threaded; nothing prevents data races. -#define LIBC_ERRNO_MODE_SHARED 3 -// libc doesn't maintain any internal state, instead the embedder must define -// `int *__llvm_libc_errno(void);` C function. -#define LIBC_ERRNO_MODE_EXTERNAL 4 -// libc uses system `` `errno` macro directly in the overlay mode; in -// fullbuild mode, effectively the same as `LIBC_ERRNO_MODE_EXTERNAL`. -#define LIBC_ERRNO_MODE_SYSTEM 5 - -#if !defined(LIBC_ERRNO_MODE) || LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_DEFAULT -#undef LIBC_ERRNO_MODE -#if defined(LIBC_FULL_BUILD) || !defined(LIBC_COPT_PUBLIC_PACKAGING) -#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_THREAD_LOCAL -#else -#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM -#endif -#endif // LIBC_ERRNO_MODE - -#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_DEFAULT && \ - LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_UNDEFINED && \ - LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_THREAD_LOCAL && \ - LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SHARED && \ - LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_EXTERNAL && \ - LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM -#error LIBC_ERRNO_MODE must be one of the following values: \ -LIBC_ERRNO_MODE_DEFAULT, \ -LIBC_ERRNO_MODE_UNDEFINED, \ -LIBC_ERRNO_MODE_THREAD_LOCAL, \ -LIBC_ERRNO_MODE_SHARED, \ -LIBC_ERRNO_MODE_EXTERNAL, \ -LIBC_ERRNO_MODE_SYSTEM -#endif - namespace LIBC_NAMESPACE_DECL { +#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE + #if LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_UNDEFINED void Errno::operator=(int) {} @@ -93,4 +56,6 @@ Errno::operator int() { return errno; } // Define the global `libc_errno` instance. Errno libc_errno; +#endif // LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE + } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/errno/libc_errno.h b/libc/src/errno/libc_errno.h deleted file mode 100644 index 44ee2714843b..000000000000 --- a/libc/src/errno/libc_errno.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- Implementation header for libc_errno --------------------*- 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_LIBC_SRC_ERRNO_LIBC_ERRNO_H -#define LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H - -#include "src/__support/macros/attributes.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/properties/architectures.h" - -#include "hdr/errno_macros.h" - -// This header is to be consumed by internal implementations, in which all of -// them should refer to `libc_errno` instead of using `errno` directly from -// header. - -// Unit and hermetic tests should: -// - #include "src/errno/libc_errno.h" -// - NOT #include -// - Only use `libc_errno` in the code -// - Depend on libc.src.errno.errno - -// Integration tests should: -// - NOT #include "src/errno/libc_errno.h" -// - #include -// - Use regular `errno` in the code -// - Still depend on libc.src.errno.errno - -namespace LIBC_NAMESPACE_DECL { - -extern "C" int *__llvm_libc_errno() noexcept; - -struct Errno { - void operator=(int); - operator int(); -}; - -extern Errno libc_errno; - -} // namespace LIBC_NAMESPACE_DECL - -#endif // LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H diff --git a/libc/src/fcntl/linux/CMakeLists.txt b/libc/src/fcntl/linux/CMakeLists.txt index 580db16cd413..c31eb3f438c1 100644 --- a/libc/src/fcntl/linux/CMakeLists.txt +++ b/libc/src/fcntl/linux/CMakeLists.txt @@ -19,6 +19,7 @@ add_entrypoint_object( DEPENDS libc.hdr.fcntl_macros libc.src.__support.OSUtil.osutil + libc.src.errno.errno ) add_entrypoint_object( diff --git a/libc/src/fcntl/linux/creat.cpp b/libc/src/fcntl/linux/creat.cpp index 23abae243aed..71412a8e68c5 100644 --- a/libc/src/fcntl/linux/creat.cpp +++ b/libc/src/fcntl/linux/creat.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/fcntl_macros.h" #include // For syscall numbers. diff --git a/libc/src/fcntl/linux/fcntl.cpp b/libc/src/fcntl/linux/fcntl.cpp index a0c8459ced34..fd9c48eb562f 100644 --- a/libc/src/fcntl/linux/fcntl.cpp +++ b/libc/src/fcntl/linux/fcntl.cpp @@ -10,6 +10,7 @@ #include "src/__support/OSUtil/fcntl.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include @@ -22,7 +23,14 @@ LLVM_LIBC_FUNCTION(int, fcntl, (int fd, int cmd, ...)) { va_start(varargs, cmd); arg = va_arg(varargs, void *); va_end(varargs); - return LIBC_NAMESPACE::internal::fcntl(fd, cmd, arg); + + auto result = LIBC_NAMESPACE::internal::fcntl(fd, cmd, arg); + + if (!result.has_value()) { + libc_errno = result.error(); + return -1; + } + return result.value(); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/fcntl/linux/open.cpp b/libc/src/fcntl/linux/open.cpp index 8b699ecdd204..3a56d1055419 100644 --- a/libc/src/fcntl/linux/open.cpp +++ b/libc/src/fcntl/linux/open.cpp @@ -8,15 +8,13 @@ #include "src/fcntl/open.h" -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" - #include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" +#include "src/__support/OSUtil/fcntl.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" #include -#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { @@ -31,17 +29,13 @@ LLVM_LIBC_FUNCTION(int, open, (const char *path, int flags, ...)) { va_end(varargs); } -#ifdef SYS_open - int fd = LIBC_NAMESPACE::syscall_impl(SYS_open, path, flags, mode_flags); -#else - int fd = LIBC_NAMESPACE::syscall_impl(SYS_openat, AT_FDCWD, path, flags, - mode_flags); -#endif - if (fd > 0) - return fd; + auto result = internal::open(path, flags, mode_flags); - libc_errno = -fd; - return -1; + if (!result.has_value()) { + libc_errno = result.error(); + return -1; + } + return result.value(); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/fcntl/linux/openat.cpp b/libc/src/fcntl/linux/openat.cpp index 6063d9c00ad6..b47ad1fb3bb0 100644 --- a/libc/src/fcntl/linux/openat.cpp +++ b/libc/src/fcntl/linux/openat.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/types/mode_t.h" #include diff --git a/libc/src/inttypes/strtoimax.cpp b/libc/src/inttypes/strtoimax.cpp index 85f197c75d90..6e55a4b56aac 100644 --- a/libc/src/inttypes/strtoimax.cpp +++ b/libc/src/inttypes/strtoimax.cpp @@ -8,9 +8,9 @@ #include "src/inttypes/strtoimax.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/inttypes/strtoumax.cpp b/libc/src/inttypes/strtoumax.cpp index 2e9cbc9acba7..ce5a0a782d97 100644 --- a/libc/src/inttypes/strtoumax.cpp +++ b/libc/src/inttypes/strtoumax.cpp @@ -8,9 +8,9 @@ #include "src/inttypes/strtoumax.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index db3ef8886b52..fd1e6c0d648a 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -1321,15 +1321,7 @@ add_entrypoint_object( HDRS ../expf.h DEPENDS - .common_constants - libc.src.__support.FPUtil.basic_operations - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.macros.optimization + libc.src.__support.math.expf libc.src.errno.errno ) diff --git a/libc/src/math/generic/exp10m1f.cpp b/libc/src/math/generic/exp10m1f.cpp index e973b2921c2e..27729104e038 100644 --- a/libc/src/math/generic/exp10m1f.cpp +++ b/libc/src/math/generic/exp10m1f.cpp @@ -14,9 +14,9 @@ #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" -#include "src/errno/libc_errno.h" #include "explogxf.h" diff --git a/libc/src/math/generic/exp2m1f.cpp b/libc/src/math/generic/exp2m1f.cpp index 4913a5e4277e..127c6eaa494d 100644 --- a/libc/src/math/generic/exp2m1f.cpp +++ b/libc/src/math/generic/exp2m1f.cpp @@ -14,10 +14,10 @@ #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/cpu_features.h" -#include "src/errno/libc_errno.h" #include "explogxf.h" diff --git a/libc/src/math/generic/expf.cpp b/libc/src/math/generic/expf.cpp index fa507d4d9322..de11f51ac64a 100644 --- a/libc/src/math/generic/expf.cpp +++ b/libc/src/math/generic/expf.cpp @@ -7,103 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/expf.h" -#include "common_constants.h" // Lookup tables EXP_M1 and EXP_M2. -#include "src/__support/FPUtil/BasicOperations.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/math/expf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, expf, (float x)) { - using FPBits = typename fputil::FPBits; - FPBits xbits(x); - - uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & 0x7fff'ffffU; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Exceptional values - if (LIBC_UNLIKELY(x_u == 0xc236'bd8cU)) { // x = -0x1.6d7b18p+5f - return 0x1.108a58p-66f - x * 0x1.0p-95f; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // When |x| >= 89, |x| < 2^-25, or x is nan - if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) { - // |x| < 2^-25 - if (xbits.get_biased_exponent() <= 101) { - return 1.0f + x; - } - - // When x < log(2^-150) or nan - if (xbits.uintval() >= 0xc2cf'f1b5U) { - // exp(-Inf) = 0 - if (xbits.is_inf()) - return 0.0f; - // exp(nan) = nan - if (xbits.is_nan()) - return x; - if (fputil::fenv_is_round_up()) - return FPBits::min_subnormal().get_val(); - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_UNDERFLOW); - return 0.0f; - } - // x >= 89 or nan - if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) { - // x is finite - if (xbits.uintval() < 0x7f80'0000U) { - int rounding = fputil::quick_get_round(); - if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) - return FPBits::max_normal().get_val(); - - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - } - // x is +inf or nan - return x + FPBits::inf().get_val(); - } - } - // For -104 < x < 89, to compute exp(x), we perform the following range - // reduction: find hi, mid, lo such that: - // x = hi + mid + lo, in which - // hi is an integer, - // mid * 2^7 is an integer - // -2^(-8) <= lo < 2^-8. - // In particular, - // hi + mid = round(x * 2^7) * 2^(-7). - // Then, - // exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo). - // We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2 - // respectively. exp(lo) is computed using a degree-4 minimax polynomial - // generated by Sollya. - - // x_hi = (hi + mid) * 2^7 = round(x * 2^7). - float kf = fputil::nearest_integer(x * 0x1.0p7f); - // Subtract (hi + mid) from x to get lo. - double xd = static_cast(fputil::multiply_add(kf, -0x1.0p-7f, x)); - int x_hi = static_cast(kf); - x_hi += 104 << 7; - // hi = x_hi >> 7 - double exp_hi = EXP_M1[x_hi >> 7]; - // mid * 2^7 = x_hi & 0x0000'007fU; - double exp_mid = EXP_M2[x_hi & 0x7f]; - // Degree-4 minimax polynomial generated by Sollya with the following - // commands: - // > display = hexadecimal; - // > Q = fpminimax(expm1(x)/x, 3, [|D...|], [-2^-8, 2^-8]); - // > Q; - double exp_lo = - fputil::polyeval(xd, 0x1p0, 0x1.ffffffffff777p-1, 0x1.000000000071cp-1, - 0x1.555566668e5e7p-3, 0x1.55555555ef243p-5); - return static_cast(exp_hi * exp_mid * exp_lo); -} +LLVM_LIBC_FUNCTION(float, expf, (float x)) { return math::expf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp index b25ec41f277b..cff718eec216 100644 --- a/libc/src/math/generic/log2f.cpp +++ b/libc/src/math/generic/log2f.cpp @@ -79,7 +79,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) { } if (xbits.is_neg() && !xbits.is_nan()) { fputil::set_errno_if_required(EDOM); - fputil::raise_except(FE_INVALID); + fputil::raise_except_if_required(FE_INVALID); return FPBits::quiet_nan().get_val(); } if (xbits.is_inf_or_nan()) { diff --git a/libc/src/math/generic/nan.cpp b/libc/src/math/generic/nan.cpp index f92cd3ff5eb5..829a2ea435ac 100644 --- a/libc/src/math/generic/nan.cpp +++ b/libc/src/math/generic/nan.cpp @@ -8,9 +8,9 @@ #include "src/math/nan.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/generic/nanf.cpp b/libc/src/math/generic/nanf.cpp index 7287182406ac..1cb66160e736 100644 --- a/libc/src/math/generic/nanf.cpp +++ b/libc/src/math/generic/nanf.cpp @@ -8,9 +8,9 @@ #include "src/math/nanf.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/generic/nanf128.cpp b/libc/src/math/generic/nanf128.cpp index 3d8581afa037..4155c5333a9c 100644 --- a/libc/src/math/generic/nanf128.cpp +++ b/libc/src/math/generic/nanf128.cpp @@ -8,9 +8,9 @@ #include "src/math/nanf128.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/generic/nanf16.cpp b/libc/src/math/generic/nanf16.cpp index 27d9d165f4a8..7b166400601b 100644 --- a/libc/src/math/generic/nanf16.cpp +++ b/libc/src/math/generic/nanf16.cpp @@ -8,9 +8,9 @@ #include "src/math/nanf16.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/generic/nanl.cpp b/libc/src/math/generic/nanl.cpp index 4f698cb3c88d..58d638c4b531 100644 --- a/libc/src/math/generic/nanl.cpp +++ b/libc/src/math/generic/nanl.cpp @@ -8,9 +8,9 @@ #include "src/math/nanl.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/poll/linux/poll.cpp b/libc/src/poll/linux/poll.cpp index f82fcbcc6577..4cac75b9687c 100644 --- a/libc/src/poll/linux/poll.cpp +++ b/libc/src/poll/linux/poll.cpp @@ -13,8 +13,8 @@ #include "hdr/types/struct_timespec.h" #include "src/__support/OSUtil/syscall.h" // syscall_impl #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // SYS_poll, SYS_ppoll diff --git a/libc/src/pthread/pthread_atfork.cpp b/libc/src/pthread/pthread_atfork.cpp index b2c67c78e5d9..4cad16a02de7 100644 --- a/libc/src/pthread/pthread_atfork.cpp +++ b/libc/src/pthread/pthread_atfork.cpp @@ -9,9 +9,9 @@ #include "pthread_atfork.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/fork_callbacks.h" -#include "src/errno/libc_errno.h" #include // For pthread_* type definitions. diff --git a/libc/src/pthread/pthread_attr_setdetachstate.cpp b/libc/src/pthread/pthread_attr_setdetachstate.cpp index 872f694e01f3..c482d25610c2 100644 --- a/libc/src/pthread/pthread_attr_setdetachstate.cpp +++ b/libc/src/pthread/pthread_attr_setdetachstate.cpp @@ -9,8 +9,8 @@ #include "pthread_attr_setdetachstate.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_attr_setguardsize.cpp b/libc/src/pthread/pthread_attr_setguardsize.cpp index fa4375e915ab..c996210a61d8 100644 --- a/libc/src/pthread/pthread_attr_setguardsize.cpp +++ b/libc/src/pthread/pthread_attr_setguardsize.cpp @@ -9,8 +9,8 @@ #include "pthread_attr_setguardsize.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For EXEC_PAGESIZE. #include diff --git a/libc/src/pthread/pthread_attr_setstack.cpp b/libc/src/pthread/pthread_attr_setstack.cpp index 1154055a63a7..767f959b1400 100644 --- a/libc/src/pthread/pthread_attr_setstack.cpp +++ b/libc/src/pthread/pthread_attr_setstack.cpp @@ -10,9 +10,9 @@ #include "pthread_attr_setstacksize.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/thread.h" // For STACK_ALIGNMENT -#include "src/errno/libc_errno.h" #include #include diff --git a/libc/src/pthread/pthread_attr_setstacksize.cpp b/libc/src/pthread/pthread_attr_setstacksize.cpp index 0a5d1af661ab..38c77ca761d6 100644 --- a/libc/src/pthread/pthread_attr_setstacksize.cpp +++ b/libc/src/pthread/pthread_attr_setstacksize.cpp @@ -9,8 +9,8 @@ #include "pthread_attr_setstacksize.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_condattr_setclock.cpp b/libc/src/pthread/pthread_condattr_setclock.cpp index 5e825d5ecea6..2f63d5e9d194 100644 --- a/libc/src/pthread/pthread_condattr_setclock.cpp +++ b/libc/src/pthread/pthread_condattr_setclock.cpp @@ -9,8 +9,8 @@ #include "pthread_condattr_setclock.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/time_macros.h" // CLOCK_MONOTONIC, CLOCK_REALTIME #include // pthread_condattr_t diff --git a/libc/src/pthread/pthread_condattr_setpshared.cpp b/libc/src/pthread/pthread_condattr_setpshared.cpp index 433b2dc1d2d9..9c117499a559 100644 --- a/libc/src/pthread/pthread_condattr_setpshared.cpp +++ b/libc/src/pthread/pthread_condattr_setpshared.cpp @@ -9,8 +9,8 @@ #include "pthread_condattr_setpshared.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // pthread_condattr_t, PTHREAD_PROCESS_SHARED, PTHREAD_PROCESS_PRIVATE diff --git a/libc/src/pthread/pthread_create.cpp b/libc/src/pthread/pthread_create.cpp index e1b1f3b325d1..45be2807fa83 100644 --- a/libc/src/pthread/pthread_create.cpp +++ b/libc/src/pthread/pthread_create.cpp @@ -16,10 +16,10 @@ #include "pthread_attr_getstack.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" #include // For pthread_* type definitions. diff --git a/libc/src/pthread/pthread_key_create.cpp b/libc/src/pthread/pthread_key_create.cpp index 383762f273e7..7253de14cc0d 100644 --- a/libc/src/pthread/pthread_key_create.cpp +++ b/libc/src/pthread/pthread_key_create.cpp @@ -9,9 +9,9 @@ #include "pthread_key_create.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_key_delete.cpp b/libc/src/pthread/pthread_key_delete.cpp index b54db821ab05..2b14d874fe31 100644 --- a/libc/src/pthread/pthread_key_delete.cpp +++ b/libc/src/pthread/pthread_key_delete.cpp @@ -9,9 +9,9 @@ #include "pthread_key_delete.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_mutexattr_setpshared.cpp b/libc/src/pthread/pthread_mutexattr_setpshared.cpp index deeae15be230..a87a08259c4b 100644 --- a/libc/src/pthread/pthread_mutexattr_setpshared.cpp +++ b/libc/src/pthread/pthread_mutexattr_setpshared.cpp @@ -10,8 +10,8 @@ #include "pthread_mutexattr.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_mutexattr_setrobust.cpp b/libc/src/pthread/pthread_mutexattr_setrobust.cpp index 9fd46f4c928d..fd7a8d7ce1d1 100644 --- a/libc/src/pthread/pthread_mutexattr_setrobust.cpp +++ b/libc/src/pthread/pthread_mutexattr_setrobust.cpp @@ -10,8 +10,8 @@ #include "pthread_mutexattr.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_mutexattr_settype.cpp b/libc/src/pthread/pthread_mutexattr_settype.cpp index c7e78271f9c3..5a65f031045d 100644 --- a/libc/src/pthread/pthread_mutexattr_settype.cpp +++ b/libc/src/pthread/pthread_mutexattr_settype.cpp @@ -10,8 +10,8 @@ #include "pthread_mutexattr.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_rwlock_timedrdlock.cpp b/libc/src/pthread/pthread_rwlock_timedrdlock.cpp index 112ff5c9cdad..fcddfed22490 100644 --- a/libc/src/pthread/pthread_rwlock_timedrdlock.cpp +++ b/libc/src/pthread/pthread_rwlock_timedrdlock.cpp @@ -9,11 +9,11 @@ #include "src/pthread/pthread_rwlock_timedrdlock.h" #include "src/__support/common.h" #include "src/__support/libc_assert.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/threads/linux/rwlock.h" #include "src/__support/time/linux/abs_timeout.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_rwlock_trywrlock.cpp b/libc/src/pthread/pthread_rwlock_trywrlock.cpp index a63dc893e716..660c15a87b36 100644 --- a/libc/src/pthread/pthread_rwlock_trywrlock.cpp +++ b/libc/src/pthread/pthread_rwlock_trywrlock.cpp @@ -9,9 +9,9 @@ #include "src/pthread/pthread_rwlock_trywrlock.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/linux/rwlock.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_rwlock_unlock.cpp b/libc/src/pthread/pthread_rwlock_unlock.cpp index e61290179bd6..5496bea929c5 100644 --- a/libc/src/pthread/pthread_rwlock_unlock.cpp +++ b/libc/src/pthread/pthread_rwlock_unlock.cpp @@ -9,9 +9,9 @@ #include "src/pthread/pthread_rwlock_unlock.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/linux/rwlock.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/pthread/pthread_rwlockattr_setkind_np.cpp b/libc/src/pthread/pthread_rwlockattr_setkind_np.cpp index 80d34a35c717..e6800311b858 100644 --- a/libc/src/pthread/pthread_rwlockattr_setkind_np.cpp +++ b/libc/src/pthread/pthread_rwlockattr_setkind_np.cpp @@ -9,8 +9,8 @@ #include "pthread_rwlockattr_setkind_np.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // pthread_rwlockattr_t diff --git a/libc/src/pthread/pthread_rwlockattr_setpshared.cpp b/libc/src/pthread/pthread_rwlockattr_setpshared.cpp index 5a7191aefd3d..4fbd095ac2b4 100644 --- a/libc/src/pthread/pthread_rwlockattr_setpshared.cpp +++ b/libc/src/pthread/pthread_rwlockattr_setpshared.cpp @@ -9,8 +9,8 @@ #include "pthread_rwlockattr_setpshared.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // pthread_rwlockattr_t, PTHREAD_PROCESS_SHARED, PTHREAD_PROCESS_PRIVATE diff --git a/libc/src/pthread/pthread_setspecific.cpp b/libc/src/pthread/pthread_setspecific.cpp index 70c29c167084..b147a66d2fad 100644 --- a/libc/src/pthread/pthread_setspecific.cpp +++ b/libc/src/pthread/pthread_setspecific.cpp @@ -9,9 +9,9 @@ #include "pthread_setspecific.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/sched/linux/sched_get_priority_max.cpp b/libc/src/sched/linux/sched_get_priority_max.cpp index 77a82c77405f..fb30b1e319e7 100644 --- a/libc/src/sched/linux/sched_get_priority_max.cpp +++ b/libc/src/sched/linux/sched_get_priority_max.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_get_priority_min.cpp b/libc/src/sched/linux/sched_get_priority_min.cpp index fca66a15edb5..54f67e915fc1 100644 --- a/libc/src/sched/linux/sched_get_priority_min.cpp +++ b/libc/src/sched/linux/sched_get_priority_min.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_getaffinity.cpp b/libc/src/sched/linux/sched_getaffinity.cpp index 7b1fd8c5aa2a..e005819e2a97 100644 --- a/libc/src/sched/linux/sched_getaffinity.cpp +++ b/libc/src/sched/linux/sched_getaffinity.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include diff --git a/libc/src/sched/linux/sched_getparam.cpp b/libc/src/sched/linux/sched_getparam.cpp index 75756a65f0ed..b0576c3ac65b 100644 --- a/libc/src/sched/linux/sched_getparam.cpp +++ b/libc/src/sched/linux/sched_getparam.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_getscheduler.cpp b/libc/src/sched/linux/sched_getscheduler.cpp index 545cda8e7484..d8e02967a633 100644 --- a/libc/src/sched/linux/sched_getscheduler.cpp +++ b/libc/src/sched/linux/sched_getscheduler.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_rr_get_interval.cpp b/libc/src/sched/linux/sched_rr_get_interval.cpp index 1f0ef69dfc89..5668d596bce1 100644 --- a/libc/src/sched/linux/sched_rr_get_interval.cpp +++ b/libc/src/sched/linux/sched_rr_get_interval.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_setaffinity.cpp b/libc/src/sched/linux/sched_setaffinity.cpp index cad48c26bf93..93e930dcf2e3 100644 --- a/libc/src/sched/linux/sched_setaffinity.cpp +++ b/libc/src/sched/linux/sched_setaffinity.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_setparam.cpp b/libc/src/sched/linux/sched_setparam.cpp index e78e78a707e0..7875d9e2f19b 100644 --- a/libc/src/sched/linux/sched_setparam.cpp +++ b/libc/src/sched/linux/sched_setparam.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_setscheduler.cpp b/libc/src/sched/linux/sched_setscheduler.cpp index b6b6f667b3f9..232e5a59b185 100644 --- a/libc/src/sched/linux/sched_setscheduler.cpp +++ b/libc/src/sched/linux/sched_setscheduler.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sched/linux/sched_yield.cpp b/libc/src/sched/linux/sched_yield.cpp index 3de9d0ba3571..c1e9168f34d0 100644 --- a/libc/src/sched/linux/sched_yield.cpp +++ b/libc/src/sched/linux/sched_yield.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/search/hcreate.cpp b/libc/src/search/hcreate.cpp index ac816a902e22..68bdb29e51df 100644 --- a/libc/src/search/hcreate.cpp +++ b/libc/src/search/hcreate.cpp @@ -9,8 +9,8 @@ #include "src/search/hcreate.h" #include "src/__support/HashTable/randomness.h" #include "src/__support/HashTable/table.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/search/hsearch/global.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/search/hcreate_r.cpp b/libc/src/search/hcreate_r.cpp index 17acd808c19a..c89be803b4e1 100644 --- a/libc/src/search/hcreate_r.cpp +++ b/libc/src/search/hcreate_r.cpp @@ -9,8 +9,8 @@ #include "src/search/hcreate_r.h" #include "src/__support/HashTable/randomness.h" #include "src/__support/HashTable/table.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, hcreate_r, diff --git a/libc/src/search/hdestroy_r.cpp b/libc/src/search/hdestroy_r.cpp index 7eff5bb6fff9..ba5476098be2 100644 --- a/libc/src/search/hdestroy_r.cpp +++ b/libc/src/search/hdestroy_r.cpp @@ -8,8 +8,8 @@ #include "src/search/hdestroy_r.h" #include "src/__support/HashTable/table.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void, hdestroy_r, (struct hsearch_data * htab)) { diff --git a/libc/src/search/hsearch.cpp b/libc/src/search/hsearch.cpp index c18b5d3d7f54..034333d17057 100644 --- a/libc/src/search/hsearch.cpp +++ b/libc/src/search/hsearch.cpp @@ -9,8 +9,8 @@ #include "src/search/hsearch.h" #include "src/__support/HashTable/randomness.h" #include "src/__support/HashTable/table.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/search/hsearch/global.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/search/hsearch_r.cpp b/libc/src/search/hsearch_r.cpp index f93e608a190b..323001e1b103 100644 --- a/libc/src/search/hsearch_r.cpp +++ b/libc/src/search/hsearch_r.cpp @@ -8,8 +8,8 @@ #include "src/search/hsearch_r.h" #include "src/__support/HashTable/table.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, hsearch_r, diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt index 239254fa57dc..8b8e74f0955e 100644 --- a/libc/src/setjmp/CMakeLists.txt +++ b/libc/src/setjmp/CMakeLists.txt @@ -1,3 +1,6 @@ +# Process architecture-specific subdirectory FIRST to avoid missing targets. + +# Then process OS-specific subdirectory if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) add_object_library( diff --git a/libc/src/setjmp/darwin/CMakeLists.txt b/libc/src/setjmp/darwin/CMakeLists.txt new file mode 100644 index 000000000000..b844c8c5ee55 --- /dev/null +++ b/libc/src/setjmp/darwin/CMakeLists.txt @@ -0,0 +1,12 @@ +add_object_library( + sigsetjmp_epilogue + HDRS + ../sigsetjmp_epilogue.h + SRCS + sigsetjmp_epilogue.cpp + DEPENDS + libc.src.__support.common + libc.src.__support.OSUtil.osutil + libc.hdr.types.jmp_buf + libc.hdr.types.sigset_t +) diff --git a/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp b/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp new file mode 100644 index 000000000000..b2ca4d99ed82 --- /dev/null +++ b/libc/src/setjmp/darwin/sigsetjmp_epilogue.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of sigsetjmp_epilogue ------------------------------===// +// +// 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 "src/setjmp/sigsetjmp_epilogue.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" +#include "src/signal/sigprocmask.h" + +namespace LIBC_NAMESPACE_DECL { +[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval) { + syscall_impl(sigprocmask, SIG_SETMASK, + /* set= */ retval ? &buffer->sigmask : nullptr, + /* old_set= */ retval ? nullptr : &buffer->sigmask); + return retval; +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/signal/linux/kill.cpp b/libc/src/signal/linux/kill.cpp index ed117858f51e..0f5e88757acb 100644 --- a/libc/src/signal/linux/kill.cpp +++ b/libc/src/signal/linux/kill.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include diff --git a/libc/src/signal/linux/sigaction.cpp b/libc/src/signal/linux/sigaction.cpp index 65ec36741683..43a3e195474e 100644 --- a/libc/src/signal/linux/sigaction.cpp +++ b/libc/src/signal/linux/sigaction.cpp @@ -10,8 +10,8 @@ #include "hdr/types/sigset_t.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/signal/linux/sigaddset.cpp b/libc/src/signal/linux/sigaddset.cpp index 628883e13b88..2091e8b51453 100644 --- a/libc/src/signal/linux/sigaddset.cpp +++ b/libc/src/signal/linux/sigaddset.cpp @@ -10,8 +10,8 @@ #include "hdr/types/sigset_t.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/signal/linux/sigaltstack.cpp b/libc/src/signal/linux/sigaltstack.cpp index c19394cd1791..990b841c6d90 100644 --- a/libc/src/signal/linux/sigaltstack.cpp +++ b/libc/src/signal/linux/sigaltstack.cpp @@ -8,8 +8,8 @@ #include "src/signal/sigaltstack.h" #include "hdr/types/stack_t.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include "src/__support/common.h" diff --git a/libc/src/signal/linux/sigdelset.cpp b/libc/src/signal/linux/sigdelset.cpp index 2e964051ebde..6fce0d7a6e14 100644 --- a/libc/src/signal/linux/sigdelset.cpp +++ b/libc/src/signal/linux/sigdelset.cpp @@ -10,8 +10,8 @@ #include "hdr/types/sigset_t.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/signal/linux/sigemptyset.cpp b/libc/src/signal/linux/sigemptyset.cpp index d347477695e6..034a9e2cbe15 100644 --- a/libc/src/signal/linux/sigemptyset.cpp +++ b/libc/src/signal/linux/sigemptyset.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/signal/sigemptyset.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include "src/__support/common.h" diff --git a/libc/src/signal/linux/sigfillset.cpp b/libc/src/signal/linux/sigfillset.cpp index 3e9897a03bb7..f0b499093b31 100644 --- a/libc/src/signal/linux/sigfillset.cpp +++ b/libc/src/signal/linux/sigfillset.cpp @@ -10,8 +10,8 @@ #include "hdr/types/sigset_t.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/signal/linux/sigprocmask.cpp b/libc/src/signal/linux/sigprocmask.cpp index 8838379ae5d3..af3c424c5f34 100644 --- a/libc/src/signal/linux/sigprocmask.cpp +++ b/libc/src/signal/linux/sigprocmask.cpp @@ -11,8 +11,8 @@ #include "hdr/types/sigset_t.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include // For syscall numbers. diff --git a/libc/src/spawn/posix_spawn_file_actions_addclose.cpp b/libc/src/spawn/posix_spawn_file_actions_addclose.cpp index bb8504f655c4..9a575bd59163 100644 --- a/libc/src/spawn/posix_spawn_file_actions_addclose.cpp +++ b/libc/src/spawn/posix_spawn_file_actions_addclose.cpp @@ -11,8 +11,8 @@ #include "file_actions.h" #include "src/__support/CPP/new.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp b/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp index 710063d52e74..1ad45ed942bb 100644 --- a/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp +++ b/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp @@ -11,8 +11,8 @@ #include "file_actions.h" #include "src/__support/CPP/new.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/spawn/posix_spawn_file_actions_addopen.cpp b/libc/src/spawn/posix_spawn_file_actions_addopen.cpp index 028d6e895f3c..9977fc2d0a21 100644 --- a/libc/src/spawn/posix_spawn_file_actions_addopen.cpp +++ b/libc/src/spawn/posix_spawn_file_actions_addopen.cpp @@ -11,8 +11,8 @@ #include "file_actions.h" #include "src/__support/CPP/new.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/spawn/posix_spawn_file_actions_destroy.cpp b/libc/src/spawn/posix_spawn_file_actions_destroy.cpp index 168118da249d..affd338005cf 100644 --- a/libc/src/spawn/posix_spawn_file_actions_destroy.cpp +++ b/libc/src/spawn/posix_spawn_file_actions_destroy.cpp @@ -12,8 +12,8 @@ #include "src/__support/CPP/new.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index 63f6ed8a11f1..b0a6ef1e291b 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -221,6 +221,7 @@ add_stdio_entrypoint_object(fopen) add_stdio_entrypoint_object(fclose) add_stdio_entrypoint_object(fread_unlocked) add_stdio_entrypoint_object(fread) +add_stdio_entrypoint_object(perror) add_stdio_entrypoint_object(puts) add_stdio_entrypoint_object(fputs) add_stdio_entrypoint_object(fwrite_unlocked) diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index c94698ec0295..7253c6549a4e 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -21,8 +21,8 @@ namespace LIBC_NAMESPACE_DECL { namespace { -LIBC_INLINE int raw_write_hook(cpp::string_view new_str, void *) { - write_to_stderr(new_str); +LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { + write_to_stdout(new_str); return printf_core::WRITE_OK; } @@ -35,11 +35,11 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); - constexpr size_t BUFF_SIZE = 1024; + static constexpr size_t BUFF_SIZE = 1024; char buffer[BUFF_SIZE]; printf_core::WriteBuffer wb( - buffer, BUFF_SIZE, &raw_write_hook, nullptr); + buffer, BUFF_SIZE, &stdout_write_hook, nullptr); printf_core::Writer writer(wb); int retval = printf_core::printf_main(&writer, format, args); diff --git a/libc/src/stdio/baremetal/putchar.cpp b/libc/src/stdio/baremetal/putchar.cpp index 0ba46a5ade6c..ac21e6e783b0 100644 --- a/libc/src/stdio/baremetal/putchar.cpp +++ b/libc/src/stdio/baremetal/putchar.cpp @@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, putchar, (int c)) { char uc = static_cast(c); - write_to_stderr(cpp::string_view(&uc, 1)); + write_to_stdout(cpp::string_view(&uc, 1)); return 0; } diff --git a/libc/src/stdio/baremetal/puts.cpp b/libc/src/stdio/baremetal/puts.cpp index 5062efda1c0d..fcd3aa086b2b 100644 --- a/libc/src/stdio/baremetal/puts.cpp +++ b/libc/src/stdio/baremetal/puts.cpp @@ -17,8 +17,8 @@ LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) { cpp::string_view str_view(str); // TODO: Can we combine these to avoid needing two writes? - write_to_stderr(str_view); - write_to_stderr("\n"); + write_to_stdout(str_view); + write_to_stdout("\n"); return 0; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 3e8631abd90d..ab02533f1491 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -21,8 +21,8 @@ namespace LIBC_NAMESPACE_DECL { namespace { -LIBC_INLINE int raw_write_hook(cpp::string_view new_str, void *) { - write_to_stderr(new_str); +LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { + write_to_stdout(new_str); return printf_core::WRITE_OK; } @@ -33,11 +33,11 @@ LLVM_LIBC_FUNCTION(int, vprintf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - constexpr size_t BUFF_SIZE = 1024; + static constexpr size_t BUFF_SIZE = 1024; char buffer[BUFF_SIZE]; printf_core::WriteBuffer wb( - buffer, BUFF_SIZE, &raw_write_hook, nullptr); + buffer, BUFF_SIZE, &stdout_write_hook, nullptr); printf_core::Writer writer(wb); int retval = printf_core::printf_main(&writer, format, args); diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp index 9f5694e8e058..da8a132a4db6 100644 --- a/libc/src/stdio/fopencookie.cpp +++ b/libc/src/stdio/fopencookie.cpp @@ -14,8 +14,8 @@ #include "src/__support/CPP/new.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt index e1f4ed5c1949..6361822b6199 100644 --- a/libc/src/stdio/generic/CMakeLists.txt +++ b/libc/src/stdio/generic/CMakeLists.txt @@ -206,6 +206,21 @@ add_generic_entrypoint_object( libc.src.__support.File.platform_file ) +add_generic_entrypoint_object( + perror + SRCS + perror.cpp + HDRS + ../perror.h + DEPENDS + libc.src.errno.errno + libc.src.__support.StringUtil.error_to_string + libc.src.__support.CPP.string_view + libc.src.__support.File.file + libc.src.__support.File.platform_file + libc.src.__support.File.platform_stderr +) + add_generic_entrypoint_object( fputs SRCS diff --git a/libc/src/stdio/generic/fclose.cpp b/libc/src/stdio/generic/fclose.cpp index 388407a58d41..902b4cf97237 100644 --- a/libc/src/stdio/generic/fclose.cpp +++ b/libc/src/stdio/generic/fclose.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fflush.cpp b/libc/src/stdio/generic/fflush.cpp index 5bdf71ad3594..d0271d9154c8 100644 --- a/libc/src/stdio/generic/fflush.cpp +++ b/libc/src/stdio/generic/fflush.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fgetc.cpp b/libc/src/stdio/generic/fgetc.cpp index aa6660ca180c..e65ce2fda49b 100644 --- a/libc/src/stdio/generic/fgetc.cpp +++ b/libc/src/stdio/generic/fgetc.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fgetc_unlocked.cpp b/libc/src/stdio/generic/fgetc_unlocked.cpp index 34a27f1d1c42..5c07d4feb513 100644 --- a/libc/src/stdio/generic/fgetc_unlocked.cpp +++ b/libc/src/stdio/generic/fgetc_unlocked.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fgets.cpp b/libc/src/stdio/generic/fgets.cpp index de6474087a14..e0ad9b6e2f56 100644 --- a/libc/src/stdio/generic/fgets.cpp +++ b/libc/src/stdio/generic/fgets.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fopen.cpp b/libc/src/stdio/generic/fopen.cpp index d6e418bacf37..57c85c2e54e1 100644 --- a/libc/src/stdio/generic/fopen.cpp +++ b/libc/src/stdio/generic/fopen.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fputc.cpp b/libc/src/stdio/generic/fputc.cpp index 54a38aeb2f1e..6639f0687c87 100644 --- a/libc/src/stdio/generic/fputc.cpp +++ b/libc/src/stdio/generic/fputc.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fputs.cpp b/libc/src/stdio/generic/fputs.cpp index 8aef7683b3ce..621b40f63c91 100644 --- a/libc/src/stdio/generic/fputs.cpp +++ b/libc/src/stdio/generic/fputs.cpp @@ -11,8 +11,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fread.cpp b/libc/src/stdio/generic/fread.cpp index 3a04094ea8b4..1b576ec34688 100644 --- a/libc/src/stdio/generic/fread.cpp +++ b/libc/src/stdio/generic/fread.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fread_unlocked.cpp b/libc/src/stdio/generic/fread_unlocked.cpp index 151f43c6bbeb..257f1a212add 100644 --- a/libc/src/stdio/generic/fread_unlocked.cpp +++ b/libc/src/stdio/generic/fread_unlocked.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fseek.cpp b/libc/src/stdio/generic/fseek.cpp index 21820da18542..99191e7c4194 100644 --- a/libc/src/stdio/generic/fseek.cpp +++ b/libc/src/stdio/generic/fseek.cpp @@ -9,8 +9,8 @@ #include "src/stdio/fseek.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fseeko.cpp b/libc/src/stdio/generic/fseeko.cpp index 7456b4a21907..afcfc71c7c09 100644 --- a/libc/src/stdio/generic/fseeko.cpp +++ b/libc/src/stdio/generic/fseeko.cpp @@ -9,8 +9,8 @@ #include "src/stdio/fseeko.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/ftell.cpp b/libc/src/stdio/generic/ftell.cpp index ec15ca4e96ca..b55a806007af 100644 --- a/libc/src/stdio/generic/ftell.cpp +++ b/libc/src/stdio/generic/ftell.cpp @@ -9,8 +9,8 @@ #include "src/stdio/ftell.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/ftello.cpp b/libc/src/stdio/generic/ftello.cpp index e3d0726ec484..91031cb7fad7 100644 --- a/libc/src/stdio/generic/ftello.cpp +++ b/libc/src/stdio/generic/ftello.cpp @@ -9,8 +9,8 @@ #include "src/stdio/ftello.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fwrite.cpp b/libc/src/stdio/generic/fwrite.cpp index 66eb9a3c7185..b44ecb283811 100644 --- a/libc/src/stdio/generic/fwrite.cpp +++ b/libc/src/stdio/generic/fwrite.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/fwrite_unlocked.cpp b/libc/src/stdio/generic/fwrite_unlocked.cpp index a0d9014cd68d..2f9ec26f2f80 100644 --- a/libc/src/stdio/generic/fwrite_unlocked.cpp +++ b/libc/src/stdio/generic/fwrite_unlocked.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/getc.cpp b/libc/src/stdio/generic/getc.cpp index e988468898c5..0ac010ebc599 100644 --- a/libc/src/stdio/generic/getc.cpp +++ b/libc/src/stdio/generic/getc.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/getc_unlocked.cpp b/libc/src/stdio/generic/getc_unlocked.cpp index 92d5092623ac..eee23a18d05d 100644 --- a/libc/src/stdio/generic/getc_unlocked.cpp +++ b/libc/src/stdio/generic/getc_unlocked.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/getchar.cpp b/libc/src/stdio/generic/getchar.cpp index 371fc70eb214..87d24a2b1f09 100644 --- a/libc/src/stdio/generic/getchar.cpp +++ b/libc/src/stdio/generic/getchar.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/getchar_unlocked.cpp b/libc/src/stdio/generic/getchar_unlocked.cpp index b898f5cb2596..f321969483e3 100644 --- a/libc/src/stdio/generic/getchar_unlocked.cpp +++ b/libc/src/stdio/generic/getchar_unlocked.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/perror.cpp b/libc/src/stdio/generic/perror.cpp new file mode 100644 index 000000000000..68b4ad644caa --- /dev/null +++ b/libc/src/stdio/generic/perror.cpp @@ -0,0 +1,81 @@ +//===-- Implementation of perror ------------------------------------------===// +// +// 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 "src/stdio/perror.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/File/file.h" +#include "src/__support/StringUtil/error_to_string.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +static int write_out(cpp::string_view str_view, File *f) { + if (str_view.size() > 0) { + auto result = f->write_unlocked(str_view.data(), str_view.size()); + if (result.has_error()) + return result.error; + } + return 0; +} + +// separate function so that we can return early on error but still get the +// unlock. This function sets errno and should not be called elsewhere. +static void write_sequence(cpp::string_view str_view, + cpp::string_view err_str) { + int write_err; + // TODO: this seems like there should be some sort of queue system to + // deduplicate this code. + + // FORMAT: + // if str != nullptr and doesn't start with a null byte: + // "[str]: [strerror(errno)]\n" + // else + // "[strerror(errno)]\n" + if (str_view.size() > 0) { + write_err = write_out(str_view, LIBC_NAMESPACE::stderr); + if (write_err != 0) { + libc_errno = write_err; + return; + } + + write_err = write_out(": ", LIBC_NAMESPACE::stderr); + if (write_err != 0) { + libc_errno = write_err; + return; + } + } + + write_err = write_out(err_str, LIBC_NAMESPACE::stderr); + if (write_err != 0) { + libc_errno = write_err; + return; + } + + write_err = write_out("\n", LIBC_NAMESPACE::stderr); + if (write_err != 0) { + libc_errno = write_err; + return; + } +} + +LLVM_LIBC_FUNCTION(void, perror, (const char *str)) { + const char empty_str[1] = {'\0'}; + if (str == nullptr) + str = empty_str; + cpp::string_view str_view(str); + + cpp::string_view err_str = get_error_string(libc_errno); + + // We need to lock the stream to ensure the newline is always appended. + LIBC_NAMESPACE::stderr->lock(); + write_sequence(str_view, err_str); + LIBC_NAMESPACE::stderr->unlock(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/putc.cpp b/libc/src/stdio/generic/putc.cpp index b5f008fdce44..83bc3d4131e7 100644 --- a/libc/src/stdio/generic/putc.cpp +++ b/libc/src/stdio/generic/putc.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/putchar.cpp b/libc/src/stdio/generic/putchar.cpp index e86df23d6716..2b3509e5e414 100644 --- a/libc/src/stdio/generic/putchar.cpp +++ b/libc/src/stdio/generic/putchar.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/generic/puts.cpp b/libc/src/stdio/generic/puts.cpp index 7dbe2c79f920..4267dd546c4d 100644 --- a/libc/src/stdio/generic/puts.cpp +++ b/libc/src/stdio/generic/puts.cpp @@ -11,8 +11,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/gpu/fprintf.cpp b/libc/src/stdio/gpu/fprintf.cpp index 5b8f01d7d534..9877817d9209 100644 --- a/libc/src/stdio/gpu/fprintf.cpp +++ b/libc/src/stdio/gpu/fprintf.cpp @@ -12,7 +12,7 @@ #include "src/__support/CPP/string_view.h" #include "src/__support/arg_list.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/stdio/gpu/vfprintf_utils.h" #include diff --git a/libc/src/stdio/gpu/printf.cpp b/libc/src/stdio/gpu/printf.cpp index 53fe69d5e2eb..8a9174d7397a 100644 --- a/libc/src/stdio/gpu/printf.cpp +++ b/libc/src/stdio/gpu/printf.cpp @@ -11,7 +11,7 @@ #include "src/__support/CPP/string_view.h" #include "src/__support/arg_list.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/stdio/gpu/vfprintf_utils.h" #include diff --git a/libc/src/stdio/linux/fdopen.cpp b/libc/src/stdio/linux/fdopen.cpp index 7d72fdc88e9f..5623f06b7cff 100644 --- a/libc/src/stdio/linux/fdopen.cpp +++ b/libc/src/stdio/linux/fdopen.cpp @@ -9,8 +9,8 @@ #include "src/stdio/fdopen.h" #include "src/__support/File/linux/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/linux/remove.cpp b/libc/src/stdio/linux/remove.cpp index dbb4491d0e6c..ac755db0bc78 100644 --- a/libc/src/stdio/linux/remove.cpp +++ b/libc/src/stdio/linux/remove.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" // For AT_* macros. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/linux/rename.cpp b/libc/src/stdio/linux/rename.cpp index fbcb29be48f4..426c8698e557 100644 --- a/libc/src/stdio/linux/rename.cpp +++ b/libc/src/stdio/linux/rename.cpp @@ -10,8 +10,8 @@ #include "hdr/fcntl_macros.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/perror.h b/libc/src/stdio/perror.h new file mode 100644 index 000000000000..bf8d0af1df5d --- /dev/null +++ b/libc/src/stdio/perror.h @@ -0,0 +1,20 @@ +//===-- Implementation header of perror -------------------------*- 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_LIBC_SRC_STDIO_PERROR_H +#define LLVM_LIBC_SRC_STDIO_PERROR_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +void perror(const char *s); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_PERROR_H diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h index 89556f1a9e5f..cef9b1ae58fa 100644 --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -25,7 +25,7 @@ #include "src/__support/fixed_point/fx_rep.h" #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/setbuf.cpp b/libc/src/stdio/setbuf.cpp index f3db97de5837..fcc6df12ddb0 100644 --- a/libc/src/stdio/setbuf.cpp +++ b/libc/src/stdio/setbuf.cpp @@ -9,8 +9,8 @@ #include "src/stdio/setbuf.h" #include "hdr/stdio_macros.h" #include "src/__support/File/file.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/setvbuf.cpp b/libc/src/stdio/setvbuf.cpp index 0a6b8cacb59c..9fc6cb040233 100644 --- a/libc/src/stdio/setvbuf.cpp +++ b/libc/src/stdio/setvbuf.cpp @@ -10,8 +10,8 @@ #include "src/__support/File/file.h" #include "hdr/types/FILE.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/atof.cpp b/libc/src/stdlib/atof.cpp index 18a65c67705d..d0d8d211dea8 100644 --- a/libc/src/stdlib/atof.cpp +++ b/libc/src/stdlib/atof.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/atof.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/atoi.cpp b/libc/src/stdlib/atoi.cpp index 9e46b53b1aa0..420bbc8143d5 100644 --- a/libc/src/stdlib/atoi.cpp +++ b/libc/src/stdlib/atoi.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/atoi.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/atol.cpp b/libc/src/stdlib/atol.cpp index 7f3414a4afdd..e1110ffa449b 100644 --- a/libc/src/stdlib/atol.cpp +++ b/libc/src/stdlib/atol.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/atol.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/atoll.cpp b/libc/src/stdlib/atoll.cpp index 4f1a02ad8315..063e817f9b79 100644 --- a/libc/src/stdlib/atoll.cpp +++ b/libc/src/stdlib/atoll.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/atoll.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtod.cpp b/libc/src/stdlib/strtod.cpp index 2c6819163aa4..deb2390c7fcd 100644 --- a/libc/src/stdlib/strtod.cpp +++ b/libc/src/stdlib/strtod.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtod.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtod_l.cpp b/libc/src/stdlib/strtod_l.cpp index 247314398315..ad333b32d240 100644 --- a/libc/src/stdlib/strtod_l.cpp +++ b/libc/src/stdlib/strtod_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtod_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtof.cpp b/libc/src/stdlib/strtof.cpp index 351bf64ad4f7..fc52dc85ffc5 100644 --- a/libc/src/stdlib/strtof.cpp +++ b/libc/src/stdlib/strtof.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtof.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtof_l.cpp b/libc/src/stdlib/strtof_l.cpp index d54efa66e084..c6e03ff51fa2 100644 --- a/libc/src/stdlib/strtof_l.cpp +++ b/libc/src/stdlib/strtof_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtof_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtol.cpp b/libc/src/stdlib/strtol.cpp index 77f8712d7c13..42db36b2052b 100644 --- a/libc/src/stdlib/strtol.cpp +++ b/libc/src/stdlib/strtol.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtol.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtol_l.cpp b/libc/src/stdlib/strtol_l.cpp index f94aff1a0d7b..497a4403eff4 100644 --- a/libc/src/stdlib/strtol_l.cpp +++ b/libc/src/stdlib/strtol_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtol_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtold.cpp b/libc/src/stdlib/strtold.cpp index 88d29c9f3627..44046c2c6f61 100644 --- a/libc/src/stdlib/strtold.cpp +++ b/libc/src/stdlib/strtold.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtold.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtold_l.cpp b/libc/src/stdlib/strtold_l.cpp index d0c57f50246b..c3af30a1b9ec 100644 --- a/libc/src/stdlib/strtold_l.cpp +++ b/libc/src/stdlib/strtold_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtold_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoll.cpp b/libc/src/stdlib/strtoll.cpp index 8d1b3efdcf87..c1dca13112e0 100644 --- a/libc/src/stdlib/strtoll.cpp +++ b/libc/src/stdlib/strtoll.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoll.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp index e82971d59c48..6f30d7794c5c 100644 --- a/libc/src/stdlib/strtoll_l.cpp +++ b/libc/src/stdlib/strtoll_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoll_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoul.cpp b/libc/src/stdlib/strtoul.cpp index 1d832318c448..d26ca5e5a10a 100644 --- a/libc/src/stdlib/strtoul.cpp +++ b/libc/src/stdlib/strtoul.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoul.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoul_l.cpp b/libc/src/stdlib/strtoul_l.cpp index 74fce00a0ac3..9a875ddee902 100644 --- a/libc/src/stdlib/strtoul_l.cpp +++ b/libc/src/stdlib/strtoul_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoul_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoull.cpp b/libc/src/stdlib/strtoull.cpp index dba22611cfb0..8f929f577311 100644 --- a/libc/src/stdlib/strtoull.cpp +++ b/libc/src/stdlib/strtoull.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoull.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp index 2ea8a43a40ef..9eb056b0e59b 100644 --- a/libc/src/stdlib/strtoull_l.cpp +++ b/libc/src/stdlib/strtoull_l.cpp @@ -8,9 +8,9 @@ #include "src/stdlib/strtoull_l.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index c3b414d87285..8784bc3750cb 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -87,7 +87,6 @@ add_entrypoint_object( HDRS stpcpy.h DEPENDS - .mempcpy .string_utils ) @@ -108,7 +107,6 @@ add_entrypoint_object( HDRS strcat.h DEPENDS - .strcpy .string_utils libc.include.llvm-libc-types.size_t ) @@ -265,7 +263,6 @@ add_entrypoint_object( HDRS strncat.h DEPENDS - .strncpy .string_utils libc.include.llvm-libc-types.size_t ) diff --git a/libc/src/string/stpcpy.cpp b/libc/src/string/stpcpy.cpp index 979edd72c1f1..48c0db950ace 100644 --- a/libc/src/string/stpcpy.cpp +++ b/libc/src/string/stpcpy.cpp @@ -8,7 +8,6 @@ #include "src/string/stpcpy.h" #include "src/__support/macros/config.h" -#include "src/string/mempcpy.h" #include "src/string/string_utils.h" #include "src/__support/common.h" @@ -18,8 +17,8 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(char *, stpcpy, (char *__restrict dest, const char *__restrict src)) { size_t size = internal::string_length(src) + 1; - char *result = - reinterpret_cast(LIBC_NAMESPACE::mempcpy(dest, src, size)); + __builtin_memcpy(dest, src, size); + char *result = dest + size; if (result != nullptr) return result - 1; diff --git a/libc/src/string/strcat.cpp b/libc/src/string/strcat.cpp index 6a6f068bd475..7dce6d15a65c 100644 --- a/libc/src/string/strcat.cpp +++ b/libc/src/string/strcat.cpp @@ -9,7 +9,6 @@ #include "src/string/strcat.h" #include "src/__support/macros/config.h" #include "src/__support/macros/null_check.h" -#include "src/string/strcpy.h" #include "src/string/string_utils.h" #include "src/__support/common.h" @@ -21,9 +20,11 @@ LLVM_LIBC_FUNCTION(char *, strcat, LIBC_CRASH_ON_NULLPTR(dest); LIBC_CRASH_ON_NULLPTR(src); size_t dest_length = internal::string_length(dest); - size_t src_length = internal::string_length(src); - LIBC_NAMESPACE::strcpy(dest + dest_length, src); - dest[dest_length + src_length] = '\0'; + size_t i; + for (i = 0; src[i] != '\0'; ++i) + dest[dest_length + i] = src[i]; + + dest[dest_length + i] = '\0'; return dest; } diff --git a/libc/src/string/strdup.cpp b/libc/src/string/strdup.cpp index 4cf4173a27bf..dab0ab4288c9 100644 --- a/libc/src/string/strdup.cpp +++ b/libc/src/string/strdup.cpp @@ -8,8 +8,8 @@ #include "src/string/strdup.h" #include "hdr/stdlib_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/string/allocating_string_utils.h" #include "src/string/memory_utils/inline_memcpy.h" diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h index dcbfc7584a30..4f56263fce8e 100644 --- a/libc/src/string/string_utils.h +++ b/libc/src/string/string_utils.h @@ -90,12 +90,11 @@ template LIBC_INLINE size_t string_length(const T *src) { // string a block at a time. if constexpr (cpp::is_same_v) return string_length_wide_read(src); -#else +#endif size_t length; for (length = 0; *src; ++src, ++length) ; return length; -#endif } template diff --git a/libc/src/string/strncat.cpp b/libc/src/string/strncat.cpp index 4926b7d244d1..6d8bb6960748 100644 --- a/libc/src/string/strncat.cpp +++ b/libc/src/string/strncat.cpp @@ -10,7 +10,6 @@ #include "src/__support/macros/config.h" #include "src/__support/macros/null_check.h" #include "src/string/string_utils.h" -#include "src/string/strncpy.h" #include "src/__support/common.h" @@ -23,11 +22,12 @@ LLVM_LIBC_FUNCTION(char *, strncat, LIBC_CRASH_ON_NULLPTR(dest); LIBC_CRASH_ON_NULLPTR(src); } - size_t src_length = internal::string_length(src); - size_t copy_amount = src_length > count ? count : src_length; size_t dest_length = internal::string_length(dest); - LIBC_NAMESPACE::strncpy(dest + dest_length, src, copy_amount); - dest[dest_length + copy_amount] = '\0'; + size_t i; + for (i = 0; i < count && src[i] != '\0'; ++i) + dest[dest_length + i] = src[i]; + + dest[dest_length + i] = '\0'; return dest; } diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt index 9a73b80d35d2..0fa11e9eee69 100644 --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -13,3 +13,4 @@ add_subdirectory(utsname) add_subdirectory(wait) add_subdirectory(prctl) add_subdirectory(uio) +add_subdirectory(ioctl) diff --git a/libc/src/sys/auxv/linux/getauxval.cpp b/libc/src/sys/auxv/linux/getauxval.cpp index 236fd25698f6..b50c5845bcc2 100644 --- a/libc/src/sys/auxv/linux/getauxval.cpp +++ b/libc/src/sys/auxv/linux/getauxval.cpp @@ -8,23 +8,29 @@ #include "src/sys/auxv/getauxval.h" #include "config/app.h" +#include "hdr/fcntl_macros.h" +#include "src/__support/OSUtil/fcntl.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // for guarded initialization #include "src/__support/threads/callonce.h" #include "src/__support/threads/linux/futex_word.h" +// ----------------------------------------------------------------------------- +// TODO: This file should not include other public libc functions. Calling other +// public libc functions is an antipattern within LLVM-libc. This needs to be +// cleaned up. DO NOT COPY THIS. +// ----------------------------------------------------------------------------- + // for mallocing the global auxv #include "src/sys/mman/mmap.h" #include "src/sys/mman/munmap.h" // for reading /proc/self/auxv -#include "src/fcntl/open.h" #include "src/sys/prctl/prctl.h" -#include "src/unistd/close.h" #include "src/unistd/read.h" // getauxval will work either with or without __cxa_atexit support. @@ -60,17 +66,18 @@ public: constexpr static size_t AUXV_MMAP_SIZE = sizeof(AuxEntry) * MAX_AUXV_ENTRIES; AuxvMMapGuard() - : ptr(mmap(nullptr, AUXV_MMAP_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) {} + : ptr(LIBC_NAMESPACE::mmap(nullptr, AUXV_MMAP_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) {} ~AuxvMMapGuard() { if (ptr != MAP_FAILED) - munmap(ptr, AUXV_MMAP_SIZE); + LIBC_NAMESPACE::munmap(ptr, AUXV_MMAP_SIZE); } void submit_to_global() { // atexit may fail, we do not set it to global in that case. int ret = __cxa_atexit( [](void *) { - munmap(auxv, AUXV_MMAP_SIZE); + LIBC_NAMESPACE::munmap(auxv, AUXV_MMAP_SIZE); auxv = nullptr; }, nullptr, nullptr); @@ -90,10 +97,16 @@ private: class AuxvFdGuard { public: - AuxvFdGuard() : fd(open("/proc/self/auxv", O_RDONLY | O_CLOEXEC)) {} + AuxvFdGuard() { + auto result = internal::open("/proc/self/auxv", O_RDONLY | O_CLOEXEC); + if (!result.has_value()) + fd = -1; + + fd = result.value(); + } ~AuxvFdGuard() { if (fd != -1) - close(fd); + internal::close(fd); } bool valid() const { return fd != -1; } int get() const { return fd; } @@ -135,7 +148,8 @@ static void initialize_auxv_once(void) { bool error_detected = false; // Read until we use up all the available space or we finish reading the file. while (available_size != 0) { - ssize_t bytes_read = read(fd_guard.get(), buf, available_size); + ssize_t bytes_read = + LIBC_NAMESPACE::read(fd_guard.get(), buf, available_size); if (bytes_read <= 0) { if (libc_errno == EINTR) continue; @@ -158,7 +172,7 @@ static AuxEntry read_entry(int fd) { size_t size = sizeof(AuxEntry); char *ptr = reinterpret_cast(&buf); while (size > 0) { - ssize_t ret = read(fd, ptr, size); + ssize_t ret = LIBC_NAMESPACE::read(fd, ptr, size); if (ret < 0) { if (libc_errno == EINTR) continue; @@ -195,7 +209,8 @@ LLVM_LIBC_FUNCTION(unsigned long, getauxval, (unsigned long id)) { return search_auxv(app.auxv_ptr, id); static FutexWordType once_flag; - callonce(reinterpret_cast(&once_flag), initialize_auxv_once); + LIBC_NAMESPACE::callonce(reinterpret_cast(&once_flag), + initialize_auxv_once); if (auxv != nullptr) return search_auxv(auxv, id); diff --git a/libc/src/sys/epoll/linux/epoll_create.cpp b/libc/src/sys/epoll/linux/epoll_create.cpp index 7196ac7410c3..2e44e883ddf0 100644 --- a/libc/src/sys/epoll/linux/epoll_create.cpp +++ b/libc/src/sys/epoll/linux/epoll_create.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/epoll/linux/epoll_create1.cpp b/libc/src/sys/epoll/linux/epoll_create1.cpp index efff282e2714..3c60090fb7b4 100644 --- a/libc/src/sys/epoll/linux/epoll_create1.cpp +++ b/libc/src/sys/epoll/linux/epoll_create1.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/epoll/linux/epoll_ctl.cpp b/libc/src/sys/epoll/linux/epoll_ctl.cpp index 5f7dbb77b1e5..079bd60403b0 100644 --- a/libc/src/sys/epoll/linux/epoll_ctl.cpp +++ b/libc/src/sys/epoll/linux/epoll_ctl.cpp @@ -11,8 +11,8 @@ #include "hdr/types/struct_epoll_event.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/epoll/linux/epoll_pwait.cpp b/libc/src/sys/epoll/linux/epoll_pwait.cpp index d7836549928c..24fd1dbdc467 100644 --- a/libc/src/sys/epoll/linux/epoll_pwait.cpp +++ b/libc/src/sys/epoll/linux/epoll_pwait.cpp @@ -13,9 +13,9 @@ #include "hdr/types/struct_epoll_event.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sys/epoll/linux/epoll_pwait2.cpp b/libc/src/sys/epoll/linux/epoll_pwait2.cpp index 14b419399fe9..219984528efd 100644 --- a/libc/src/sys/epoll/linux/epoll_pwait2.cpp +++ b/libc/src/sys/epoll/linux/epoll_pwait2.cpp @@ -14,9 +14,9 @@ #include "hdr/types/struct_timespec.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sys/epoll/linux/epoll_wait.cpp b/libc/src/sys/epoll/linux/epoll_wait.cpp index 1a63be5e260f..7fae7b55992f 100644 --- a/libc/src/sys/epoll/linux/epoll_wait.cpp +++ b/libc/src/sys/epoll/linux/epoll_wait.cpp @@ -13,9 +13,9 @@ #include "hdr/types/struct_epoll_event.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/sys/ioctl/CMakeLists.txt b/libc/src/sys/ioctl/CMakeLists.txt new file mode 100644 index 000000000000..099a1b96389f --- /dev/null +++ b/libc/src/sys/ioctl/CMakeLists.txt @@ -0,0 +1,10 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif() + +add_entrypoint_object( + ioctl + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.ioctl +) diff --git a/libc/src/sys/ioctl/ioctl.h b/libc/src/sys/ioctl/ioctl.h new file mode 100644 index 000000000000..62323ba7dd4d --- /dev/null +++ b/libc/src/sys/ioctl/ioctl.h @@ -0,0 +1,20 @@ +//===-- Implementation header for ioctl ---------------------------*-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_LIBC_SRC_SYS_IOCTL_IOCTL_H +#define LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int ioctl(int fd, unsigned long request, ...); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H diff --git a/libc/src/sys/ioctl/linux/CMakeLists.txt b/libc/src/sys/ioctl/linux/CMakeLists.txt new file mode 100644 index 000000000000..876f35aaee66 --- /dev/null +++ b/libc/src/sys/ioctl/linux/CMakeLists.txt @@ -0,0 +1,12 @@ +add_entrypoint_object( + ioctl + SRCS + ioctl.cpp + HDRS + ../ioctl.h + DEPENDS + libc.include.sys_ioctl + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/sys/ioctl/linux/ioctl.cpp b/libc/src/sys/ioctl/linux/ioctl.cpp new file mode 100644 index 000000000000..9bb669c6a6f6 --- /dev/null +++ b/libc/src/sys/ioctl/linux/ioctl.cpp @@ -0,0 +1,36 @@ +//===---------- Linux implementation of the ioctl function ----------------===// +// +// 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 "src/sys/ioctl/ioctl.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, ioctl, (int fd, unsigned long request, ...)) { + va_list vargs; + va_start(vargs, request); + void *data_pointer = va_arg(vargs, void *); + int ret = + LIBC_NAMESPACE::syscall_impl(SYS_ioctl, fd, request, data_pointer); + va_end(vargs); + + // Some ioctls can be expected to return positive values + if (ret >= 0) + return ret; + + // If there is an error, errno is set and -1 is returned. + libc_errno = -ret; + return -1; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/madvise.cpp b/libc/src/sys/mman/linux/madvise.cpp index 332d6c2db4ac..1bb284f62b89 100644 --- a/libc/src/sys/mman/linux/madvise.cpp +++ b/libc/src/sys/mman/linux/madvise.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mincore.cpp b/libc/src/sys/mman/linux/mincore.cpp index b5436fda3853..d583f1ef85f3 100644 --- a/libc/src/sys/mman/linux/mincore.cpp +++ b/libc/src/sys/mman/linux/mincore.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mlock.cpp b/libc/src/sys/mman/linux/mlock.cpp index be7eb28e29c4..8582eb7c0063 100644 --- a/libc/src/sys/mman/linux/mlock.cpp +++ b/libc/src/sys/mman/linux/mlock.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mlock2.cpp b/libc/src/sys/mman/linux/mlock2.cpp index 7bc557f9bf58..955cfe128de7 100644 --- a/libc/src/sys/mman/linux/mlock2.cpp +++ b/libc/src/sys/mman/linux/mlock2.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mlockall.cpp b/libc/src/sys/mman/linux/mlockall.cpp index eae3a9ea0a18..c3502fbb3af3 100644 --- a/libc/src/sys/mman/linux/mlockall.cpp +++ b/libc/src/sys/mman/linux/mlockall.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mmap.cpp b/libc/src/sys/mman/linux/mmap.cpp index ee9a0a32e8f5..33f9fe8ff370 100644 --- a/libc/src/sys/mman/linux/mmap.cpp +++ b/libc/src/sys/mman/linux/mmap.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For EXEC_PAGESIZE. #include // For syscall numbers. diff --git a/libc/src/sys/mman/linux/mprotect.cpp b/libc/src/sys/mman/linux/mprotect.cpp index e2351028e2c7..6b14915b60c9 100644 --- a/libc/src/sys/mman/linux/mprotect.cpp +++ b/libc/src/sys/mman/linux/mprotect.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/mremap.cpp b/libc/src/sys/mman/linux/mremap.cpp index 38bcfce833d3..6cdda9435bb6 100644 --- a/libc/src/sys/mman/linux/mremap.cpp +++ b/libc/src/sys/mman/linux/mremap.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For EXEC_PAGESIZE. #include #include // For syscall numbers. diff --git a/libc/src/sys/mman/linux/msync.cpp b/libc/src/sys/mman/linux/msync.cpp index e2b4f81d616a..650678bcb36e 100644 --- a/libc/src/sys/mman/linux/msync.cpp +++ b/libc/src/sys/mman/linux/msync.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/munlock.cpp b/libc/src/sys/mman/linux/munlock.cpp index 93c25f844c6e..9638949f5fcb 100644 --- a/libc/src/sys/mman/linux/munlock.cpp +++ b/libc/src/sys/mman/linux/munlock.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/munlockall.cpp b/libc/src/sys/mman/linux/munlockall.cpp index f5911cb01bc2..f47eaece178e 100644 --- a/libc/src/sys/mman/linux/munlockall.cpp +++ b/libc/src/sys/mman/linux/munlockall.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/munmap.cpp b/libc/src/sys/mman/linux/munmap.cpp index 9c01b15ac8dc..61b1f1549dd1 100644 --- a/libc/src/sys/mman/linux/munmap.cpp +++ b/libc/src/sys/mman/linux/munmap.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" -#include // For syscall numbers. +#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/remap_file_pages.cpp b/libc/src/sys/mman/linux/remap_file_pages.cpp index f616e1915ecc..58ae4017f628 100644 --- a/libc/src/sys/mman/linux/remap_file_pages.cpp +++ b/libc/src/sys/mman/linux/remap_file_pages.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/mman/linux/shm_common.h b/libc/src/sys/mman/linux/shm_common.h index ce75c2b5b699..29d1401821e4 100644 --- a/libc/src/sys/mman/linux/shm_common.h +++ b/libc/src/sys/mman/linux/shm_common.h @@ -9,10 +9,15 @@ #include "src/__support/CPP/array.h" #include "src/__support/CPP/optional.h" #include "src/__support/CPP/string_view.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/string/memory_utils/inline_memcpy.h" +// TODO: clean this up. +// 1. Change from optional to ErrorOr, and return the errno instead of setting +// it here. +// 2. Replace inline memcpy with __builtin_memcpy + // TODO: Get PATH_MAX via https://github.com/llvm/llvm-project/issues/85121 #include diff --git a/libc/src/sys/mman/linux/shm_open.cpp b/libc/src/sys/mman/linux/shm_open.cpp index 11de482272d0..3099062eace9 100644 --- a/libc/src/sys/mman/linux/shm_open.cpp +++ b/libc/src/sys/mman/linux/shm_open.cpp @@ -7,9 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/sys/mman/shm_open.h" +#include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" +#include "src/__support/OSUtil/fcntl.h" #include "src/__support/macros/config.h" -#include "src/fcntl/open.h" #include "src/sys/mman/linux/shm_common.h" namespace LIBC_NAMESPACE_DECL { @@ -17,9 +18,16 @@ namespace LIBC_NAMESPACE_DECL { static constexpr int DEFAULT_OFLAGS = O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK; LLVM_LIBC_FUNCTION(int, shm_open, (const char *name, int oflags, mode_t mode)) { - using namespace shm_common; - if (cpp::optional buffer = translate_name(name)) - return open(buffer->data(), oflags | DEFAULT_OFLAGS, mode); + if (cpp::optional buffer = + shm_common::translate_name(name)) { + auto result = internal::open(buffer->data(), oflags | DEFAULT_OFLAGS, mode); + + if (!result.has_value()) { + libc_errno = result.error(); + return -1; + } + return result.value(); + } return -1; } diff --git a/libc/src/sys/mman/linux/shm_unlink.cpp b/libc/src/sys/mman/linux/shm_unlink.cpp index 6a7630151220..4c61c7cd16ba 100644 --- a/libc/src/sys/mman/linux/shm_unlink.cpp +++ b/libc/src/sys/mman/linux/shm_unlink.cpp @@ -13,10 +13,13 @@ namespace LIBC_NAMESPACE_DECL { +// TODO: stop calling the public unlink function. It should be calling an +// internal shared utility. + LLVM_LIBC_FUNCTION(int, shm_unlink, (const char *name)) { - using namespace shm_common; - if (cpp::optional buffer = translate_name(name)) - return unlink(buffer->data()); + if (cpp::optional buffer = + shm_common::translate_name(name)) + return LIBC_NAMESPACE::unlink(buffer->data()); return -1; } diff --git a/libc/src/sys/prctl/linux/prctl.cpp b/libc/src/sys/prctl/linux/prctl.cpp index 5d4e9046b877..c726b0a53959 100644 --- a/libc/src/sys/prctl/linux/prctl.cpp +++ b/libc/src/sys/prctl/linux/prctl.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/random/linux/getrandom.cpp b/libc/src/sys/random/linux/getrandom.cpp index 9a8869a2d6d3..4a95bddfa428 100644 --- a/libc/src/sys/random/linux/getrandom.cpp +++ b/libc/src/sys/random/linux/getrandom.cpp @@ -8,24 +8,23 @@ #include "src/sys/random/getrandom.h" +#include "src/__support/OSUtil/linux/getrandom.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" - +#include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" -#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(ssize_t, getrandom, (void *buf, size_t buflen, unsigned int flags)) { - ssize_t ret = - LIBC_NAMESPACE::syscall_impl(SYS_getrandom, buf, buflen, flags); - if (ret < 0) { - libc_errno = static_cast(-ret); + auto rand = internal::getrandom(buf, buflen, flags); + if (!rand.has_value()) { + libc_errno = static_cast(rand.error()); return -1; } - return ret; + return rand.value(); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/resource/linux/getrlimit.cpp b/libc/src/sys/resource/linux/getrlimit.cpp index 30c2e91b036d..d27213419494 100644 --- a/libc/src/sys/resource/linux/getrlimit.cpp +++ b/libc/src/sys/resource/linux/getrlimit.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For struct rlimit #include // For syscall numbers. diff --git a/libc/src/sys/resource/linux/setrlimit.cpp b/libc/src/sys/resource/linux/setrlimit.cpp index 85f07900aaef..300bad75baa6 100644 --- a/libc/src/sys/resource/linux/setrlimit.cpp +++ b/libc/src/sys/resource/linux/setrlimit.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For struct rlimit #include // For syscall numbers. diff --git a/libc/src/sys/select/linux/select.cpp b/libc/src/sys/select/linux/select.cpp index 9ccb1e95f275..6c434eb58459 100644 --- a/libc/src/sys/select/linux/select.cpp +++ b/libc/src/sys/select/linux/select.cpp @@ -13,8 +13,8 @@ #include "src/__support/CPP/limits.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For size_t #include // For syscall numbers. diff --git a/libc/src/sys/sendfile/linux/sendfile.cpp b/libc/src/sys/sendfile/linux/sendfile.cpp index 9d4174cb8c91..ec892323def5 100644 --- a/libc/src/sys/sendfile/linux/sendfile.cpp +++ b/libc/src/sys/sendfile/linux/sendfile.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/socket/linux/bind.cpp b/libc/src/sys/socket/linux/bind.cpp index 72a3307a91dd..83a3d06f5380 100644 --- a/libc/src/sys/socket/linux/bind.cpp +++ b/libc/src/sys/socket/linux/bind.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For SYS_SOCKET socketcall number. #include // For syscall numbers. diff --git a/libc/src/sys/socket/linux/recv.cpp b/libc/src/sys/socket/linux/recv.cpp index 5e9f2d3233fc..baf4de1b5eb5 100644 --- a/libc/src/sys/socket/linux/recv.cpp +++ b/libc/src/sys/socket/linux/recv.cpp @@ -16,8 +16,8 @@ #include "hdr/types/struct_sockaddr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/recvfrom.cpp b/libc/src/sys/socket/linux/recvfrom.cpp index 574e65f64a54..3d8397b478cc 100644 --- a/libc/src/sys/socket/linux/recvfrom.cpp +++ b/libc/src/sys/socket/linux/recvfrom.cpp @@ -16,8 +16,8 @@ #include "hdr/types/struct_sockaddr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/recvmsg.cpp b/libc/src/sys/socket/linux/recvmsg.cpp index e42b6346f330..bc6d072dbf9a 100644 --- a/libc/src/sys/socket/linux/recvmsg.cpp +++ b/libc/src/sys/socket/linux/recvmsg.cpp @@ -15,8 +15,8 @@ #include "hdr/types/struct_msghdr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/send.cpp b/libc/src/sys/socket/linux/send.cpp index cb3b4d5a9ece..43b01e7e6e0f 100644 --- a/libc/src/sys/socket/linux/send.cpp +++ b/libc/src/sys/socket/linux/send.cpp @@ -16,7 +16,7 @@ #include "hdr/types/struct_sockaddr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/sendmsg.cpp b/libc/src/sys/socket/linux/sendmsg.cpp index b4d9c9deda02..b04783ebfe7e 100644 --- a/libc/src/sys/socket/linux/sendmsg.cpp +++ b/libc/src/sys/socket/linux/sendmsg.cpp @@ -15,7 +15,7 @@ #include "hdr/types/struct_msghdr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/sendto.cpp b/libc/src/sys/socket/linux/sendto.cpp index 2fada192b086..9dda127f872d 100644 --- a/libc/src/sys/socket/linux/sendto.cpp +++ b/libc/src/sys/socket/linux/sendto.cpp @@ -16,7 +16,7 @@ #include "hdr/types/struct_sockaddr.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/socket/linux/socket.cpp b/libc/src/sys/socket/linux/socket.cpp index 3e6df4d487a5..69eb6cfa01ce 100644 --- a/libc/src/sys/socket/linux/socket.cpp +++ b/libc/src/sys/socket/linux/socket.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For SYS_SOCKET socketcall number. #include // For syscall numbers. diff --git a/libc/src/sys/socket/linux/socketpair.cpp b/libc/src/sys/socket/linux/socketpair.cpp index 60612ac04d61..7ea8ca46cee5 100644 --- a/libc/src/sys/socket/linux/socketpair.cpp +++ b/libc/src/sys/socket/linux/socketpair.cpp @@ -10,9 +10,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" -#include "src/errno/libc_errno.h" #include // For SYS_SOCKET socketcall number. #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/chmod.cpp b/libc/src/sys/stat/linux/chmod.cpp index 1b787e47e7c6..2bd0788ec1df 100644 --- a/libc/src/sys/stat/linux/chmod.cpp +++ b/libc/src/sys/stat/linux/chmod.cpp @@ -13,8 +13,8 @@ #include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/fchmod.cpp b/libc/src/sys/stat/linux/fchmod.cpp index 0d6fd359169a..3dadfdd1d943 100644 --- a/libc/src/sys/stat/linux/fchmod.cpp +++ b/libc/src/sys/stat/linux/fchmod.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/types/mode_t.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/fchmodat.cpp b/libc/src/sys/stat/linux/fchmodat.cpp index e76db4d160fb..add2192a558a 100644 --- a/libc/src/sys/stat/linux/fchmodat.cpp +++ b/libc/src/sys/stat/linux/fchmodat.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/fstat.cpp b/libc/src/sys/stat/linux/fstat.cpp index 35cf8f08f782..dea002c5e12a 100644 --- a/libc/src/sys/stat/linux/fstat.cpp +++ b/libc/src/sys/stat/linux/fstat.cpp @@ -8,8 +8,8 @@ #include "src/sys/stat/fstat.h" #include "kernel_statx.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/__support/common.h" diff --git a/libc/src/sys/stat/linux/lstat.cpp b/libc/src/sys/stat/linux/lstat.cpp index 354c5b6e029a..5601dd5d78a9 100644 --- a/libc/src/sys/stat/linux/lstat.cpp +++ b/libc/src/sys/stat/linux/lstat.cpp @@ -8,8 +8,8 @@ #include "src/sys/stat/lstat.h" #include "kernel_statx.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" diff --git a/libc/src/sys/stat/linux/mkdir.cpp b/libc/src/sys/stat/linux/mkdir.cpp index b319b5c8393d..0829ff4f9432 100644 --- a/libc/src/sys/stat/linux/mkdir.cpp +++ b/libc/src/sys/stat/linux/mkdir.cpp @@ -13,8 +13,8 @@ #include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/mkdirat.cpp b/libc/src/sys/stat/linux/mkdirat.cpp index 097fc158010d..8f4194dc3275 100644 --- a/libc/src/sys/stat/linux/mkdirat.cpp +++ b/libc/src/sys/stat/linux/mkdirat.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/stat.cpp b/libc/src/sys/stat/linux/stat.cpp index de9cdb197d68..5553eaf00be2 100644 --- a/libc/src/sys/stat/linux/stat.cpp +++ b/libc/src/sys/stat/linux/stat.cpp @@ -8,8 +8,8 @@ #include "src/sys/stat/stat.h" #include "kernel_statx.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/__support/common.h" diff --git a/libc/src/sys/statvfs/linux/statfs_utils.h b/libc/src/sys/statvfs/linux/statfs_utils.h index 1e5be5153101..8ee4de288ef6 100644 --- a/libc/src/sys/statvfs/linux/statfs_utils.h +++ b/libc/src/sys/statvfs/linux/statfs_utils.h @@ -12,9 +12,9 @@ #include "include/llvm-libc-types/struct_statvfs.h" #include "src/__support/CPP/optional.h" #include "src/__support/OSUtil/syscall.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/time/linux/getitimer.cpp b/libc/src/sys/time/linux/getitimer.cpp index fec06aa4086e..b87406679694 100644 --- a/libc/src/sys/time/linux/getitimer.cpp +++ b/libc/src/sys/time/linux/getitimer.cpp @@ -10,7 +10,7 @@ #include "hdr/types/struct_itimerval.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/time/linux/setitimer.cpp b/libc/src/sys/time/linux/setitimer.cpp index def04a474011..1de0d4329776 100644 --- a/libc/src/sys/time/linux/setitimer.cpp +++ b/libc/src/sys/time/linux/setitimer.cpp @@ -9,7 +9,7 @@ #include "hdr/types/struct_itimerval.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/time/linux/utimes.cpp b/libc/src/sys/time/linux/utimes.cpp index 76b69937a5f4..ed37b42aedf6 100644 --- a/libc/src/sys/time/linux/utimes.cpp +++ b/libc/src/sys/time/linux/utimes.cpp @@ -15,7 +15,7 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include diff --git a/libc/src/sys/uio/linux/readv.cpp b/libc/src/sys/uio/linux/readv.cpp index f1393a9749be..c9d8d87ddc72 100644 --- a/libc/src/sys/uio/linux/readv.cpp +++ b/libc/src/sys/uio/linux/readv.cpp @@ -10,7 +10,7 @@ #include "hdr/types/struct_iovec.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/uio/linux/writev.cpp b/libc/src/sys/uio/linux/writev.cpp index 8992bed95c98..b0b9e1520792 100644 --- a/libc/src/sys/uio/linux/writev.cpp +++ b/libc/src/sys/uio/linux/writev.cpp @@ -10,7 +10,7 @@ #include "hdr/types/struct_iovec.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/utsname/linux/uname.cpp b/libc/src/sys/utsname/linux/uname.cpp index 7bb227e801e3..b47ba964faf0 100644 --- a/libc/src/sys/utsname/linux/uname.cpp +++ b/libc/src/sys/utsname/linux/uname.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. #include diff --git a/libc/src/sys/wait/wait4Impl.h b/libc/src/sys/wait/wait4Impl.h index f2bdeb02f866..77ed3ad22f14 100644 --- a/libc/src/sys/wait/wait4Impl.h +++ b/libc/src/sys/wait/wait4Impl.h @@ -12,8 +12,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" #include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include #include // For syscall numbers. diff --git a/libc/src/termios/linux/cfsetispeed.cpp b/libc/src/termios/linux/cfsetispeed.cpp index 9656b714a8ed..47b19974d21b 100644 --- a/libc/src/termios/linux/cfsetispeed.cpp +++ b/libc/src/termios/linux/cfsetispeed.cpp @@ -9,8 +9,8 @@ #include "src/termios/cfsetispeed.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include diff --git a/libc/src/termios/linux/cfsetospeed.cpp b/libc/src/termios/linux/cfsetospeed.cpp index 6130d266dbff..d2f138257a47 100644 --- a/libc/src/termios/linux/cfsetospeed.cpp +++ b/libc/src/termios/linux/cfsetospeed.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/termios/cfsetospeed.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/__support/common.h" diff --git a/libc/src/termios/linux/tcdrain.cpp b/libc/src/termios/linux/tcdrain.cpp index 116e3f0e0cbc..570b15c24fe7 100644 --- a/libc/src/termios/linux/tcdrain.cpp +++ b/libc/src/termios/linux/tcdrain.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcflow.cpp b/libc/src/termios/linux/tcflow.cpp index d229230b5d13..714ef6aa7129 100644 --- a/libc/src/termios/linux/tcflow.cpp +++ b/libc/src/termios/linux/tcflow.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcflush.cpp b/libc/src/termios/linux/tcflush.cpp index 028a5414b196..4c7b9fadc446 100644 --- a/libc/src/termios/linux/tcflush.cpp +++ b/libc/src/termios/linux/tcflush.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcgetattr.cpp b/libc/src/termios/linux/tcgetattr.cpp index 63c096ff88eb..2e768269c874 100644 --- a/libc/src/termios/linux/tcgetattr.cpp +++ b/libc/src/termios/linux/tcgetattr.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcgetsid.cpp b/libc/src/termios/linux/tcgetsid.cpp index c283d0e4fda9..7487816cf274 100644 --- a/libc/src/termios/linux/tcgetsid.cpp +++ b/libc/src/termios/linux/tcgetsid.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcsendbreak.cpp b/libc/src/termios/linux/tcsendbreak.cpp index 30bc91cf3de0..1d546c1d5953 100644 --- a/libc/src/termios/linux/tcsendbreak.cpp +++ b/libc/src/termios/linux/tcsendbreak.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/termios/linux/tcsetattr.cpp b/libc/src/termios/linux/tcsetattr.cpp index 8aa1e5c57b34..8a2c7290217b 100644 --- a/libc/src/termios/linux/tcsetattr.cpp +++ b/libc/src/termios/linux/tcsetattr.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // Safe to include without the risk of name pollution. #include // For syscall numbers diff --git a/libc/src/threads/thrd_create.cpp b/libc/src/threads/thrd_create.cpp index 4680944c2eee..67e22e72fd0e 100644 --- a/libc/src/threads/thrd_create.cpp +++ b/libc/src/threads/thrd_create.cpp @@ -8,9 +8,9 @@ #include "src/threads/thrd_create.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" #include // For thrd_* type definitions. diff --git a/libc/src/time/linux/clock.cpp b/libc/src/time/linux/clock.cpp index ee4fa82b4f89..c38697cd0668 100644 --- a/libc/src/time/linux/clock.cpp +++ b/libc/src/time/linux/clock.cpp @@ -10,10 +10,10 @@ #include "hdr/time_macros.h" #include "src/__support/CPP/limits.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/time/clock_gettime.h" #include "src/__support/time/units.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/time/linux/clock_gettime.cpp b/libc/src/time/linux/clock_gettime.cpp index 743c644d65d0..b3fcd2b22f9d 100644 --- a/libc/src/time/linux/clock_gettime.cpp +++ b/libc/src/time/linux/clock_gettime.cpp @@ -8,9 +8,9 @@ #include "src/time/clock_gettime.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/time/clock_gettime.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/time/linux/gettimeofday.cpp b/libc/src/time/linux/gettimeofday.cpp index e8ddf482fc98..237b05903c70 100644 --- a/libc/src/time/linux/gettimeofday.cpp +++ b/libc/src/time/linux/gettimeofday.cpp @@ -10,10 +10,10 @@ #include "hdr/time_macros.h" #include "hdr/types/suseconds_t.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/time/clock_gettime.h" #include "src/__support/time/units.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/time/linux/nanosleep.cpp b/libc/src/time/linux/nanosleep.cpp index 7a856376ffb2..6b9704126a0a 100644 --- a/libc/src/time/linux/nanosleep.cpp +++ b/libc/src/time/linux/nanosleep.cpp @@ -10,8 +10,8 @@ #include "hdr/time_macros.h" #include "src/__support/OSUtil/syscall.h" // For syscall functions. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For int64_t. #include // For syscall numbers. diff --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp index cf5174523aa4..a4d437233273 100644 --- a/libc/src/time/linux/timespec_get.cpp +++ b/libc/src/time/linux/timespec_get.cpp @@ -9,9 +9,9 @@ #include "src/time/timespec_get.h" #include "hdr/time_macros.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/time/clock_gettime.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/time/time.cpp b/libc/src/time/time.cpp index 860909af7488..2a81f0182c31 100644 --- a/libc/src/time/time.cpp +++ b/libc/src/time/time.cpp @@ -10,9 +10,9 @@ #include "hdr/time_macros.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/time/clock_gettime.h" -#include "src/errno/libc_errno.h" namespace LIBC_NAMESPACE_DECL { // avoid inconsitent clang-format behavior diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h index bbbb1c08a475..0541c24ece82 100644 --- a/libc/src/time/time_utils.h +++ b/libc/src/time/time_utils.h @@ -15,8 +15,8 @@ #include "src/__support/CPP/optional.h" #include "src/__support/CPP/string_view.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "time_constants.h" #include diff --git a/libc/src/time/windows/clock_getres.cpp b/libc/src/time/windows/clock_getres.cpp index b8c0c82aa641..969bb66be2d2 100644 --- a/libc/src/time/windows/clock_getres.cpp +++ b/libc/src/time/windows/clock_getres.cpp @@ -13,10 +13,10 @@ #include "src/__support/CPP/limits.h" #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/optimization.h" #include "src/__support/time/units.h" #include "src/__support/time/windows/performance_counter.h" -#include "src/errno/libc_errno.h" #include "src/time/clock_getres.h" #define WIN32_LEAN_AND_MEAN diff --git a/libc/src/unistd/linux/access.cpp b/libc/src/unistd/linux/access.cpp index 2f7ebbcdf9e8..55cd6adca779 100644 --- a/libc/src/unistd/linux/access.cpp +++ b/libc/src/unistd/linux/access.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/chdir.cpp b/libc/src/unistd/linux/chdir.cpp index a30d1dc883be..04ba509b49a5 100644 --- a/libc/src/unistd/linux/chdir.cpp +++ b/libc/src/unistd/linux/chdir.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/close.cpp b/libc/src/unistd/linux/close.cpp index 58d42a9673fb..6ef3a3c6d63f 100644 --- a/libc/src/unistd/linux/close.cpp +++ b/libc/src/unistd/linux/close.cpp @@ -8,22 +8,22 @@ #include "src/unistd/close.h" -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/OSUtil/fcntl.h" #include "src/__support/common.h" - +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, close, (int fd)) { - int ret = LIBC_NAMESPACE::syscall_impl(SYS_close, fd); - if (ret < 0) { - libc_errno = -ret; + auto result = internal::close(fd); + + if (!result.has_value()) { + libc_errno = result.error(); return -1; } - return ret; + return result.value(); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/unistd/linux/dup.cpp b/libc/src/unistd/linux/dup.cpp index c1710a37f611..81d30c6cdbc4 100644 --- a/libc/src/unistd/linux/dup.cpp +++ b/libc/src/unistd/linux/dup.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/dup2.cpp b/libc/src/unistd/linux/dup2.cpp index 7ffc151a053c..0a0e86573b34 100644 --- a/libc/src/unistd/linux/dup2.cpp +++ b/libc/src/unistd/linux/dup2.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/dup3.cpp b/libc/src/unistd/linux/dup3.cpp index c096ba73c96b..770fb73515b2 100644 --- a/libc/src/unistd/linux/dup3.cpp +++ b/libc/src/unistd/linux/dup3.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/execv.cpp b/libc/src/unistd/linux/execv.cpp index a3f2525ed7ca..d4f2bd9a5165 100644 --- a/libc/src/unistd/linux/execv.cpp +++ b/libc/src/unistd/linux/execv.cpp @@ -13,7 +13,7 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/execve.cpp b/libc/src/unistd/linux/execve.cpp index 37162c412178..2214b6df493b 100644 --- a/libc/src/unistd/linux/execve.cpp +++ b/libc/src/unistd/linux/execve.cpp @@ -13,7 +13,7 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/fchdir.cpp b/libc/src/unistd/linux/fchdir.cpp index 8196dc63ab1e..f7a7422363e6 100644 --- a/libc/src/unistd/linux/fchdir.cpp +++ b/libc/src/unistd/linux/fchdir.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/fork.cpp b/libc/src/unistd/linux/fork.cpp index 8aa0477a15d5..75a76fdea50b 100644 --- a/libc/src/unistd/linux/fork.cpp +++ b/libc/src/unistd/linux/fork.cpp @@ -15,7 +15,7 @@ #include "src/__support/threads/identifier.h" #include "src/__support/threads/thread.h" // For thread self object -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include // For SIGCHLD #include // For syscall numbers. diff --git a/libc/src/unistd/linux/fsync.cpp b/libc/src/unistd/linux/fsync.cpp index ae3895bab15f..fe08aed61e25 100644 --- a/libc/src/unistd/linux/fsync.cpp +++ b/libc/src/unistd/linux/fsync.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/ftruncate.cpp b/libc/src/unistd/linux/ftruncate.cpp index ccbb0634664a..f6aa6f8b48cc 100644 --- a/libc/src/unistd/linux/ftruncate.cpp +++ b/libc/src/unistd/linux/ftruncate.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/unistd_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For uint64_t. #include // For syscall numbers. diff --git a/libc/src/unistd/linux/getcwd.cpp b/libc/src/unistd/linux/getcwd.cpp index 1bb11a7c8e7b..c0e475dd3e8f 100644 --- a/libc/src/unistd/linux/getcwd.cpp +++ b/libc/src/unistd/linux/getcwd.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/string/allocating_string_utils.h" // For strdup. -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include // This is safe to include without any name pollution. #include // For syscall numbers. diff --git a/libc/src/unistd/linux/getentropy.cpp b/libc/src/unistd/linux/getentropy.cpp index 168a1197734e..65bcbf27601d 100644 --- a/libc/src/unistd/linux/getentropy.cpp +++ b/libc/src/unistd/linux/getentropy.cpp @@ -10,7 +10,7 @@ #include "hdr/errno_macros.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/unistd/linux/getsid.cpp b/libc/src/unistd/linux/getsid.cpp index 5977c5bf10e9..025b8d1691ac 100644 --- a/libc/src/unistd/linux/getsid.cpp +++ b/libc/src/unistd/linux/getsid.cpp @@ -11,8 +11,8 @@ #include "hdr/types/pid_t.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/isatty.cpp b/libc/src/unistd/linux/isatty.cpp index e6ea22a714c7..a4d17912b57b 100644 --- a/libc/src/unistd/linux/isatty.cpp +++ b/libc/src/unistd/linux/isatty.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For ioctl numbers. #include // For syscall numbers. diff --git a/libc/src/unistd/linux/link.cpp b/libc/src/unistd/linux/link.cpp index 477806a70df7..205cf8a84a5c 100644 --- a/libc/src/unistd/linux/link.cpp +++ b/libc/src/unistd/linux/link.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/fcntl_macros.h" #include // For syscall numbers. diff --git a/libc/src/unistd/linux/linkat.cpp b/libc/src/unistd/linux/linkat.cpp index 40f68cc90c48..ea5bc48cbedc 100644 --- a/libc/src/unistd/linux/linkat.cpp +++ b/libc/src/unistd/linux/linkat.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/lseek.cpp b/libc/src/unistd/linux/lseek.cpp index 0e957498da74..26a08269fd8d 100644 --- a/libc/src/unistd/linux/lseek.cpp +++ b/libc/src/unistd/linux/lseek.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/unistd/lseek.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/__support/File/linux/lseekImpl.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. diff --git a/libc/src/unistd/linux/pathconf.cpp b/libc/src/unistd/linux/pathconf.cpp index ca1c10bb9f7f..7dde857c1cfd 100644 --- a/libc/src/unistd/linux/pathconf.cpp +++ b/libc/src/unistd/linux/pathconf.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "src/unistd/pathconf.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/sys/statvfs/linux/statfs_utils.h" #include "src/unistd/linux/pathconf_utils.h" diff --git a/libc/src/unistd/linux/pathconf_utils.cpp b/libc/src/unistd/linux/pathconf_utils.cpp index 035e628dff25..9a62e31fd188 100644 --- a/libc/src/unistd/linux/pathconf_utils.cpp +++ b/libc/src/unistd/linux/pathconf_utils.cpp @@ -14,8 +14,8 @@ #include "hdr/unistd_macros.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/sys/statvfs/linux/statfs_utils.h" // other linux specific includes diff --git a/libc/src/unistd/linux/pipe.cpp b/libc/src/unistd/linux/pipe.cpp index dfcd5bfdaf53..b9943c833805 100644 --- a/libc/src/unistd/linux/pipe.cpp +++ b/libc/src/unistd/linux/pipe.cpp @@ -10,10 +10,10 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON -#include "src/errno/libc_errno.h" -#include // For syscall numbers. +#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/pipe2.cpp b/libc/src/unistd/linux/pipe2.cpp index ebe7e0114ae9..d30f3b37a1ad 100644 --- a/libc/src/unistd/linux/pipe2.cpp +++ b/libc/src/unistd/linux/pipe2.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/pread.cpp b/libc/src/unistd/linux/pread.cpp index 3e27857f9a2b..2f86e397feef 100644 --- a/libc/src/unistd/linux/pread.cpp +++ b/libc/src/unistd/linux/pread.cpp @@ -10,11 +10,11 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON -#include "src/errno/libc_errno.h" -#include // For uint64_t. -#include // For syscall numbers. +#include // For uint64_t. +#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/pwrite.cpp b/libc/src/unistd/linux/pwrite.cpp index 1b81b2a05949..f4cf8e16d766 100644 --- a/libc/src/unistd/linux/pwrite.cpp +++ b/libc/src/unistd/linux/pwrite.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For uint64_t. #include // For syscall numbers. diff --git a/libc/src/unistd/linux/read.cpp b/libc/src/unistd/linux/read.cpp index 4419900f2330..55676f3f7010 100644 --- a/libc/src/unistd/linux/read.cpp +++ b/libc/src/unistd/linux/read.cpp @@ -10,10 +10,10 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON -#include "src/errno/libc_errno.h" -#include // For syscall numbers. +#include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/readlink.cpp b/libc/src/unistd/linux/readlink.cpp index 2055e6b3400f..b297a41ca37b 100644 --- a/libc/src/unistd/linux/readlink.cpp +++ b/libc/src/unistd/linux/readlink.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/readlinkat.cpp b/libc/src/unistd/linux/readlinkat.cpp index e5e4d0d39bc9..cd0dcb8e0ff0 100644 --- a/libc/src/unistd/linux/readlinkat.cpp +++ b/libc/src/unistd/linux/readlinkat.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/rmdir.cpp b/libc/src/unistd/linux/rmdir.cpp index 075af12af64c..eca6e954ef89 100644 --- a/libc/src/unistd/linux/rmdir.cpp +++ b/libc/src/unistd/linux/rmdir.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/fcntl_macros.h" #include // For syscall numbers. diff --git a/libc/src/unistd/linux/symlink.cpp b/libc/src/unistd/linux/symlink.cpp index 9e1b2886ea0f..3f43de19d2f4 100644 --- a/libc/src/unistd/linux/symlink.cpp +++ b/libc/src/unistd/linux/symlink.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/fcntl_macros.h" #include // For syscall numbers. diff --git a/libc/src/unistd/linux/symlinkat.cpp b/libc/src/unistd/linux/symlinkat.cpp index bcf2d0f8cc05..8cee172f39df 100644 --- a/libc/src/unistd/linux/symlinkat.cpp +++ b/libc/src/unistd/linux/symlinkat.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/syscall.cpp b/libc/src/unistd/linux/syscall.cpp index 5394bff46adf..0f7b3da88d62 100644 --- a/libc/src/unistd/linux/syscall.cpp +++ b/libc/src/unistd/linux/syscall.cpp @@ -11,8 +11,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/sysconf.cpp b/libc/src/unistd/linux/sysconf.cpp index f785ff321c7d..03f224b15027 100644 --- a/libc/src/unistd/linux/sysconf.cpp +++ b/libc/src/unistd/linux/sysconf.cpp @@ -11,8 +11,8 @@ #include "src/__support/common.h" #include "hdr/unistd_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/sys/auxv/getauxval.h" #include diff --git a/libc/src/unistd/linux/truncate.cpp b/libc/src/unistd/linux/truncate.cpp index 8236edb480d1..6103d4b51350 100644 --- a/libc/src/unistd/linux/truncate.cpp +++ b/libc/src/unistd/linux/truncate.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/unistd_macros.h" #include // For uint64_t. diff --git a/libc/src/unistd/linux/unlink.cpp b/libc/src/unistd/linux/unlink.cpp index 72d8e2398e3d..5fde2600937b 100644 --- a/libc/src/unistd/linux/unlink.cpp +++ b/libc/src/unistd/linux/unlink.cpp @@ -12,8 +12,8 @@ #include "src/__support/common.h" #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/unlinkat.cpp b/libc/src/unistd/linux/unlinkat.cpp index 4ed20f542f17..b2012c52b885 100644 --- a/libc/src/unistd/linux/unlinkat.cpp +++ b/libc/src/unistd/linux/unlinkat.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "hdr/fcntl_macros.h" #include // For syscall numbers. diff --git a/libc/src/unistd/linux/write.cpp b/libc/src/unistd/linux/write.cpp index 99d5ab7e480b..eecb74429182 100644 --- a/libc/src/unistd/linux/write.cpp +++ b/libc/src/unistd/linux/write.cpp @@ -10,8 +10,8 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include // For syscall numbers. diff --git a/libc/src/unistd/windows/getentropy.cpp b/libc/src/unistd/windows/getentropy.cpp index bfaec723ac63..e25a7a8fed40 100644 --- a/libc/src/unistd/windows/getentropy.cpp +++ b/libc/src/unistd/windows/getentropy.cpp @@ -9,7 +9,7 @@ #include "src/unistd/getentropy.h" #include "hdr/errno_macros.h" #include "src/__support/common.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #define WIN32_LEAN_AND_MEAN #include diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 759f708c2247..ec33caccb16d 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -34,6 +34,37 @@ add_entrypoint_object( libc.src.__support.wctype_utils ) +add_entrypoint_object( + wcrtomb + SRCS + wcrtomb.cpp + HDRS + wcrtomb.h + DEPENDS + libc.hdr.types.wchar_t + libc.hdr.types.mbstate_t + libc.src.__support.libc_errno + libc.src.__support.wchar.wcrtomb + libc.src.__support.wchar.mbstate +) + +add_entrypoint_object( + mbrtowc + SRCS + mbrtowc.cpp + HDRS + mbrtowc.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.mbstate_t + libc.hdr.types.wchar_t + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.wchar.mbrtowc + libc.src.__support.libc_errno + libc.src.__support.wchar.mbstate +) + add_entrypoint_object( wmemset SRCS @@ -43,7 +74,6 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.types.wchar_t - libc.src.__support.wctype_utils ) add_entrypoint_object( @@ -54,7 +84,6 @@ add_entrypoint_object( wcschr.h DEPENDS libc.hdr.wchar_macros - libc.src.__support.wctype_utils ) add_entrypoint_object( @@ -75,7 +104,6 @@ add_entrypoint_object( wcspbrk.h DEPENDS libc.hdr.wchar_macros - libc.src.__support.wctype_utils libc.src.__support.macros.null_check ) @@ -109,7 +137,6 @@ add_entrypoint_object( DEPENDS libc.hdr.wchar_macros libc.hdr.types.size_t - libc.src.__support.wctype_utils ) add_entrypoint_object( @@ -121,7 +148,6 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.wchar_macros - libc.src.__support.wctype_utils libc.src.__support.macros.null_check ) @@ -134,7 +160,18 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.wchar_macros - libc.src.__support.wctype_utils +) + +add_entrypoint_object( + wmemmove + SRCS + wmemmove.cpp + HDRS + wmemmove.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.wchar_macros + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -205,8 +242,6 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.wchar_macros - libc.src.__support.wctype_utils - libc.src.string.memory_utils.inline_memcpy ) add_entrypoint_object( @@ -218,6 +253,5 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.wchar_macros - libc.src.string.memory_utils.inline_memcpy libc.src.string.string_utils ) diff --git a/libc/src/wchar/mbrtowc.cpp b/libc/src/wchar/mbrtowc.cpp new file mode 100644 index 000000000000..cd429ab8d30e --- /dev/null +++ b/libc/src/wchar/mbrtowc.cpp @@ -0,0 +1,38 @@ +//===-- Implementation of mbrtowc -----------------------------------------===// +// +// 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 "src/wchar/mbrtowc.h" + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbrtowc.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, mbrtowc, + (wchar_t *__restrict pwc, const char *__restrict s, size_t n, + mbstate_t *__restrict ps)) { + static internal::mbstate internal_mbstate; + auto ret = internal::mbrtowc(pwc, s, n, + ps == nullptr + ? &internal_mbstate + : reinterpret_cast(ps)); + if (!ret.has_value()) { + // Encoding failure + libc_errno = EILSEQ; + return -1; + } + return ret.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/mbrtowc.h b/libc/src/wchar/mbrtowc.h new file mode 100644 index 000000000000..e2e3d3ebd285 --- /dev/null +++ b/libc/src/wchar/mbrtowc.h @@ -0,0 +1,24 @@ +//===-- Implementation header for mbrtowc ---------------------------------===// +// +// 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_LIBC_SRC_WCHAR_MBRTOWC_H +#define LLVM_LIBC_SRC_WCHAR_MBRTOWC_H + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, size_t n, + mbstate_t *__restrict ps); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_MBRTOWC_H diff --git a/libc/src/wchar/wcrtomb.cpp b/libc/src/wchar/wcrtomb.cpp new file mode 100644 index 000000000000..6d604a00599e --- /dev/null +++ b/libc/src/wchar/wcrtomb.cpp @@ -0,0 +1,45 @@ +//===-- Implementation of wcrtomb -----------------------------------------===// +// +// 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 "src/wchar/wcrtomb.h" + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" +#include "src/__support/wchar/wcrtomb.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, wcrtomb, + (char *__restrict s, wchar_t wc, mbstate_t *__restrict ps)) { + static internal::mbstate internal_mbstate; + + // when s is nullptr, this is equivalent to wcrtomb(buf, L'\0', ps) + char buf[sizeof(wchar_t) / sizeof(char)]; + if (s == nullptr) { + s = buf; + wc = L'\0'; + } + + auto result = internal::wcrtomb( + s, wc, + ps == nullptr ? &internal_mbstate + : reinterpret_cast(ps)); + + if (!result.has_value()) { + libc_errno = EILSEQ; + return -1; + } + + return result.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcrtomb.h b/libc/src/wchar/wcrtomb.h new file mode 100644 index 000000000000..06c42f158122 --- /dev/null +++ b/libc/src/wchar/wcrtomb.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcrtomb -----------------------*- 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_LIBC_SRC_WCHAR_WCRTOMB_H +#define LLVM_LIBC_SRC_WCHAR_WCRTOMB_H + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcrtomb(char *__restrict s, wchar_t wc, mbstate_t *__restrict ps); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCRTOMB_H diff --git a/libc/src/wchar/wcscpy.cpp b/libc/src/wchar/wcscpy.cpp index dc46b972c59f..01ba994cecbb 100644 --- a/libc/src/wchar/wcscpy.cpp +++ b/libc/src/wchar/wcscpy.cpp @@ -12,7 +12,6 @@ #include "hdr/types/wchar_t.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/string/memory_utils/inline_memcpy.h" #include "src/string/string_utils.h" namespace LIBC_NAMESPACE_DECL { @@ -20,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(wchar_t *, wcscpy, (wchar_t *__restrict s1, const wchar_t *__restrict s2)) { size_t size = internal::string_length(s2) + 1; - inline_memcpy(s1, s2, size * sizeof(wchar_t)); + __builtin_memcpy(s1, s2, size * sizeof(wchar_t)); return s1; } diff --git a/libc/src/wchar/wcsncpy.cpp b/libc/src/wchar/wcsncpy.cpp index e7ae9a4a0da7..7ad6730cd776 100644 --- a/libc/src/wchar/wcsncpy.cpp +++ b/libc/src/wchar/wcsncpy.cpp @@ -12,8 +12,6 @@ #include "hdr/types/wchar_t.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/string/memory_utils/inline_memcpy.h" -#include "src/string/string_utils.h" namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/wchar/wmemcpy.cpp b/libc/src/wchar/wmemcpy.cpp index 56708d6cee49..bf92309b2094 100644 --- a/libc/src/wchar/wmemcpy.cpp +++ b/libc/src/wchar/wmemcpy.cpp @@ -12,14 +12,13 @@ #include "hdr/types/wchar_t.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/string/memory_utils/inline_memcpy.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(wchar_t *, wmemcpy, (wchar_t *__restrict s1, const wchar_t *__restrict s2, size_t n)) { - inline_memcpy(s1, s2, n * sizeof(wchar_t)); + __builtin_memcpy(s1, s2, n * sizeof(wchar_t)); return s1; } diff --git a/libc/src/wchar/wmemmove.cpp b/libc/src/wchar/wmemmove.cpp new file mode 100644 index 000000000000..3282077003bd --- /dev/null +++ b/libc/src/wchar/wmemmove.cpp @@ -0,0 +1,27 @@ +//===-- Implementation of wmemmove ----------------------------------------===// +// +// 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 "src/wchar/wmemmove.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/null_check.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wmemmove, + (wchar_t * dest, const wchar_t *src, size_t n)) { + LIBC_CRASH_ON_NULLPTR(dest); + LIBC_CRASH_ON_NULLPTR(src); + + __builtin_memmove(dest, src, n * sizeof(wchar_t)); + return dest; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wmemmove.h b/libc/src/wchar/wmemmove.h new file mode 100644 index 000000000000..b4c31ac7b397 --- /dev/null +++ b/libc/src/wchar/wmemmove.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wmemmove --------------------------------===// +// +// 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_LIBC_SRC_WCHAR_WMEMMOVE_H +#define LLVM_LIBC_SRC_WCHAR_WMEMMOVE_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WMEMMOVE_H diff --git a/libc/src/wchar/wmempcpy.cpp b/libc/src/wchar/wmempcpy.cpp index d8b89c0a88d0..21e16210a757 100644 --- a/libc/src/wchar/wmempcpy.cpp +++ b/libc/src/wchar/wmempcpy.cpp @@ -11,14 +11,13 @@ #include "hdr/types/size_t.h" #include "hdr/types/wchar_t.h" #include "src/__support/common.h" -#include "src/string/memory_utils/inline_memcpy.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(wchar_t *, wmempcpy, (wchar_t *__restrict to, const wchar_t *__restrict from, size_t size)) { - inline_memcpy(to, from, size * sizeof(wchar_t)); + __builtin_memcpy(to, from, size * sizeof(wchar_t)); return reinterpret_cast(to) + size; } diff --git a/libc/test/IntegrationTest/test.h b/libc/test/IntegrationTest/test.h index 5be66d9edff0..24c007d2e12e 100644 --- a/libc/test/IntegrationTest/test.h +++ b/libc/test/IntegrationTest/test.h @@ -68,12 +68,9 @@ //////////////////////////////////////////////////////////////////////////////// // Errno checks. -#define ASSERT_ERRNO_EQ(VAL) \ - ASSERT_EQ(VAL, static_cast(LIBC_NAMESPACE::libc_errno)) -#define ASSERT_ERRNO_SUCCESS() \ - ASSERT_EQ(0, static_cast(LIBC_NAMESPACE::libc_errno)) -#define ASSERT_ERRNO_FAILURE() \ - ASSERT_NE(0, static_cast(LIBC_NAMESPACE::libc_errno)) +#define ASSERT_ERRNO_EQ(VAL) ASSERT_EQ(VAL, static_cast(libc_errno)) +#define ASSERT_ERRNO_SUCCESS() ASSERT_EQ(0, static_cast(libc_errno)) +#define ASSERT_ERRNO_FAILURE() ASSERT_NE(0, static_cast(libc_errno)) // Integration tests are compiled with -ffreestanding which stops treating // the main function as a non-overloadable special function. Hence, we use a diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt index b0a3a7431c22..c32809da577d 100644 --- a/libc/test/UnitTest/CMakeLists.txt +++ b/libc/test/UnitTest/CMakeLists.txt @@ -35,7 +35,7 @@ function(add_unittest_framework_library name) else() _get_common_test_compile_options(compile_options "" "") target_compile_options(${name}.unit PRIVATE ${compile_options}) -endif() + endif() _get_hermetic_test_compile_options(compile_options "") target_include_directories(${name}.hermetic PRIVATE ${LIBC_INCLUDE_DIR}) diff --git a/libc/test/UnitTest/ErrnoCheckingTest.h b/libc/test/UnitTest/ErrnoCheckingTest.h index 3d3b72f80544..4b7ff452f409 100644 --- a/libc/test/UnitTest/ErrnoCheckingTest.h +++ b/libc/test/UnitTest/ErrnoCheckingTest.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_TEST_UNITTEST_ERRNOCHECKINGTEST_H #define LLVM_LIBC_TEST_UNITTEST_ERRNOCHECKINGTEST_H +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" namespace LIBC_NAMESPACE_DECL { @@ -25,7 +25,7 @@ class ErrnoCheckingTest : public Test { public: void SetUp() override { Test::SetUp(); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } void TearDown() override { diff --git a/libc/test/UnitTest/ErrnoSetterMatcher.h b/libc/test/UnitTest/ErrnoSetterMatcher.h index c6eadd25858e..212b7a8f83e7 100644 --- a/libc/test/UnitTest/ErrnoSetterMatcher.h +++ b/libc/test/UnitTest/ErrnoSetterMatcher.h @@ -12,9 +12,9 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/fpbits_str.h" #include "src/__support/StringUtil/error_to_string.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" -#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" namespace LIBC_NAMESPACE_DECL { @@ -114,8 +114,8 @@ public: bool match(T got) { actual_return = got; - actual_errno = LIBC_NAMESPACE::libc_errno; - LIBC_NAMESPACE::libc_errno = 0; + actual_errno = libc_errno; + libc_errno = 0; if constexpr (ignore_errno()) return return_cmp.compare(actual_return); else diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h index 21b8a45b0726..da15cf2907f7 100644 --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -279,8 +279,8 @@ private: #define EXPECT_MATH_ERRNO(expected) \ do { \ if (math_errhandling & MATH_ERRNO) { \ - int actual = LIBC_NAMESPACE::libc_errno; \ - LIBC_NAMESPACE::libc_errno = 0; \ + int actual = libc_errno; \ + libc_errno = 0; \ EXPECT_EQ(actual, expected); \ } \ } while (0) @@ -288,8 +288,8 @@ private: #define ASSERT_MATH_ERRNO(expected) \ do { \ if (math_errhandling & MATH_ERRNO) { \ - int actual = LIBC_NAMESPACE::libc_errno; \ - LIBC_NAMESPACE::libc_errno = 0; \ + int actual = libc_errno; \ + libc_errno = 0; \ ASSERT_EQ(actual, expected); \ } \ } while (0) diff --git a/libc/test/UnitTest/Test.h b/libc/test/UnitTest/Test.h index 95d48f40914e..a5a2a3c7cf58 100644 --- a/libc/test/UnitTest/Test.h +++ b/libc/test/UnitTest/Test.h @@ -42,15 +42,14 @@ #define ASSERT_ERRNO_EQ(VAL) \ do { \ - ASSERT_EQ(VAL, static_cast(LIBC_NAMESPACE::libc_errno)); \ - LIBC_NAMESPACE::libc_errno = 0; \ + ASSERT_EQ(VAL, static_cast(libc_errno)); \ + libc_errno = 0; \ } while (0) -#define ASSERT_ERRNO_SUCCESS() \ - ASSERT_EQ(0, static_cast(LIBC_NAMESPACE::libc_errno)) +#define ASSERT_ERRNO_SUCCESS() ASSERT_EQ(0, static_cast(libc_errno)) #define ASSERT_ERRNO_FAILURE() \ do { \ - ASSERT_NE(0, static_cast(LIBC_NAMESPACE::libc_errno)); \ - LIBC_NAMESPACE::libc_errno = 0; \ + ASSERT_NE(0, static_cast(libc_errno)); \ + libc_errno = 0; \ } while (0) #endif // LLVM_LIBC_TEST_UNITTEST_TEST_H diff --git a/libc/test/integration/src/pthread/pthread_create_test.cpp b/libc/test/integration/src/pthread/pthread_create_test.cpp index 29da4d5c3c8d..aecbad6514aa 100644 --- a/libc/test/integration/src/pthread/pthread_create_test.cpp +++ b/libc/test/integration/src/pthread/pthread_create_test.cpp @@ -29,7 +29,7 @@ #include "src/__support/CPP/new.h" #include "src/__support/threads/thread.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "test/IntegrationTest/test.h" @@ -332,7 +332,7 @@ static void run_failure_tests() { } TEST_MAIN() { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; run_success_tests(); run_failure_tests(); return 0; diff --git a/libc/test/integration/src/pthread/pthread_join_test.cpp b/libc/test/integration/src/pthread/pthread_join_test.cpp index 994fa57a6b33..5d0bcd8e2365 100644 --- a/libc/test/integration/src/pthread/pthread_join_test.cpp +++ b/libc/test/integration/src/pthread/pthread_join_test.cpp @@ -9,7 +9,7 @@ #include "src/pthread/pthread_create.h" #include "src/pthread/pthread_join.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "test/IntegrationTest/test.h" #include @@ -25,7 +25,7 @@ static void nullJoinTest() { } TEST_MAIN() { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; nullJoinTest(); return 0; } diff --git a/libc/test/integration/src/pthread/pthread_name_test.cpp b/libc/test/integration/src/pthread/pthread_name_test.cpp index 37ceceee880d..35dd3b165e0e 100644 --- a/libc/test/integration/src/pthread/pthread_name_test.cpp +++ b/libc/test/integration/src/pthread/pthread_name_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/CPP/string_view.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/pthread/pthread_create.h" #include "src/pthread/pthread_getname_np.h" #include "src/pthread/pthread_join.h" diff --git a/libc/test/integration/src/unistd/getcwd_test.cpp b/libc/test/integration/src/unistd/getcwd_test.cpp index 551768187bf0..1b321b01e931 100644 --- a/libc/test/integration/src/unistd/getcwd_test.cpp +++ b/libc/test/integration/src/unistd/getcwd_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/CPP/string_view.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/stdlib/getenv.h" #include "src/unistd/getcwd.h" @@ -31,12 +31,12 @@ TEST_MAIN(int argc, char **argv, char **envp) { cwd = LIBC_NAMESPACE::getcwd(buffer, 0); ASSERT_TRUE(cwd == nullptr); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // Insufficient size cwd = LIBC_NAMESPACE::getcwd(buffer, 2); ASSERT_TRUE(cwd == nullptr); - int err = LIBC_NAMESPACE::libc_errno; + int err = libc_errno; ASSERT_EQ(err, ERANGE); return 0; diff --git a/libc/test/integration/startup/linux/tls_test.cpp b/libc/test/integration/startup/linux/tls_test.cpp index ef9fd9fcb7ff..de3bd06c39cf 100644 --- a/libc/test/integration/startup/linux/tls_test.cpp +++ b/libc/test/integration/startup/linux/tls_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sys/mman/mmap.h" #include "test/IntegrationTest/test.h" diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt index b7c145788c0c..6dca47b5343e 100644 --- a/libc/test/src/CMakeLists.txt +++ b/libc/test/src/CMakeLists.txt @@ -62,6 +62,7 @@ add_subdirectory(errno) add_subdirectory(fenv) add_subdirectory(math) add_subdirectory(search) +add_subdirectory(setjmp) add_subdirectory(stdbit) add_subdirectory(stdfix) add_subdirectory(stdio) @@ -92,7 +93,6 @@ add_subdirectory(assert) add_subdirectory(compiler) add_subdirectory(dirent) add_subdirectory(locale) -add_subdirectory(setjmp) add_subdirectory(signal) add_subdirectory(spawn) diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index c1736c8fe59e..9f626ed31cc0 100644 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -127,7 +127,6 @@ add_libc_test( libc.src.__support.integer_literals libc.src.__support.str_to_float libc.src.__support.uint128 - libc.src.errno.errno ) @@ -140,7 +139,6 @@ add_libc_test( DEPENDS libc.src.__support.integer_literals libc.src.__support.str_to_integer - libc.src.errno.errno ) add_libc_test( @@ -277,3 +275,8 @@ add_subdirectory(fixed_point) add_subdirectory(HashTable) add_subdirectory(time) add_subdirectory(threads) +# Requires access to uchar header which is not on MacOS +# Cannot currently build this on MacOS in overlay mode +if(NOT(LIBC_TARGET_OS_IS_DARWIN)) + add_subdirectory(wchar) +endif() diff --git a/libc/test/src/__support/HashTable/table_test.cpp b/libc/test/src/__support/HashTable/table_test.cpp index a579bfabb2d7..ba9849b6b5af 100644 --- a/libc/test/src/__support/HashTable/table_test.cpp +++ b/libc/test/src/__support/HashTable/table_test.cpp @@ -108,7 +108,9 @@ TEST(LlvmLibcTableTest, Insertion) { static_cast(keys[CAP].bytes)); for (size_t i = 0; i <= CAP; ++i) { - ASSERT_EQ(strcmp(table->find(keys[i].bytes)->key, keys[i].bytes), 0); + auto comp = [](char l, char r) -> int { return l - r; }; + ASSERT_EQ( + inline_strcmp(table->find(keys[i].bytes)->key, keys[i].bytes, comp), 0); } for (size_t i = CAP + 1; i < 256; ++i) { ASSERT_EQ(table->find(keys[i].bytes), static_cast(nullptr)); diff --git a/libc/test/src/__support/str_to_double_test.cpp b/libc/test/src/__support/str_to_double_test.cpp index ccfa44f12d8e..dc503aa16f08 100644 --- a/libc/test/src/__support/str_to_double_test.cpp +++ b/libc/test/src/__support/str_to_double_test.cpp @@ -99,7 +99,6 @@ TEST(LlvmLibcStrToDblTest, SimpleDecimalConversionExtraTypes) { uint64_t double_output_mantissa = 0; uint32_t output_exp2 = 0; - LIBC_NAMESPACE::libc_errno = 0; auto double_result = internal::simple_decimal_conversion("123456789012345678900"); diff --git a/libc/test/src/__support/str_to_float_test.cpp b/libc/test/src/__support/str_to_float_test.cpp index 66f7db742eb4..03ae80fc2ee3 100644 --- a/libc/test/src/__support/str_to_float_test.cpp +++ b/libc/test/src/__support/str_to_float_test.cpp @@ -55,7 +55,6 @@ TEST(LlvmLibcStrToFltTest, SimpleDecimalConversionExtraTypes) { uint32_t float_output_mantissa = 0; uint32_t output_exp2 = 0; - LIBC_NAMESPACE::libc_errno = 0; auto float_result = internal::simple_decimal_conversion("123456789012345678900"); float_output_mantissa = float_result.num.mantissa; diff --git a/libc/test/src/__support/str_to_fp_test.h b/libc/test/src/__support/str_to_fp_test.h index c7bc57b845fe..9b4844d410db 100644 --- a/libc/test/src/__support/str_to_fp_test.h +++ b/libc/test/src/__support/str_to_fp_test.h @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" #include "src/__support/uint128.h" -#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" @@ -67,7 +67,6 @@ template struct LlvmLibcStrToFloatTest : public testing::Test { const int expectedErrno = 0) { StorageType actual_output_mantissa = 0; uint32_t actual_output_exp2 = 0; - LIBC_NAMESPACE::libc_errno = 0; auto result = internal::simple_decimal_conversion(numStart); diff --git a/libc/test/src/__support/str_to_integer_test.cpp b/libc/test/src/__support/str_to_integer_test.cpp index 34b645b4b38c..40cb76a8bd6a 100644 --- a/libc/test/src/__support/str_to_integer_test.cpp +++ b/libc/test/src/__support/str_to_integer_test.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/libc_errno.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" #include #include "test/UnitTest/Test.h" diff --git a/libc/test/src/__support/wchar/CMakeLists.txt b/libc/test/src/__support/wchar/CMakeLists.txt new file mode 100644 index 000000000000..5176bfd4b024 --- /dev/null +++ b/libc/test/src/__support/wchar/CMakeLists.txt @@ -0,0 +1,21 @@ +add_custom_target(libc-support-wchar-tests) + +add_libc_test( + utf8_to_32_test + SUITE + libc-support-tests + SRCS + utf8_to_32_test.cpp + DEPENDS + libc.src.__support.wchar.character_converter +) + +add_libc_test( + utf32_to_8_test + SUITE + libc-support-tests + SRCS + utf32_to_8_test.cpp + DEPENDS + libc.src.__support.wchar.character_converter +) diff --git a/libc/test/src/__support/wchar/utf32_to_8_test.cpp b/libc/test/src/__support/wchar/utf32_to_8_test.cpp new file mode 100644 index 000000000000..a6a7bc4aa6f4 --- /dev/null +++ b/libc/test/src/__support/wchar/utf32_to_8_test.cpp @@ -0,0 +1,188 @@ +//===-- Unittests for the CharacterConverter class (utf32 -> 8) -----------===// +// +// 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 "src/__support/common.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcCharacterConverterUTF32To8Test, OneByte) { + LIBC_NAMESPACE::internal::mbstate state; + LIBC_NAMESPACE::internal::CharacterConverter cr(&state); + cr.clear(); + + // utf8 1-byte encodings are identical to their utf32 representations + char32_t utf32_A = 0x41; // 'A' + cr.push(utf32_A); + ASSERT_TRUE(cr.isFull()); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 'A'); + ASSERT_TRUE(cr.isEmpty()); + + char32_t utf32_B = 0x42; // 'B' + cr.push(utf32_B); + ASSERT_TRUE(cr.isFull()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 'B'); + ASSERT_TRUE(cr.isEmpty()); + + // should error if we try to pop another utf8 byte out + popped = cr.pop_utf8(); + ASSERT_FALSE(popped.has_value()); +} + +TEST(LlvmLibcCharacterConverterUTF32To8Test, TwoByte) { + LIBC_NAMESPACE::internal::mbstate state; + LIBC_NAMESPACE::internal::CharacterConverter cr(&state); + cr.clear(); + + // testing utf32: 0xff -> utf8: 0xc3 0xbf + char32_t utf32 = 0xff; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xc3); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xbf); + ASSERT_TRUE(cr.isEmpty()); + + // testing utf32: 0x58e -> utf8: 0xd6 0x8e + utf32 = 0x58e; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xd6); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x8e); + ASSERT_TRUE(cr.isEmpty()); + + // should error if we try to pop another utf8 byte out + popped = cr.pop_utf8(); + ASSERT_FALSE(popped.has_value()); +} + +TEST(LlvmLibcCharacterConverterUTF32To8Test, ThreeByte) { + LIBC_NAMESPACE::internal::mbstate state; + LIBC_NAMESPACE::internal::CharacterConverter cr(&state); + cr.clear(); + + // testing utf32: 0xac15 -> utf8: 0xea 0xb0 0x95 + char32_t utf32 = 0xac15; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xea); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xb0); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x95); + ASSERT_TRUE(cr.isEmpty()); + + // testing utf32: 0x267b -> utf8: 0xe2 0x99 0xbb + utf32 = 0x267b; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xe2); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x99); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xbb); + ASSERT_TRUE(cr.isEmpty()); + + // should error if we try to pop another utf8 byte out + popped = cr.pop_utf8(); + ASSERT_FALSE(popped.has_value()); +} + +TEST(LlvmLibcCharacterConverterUTF32To8Test, FourByte) { + LIBC_NAMESPACE::internal::mbstate state; + LIBC_NAMESPACE::internal::CharacterConverter cr(&state); + cr.clear(); + + // testing utf32: 0x1f921 -> utf8: 0xf0 0x9f 0xa4 0xa1 + char32_t utf32 = 0x1f921; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xf0); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x9f); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa4); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa1); + ASSERT_TRUE(cr.isEmpty()); + + // testing utf32: 0x12121 -> utf8: 0xf0 0x92 0x84 0xa1 + utf32 = 0x12121; + cr.push(utf32); + ASSERT_TRUE(cr.isFull()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xf0); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x92); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x84); + ASSERT_TRUE(!cr.isEmpty()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa1); + ASSERT_TRUE(cr.isEmpty()); + + // should error if we try to pop another utf8 byte out + popped = cr.pop_utf8(); + ASSERT_FALSE(popped.has_value()); +} + +TEST(LlvmLibcCharacterConverterUTF32To8Test, CantPushMidConversion) { + LIBC_NAMESPACE::internal::mbstate state; + LIBC_NAMESPACE::internal::CharacterConverter cr(&state); + cr.clear(); + + // testing utf32: 0x12121 -> utf8: 0xf0 0x92 0x84 0xa1 + char32_t utf32 = 0x12121; + ASSERT_EQ(cr.push(utf32), 0); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + + // can't push a utf32 without finishing popping the utf8 bytes out + int err = cr.push(utf32); + ASSERT_EQ(err, -1); +} diff --git a/libc/test/src/__support/wchar/utf8_to_32_test.cpp b/libc/test/src/__support/wchar/utf8_to_32_test.cpp new file mode 100644 index 000000000000..36ae7d689cc0 --- /dev/null +++ b/libc/test/src/__support/wchar/utf8_to_32_test.cpp @@ -0,0 +1,196 @@ +//===-- Unittests for character_converter utf8->utf32 ---------------------===// +// +// 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 "src/__support/error_or.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcCharacterConverterUTF8To32Test, OneByte) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + char ch = 'A'; + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch)); + auto wch = char_conv.pop_utf32(); + + ASSERT_EQ(err, 0); + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 65); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, TwoBytes) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[2] = {static_cast(0xC2), + static_cast(0x8E)}; // Ž car symbol + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + char_conv.push(static_cast(ch[0])); + char_conv.push(static_cast(ch[1])); + auto wch = char_conv.pop_utf32(); + + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 142); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, ThreeBytes) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[3] = {static_cast(0xE2), static_cast(0x88), + static_cast(0x91)}; // ∑ sigma symbol + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + char_conv.push(static_cast(ch[0])); + char_conv.push(static_cast(ch[1])); + char_conv.push(static_cast(ch[2])); + auto wch = char_conv.pop_utf32(); + + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 8721); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, FourBytes) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[4] = {static_cast(0xF0), static_cast(0x9F), + static_cast(0xA4), + static_cast(0xA1)}; // 🤡 clown emoji + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + char_conv.push(static_cast(ch[0])); + char_conv.push(static_cast(ch[1])); + char_conv.push(static_cast(ch[2])); + char_conv.push(static_cast(ch[3])); + auto wch = char_conv.pop_utf32(); + + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 129313); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, InvalidByte) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch = static_cast(0x80); // invalid starting bit sequence + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch)); + + ASSERT_EQ(err, -1); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, InvalidMultiByte) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[4] = { + static_cast(0x80), static_cast(0x00), static_cast(0x80), + static_cast(0x00)}; // first and third bytes are invalid + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch[0])); + ASSERT_EQ(err, -1); + err = char_conv.push(static_cast(ch[1])); + ASSERT_EQ(err, 0); + // Prev byte was single byte so trying to push another should error. + err = char_conv.push(static_cast(ch[2])); + ASSERT_EQ(err, -1); + err = char_conv.push(static_cast(ch[3])); + ASSERT_EQ(err, 0); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, InvalidLastByte) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + // Last byte is invalid since it does not have correct starting sequence. + // 0xC0 --> 11000000 starting sequence should be 10xxxxxx + const char ch[4] = {static_cast(0xF1), static_cast(0x80), + static_cast(0x80), static_cast(0xC0)}; + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch[0])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[1])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[2])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[3])); + ASSERT_EQ(err, -1); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, ValidTwoByteWithExtraRead) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[3] = {static_cast(0xC2), static_cast(0x8E), + static_cast(0x80)}; + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch[0])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[1])); + ASSERT_EQ(err, 0); + // Should produce an error on 3rd byte + err = char_conv.push(static_cast(ch[2])); + ASSERT_EQ(err, -1); + + // Should produce an error since mbstate was reset + auto wch = char_conv.pop_utf32(); + ASSERT_FALSE(wch.has_value()); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, TwoValidTwoBytes) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + const char ch[4] = {static_cast(0xC2), static_cast(0x8E), + static_cast(0xC7), static_cast(0x8C)}; + + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + int err = char_conv.push(static_cast(ch[0])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[1])); + ASSERT_EQ(err, 0); + auto wch = char_conv.pop_utf32(); + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 142); + + // Second two byte character + err = char_conv.push(static_cast(ch[2])); + ASSERT_EQ(err, 0); + err = char_conv.push(static_cast(ch[3])); + ASSERT_EQ(err, 0); + wch = char_conv.pop_utf32(); + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 460); +} + +TEST(LlvmLibcCharacterConverterUTF8To32Test, InvalidPop) { + LIBC_NAMESPACE::internal::mbstate state; + state.bytes_stored = 0; + state.total_bytes = 0; + LIBC_NAMESPACE::internal::CharacterConverter char_conv(&state); + const char ch[2] = {static_cast(0xC2), static_cast(0x8E)}; + int err = char_conv.push(static_cast(ch[0])); + ASSERT_EQ(err, 0); + auto wch = char_conv.pop_utf32(); + ASSERT_FALSE( + wch.has_value()); // Should fail since we have not read enough bytes + err = char_conv.push(static_cast(ch[1])); + ASSERT_EQ(err, 0); + wch = char_conv.pop_utf32(); + ASSERT_TRUE(wch.has_value()); + ASSERT_EQ(static_cast(wch.value()), 142); +} diff --git a/libc/test/src/dirent/dirent_test.cpp b/libc/test/src/dirent/dirent_test.cpp index 41f522a6a75f..3f0095ca5ebe 100644 --- a/libc/test/src/dirent/dirent_test.cpp +++ b/libc/test/src/dirent/dirent_test.cpp @@ -7,11 +7,11 @@ //===----------------------------------------------------------------------===// #include "src/__support/CPP/string_view.h" +#include "src/__support/libc_errno.h" #include "src/dirent/closedir.h" #include "src/dirent/dirfd.h" #include "src/dirent/opendir.h" #include "src/dirent/readdir.h" -#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" @@ -55,17 +55,17 @@ TEST(LlvmLibcDirentTest, SimpleOpenAndRead) { } TEST(LlvmLibcDirentTest, OpenNonExistentDir) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ::DIR *dir = LIBC_NAMESPACE::opendir("___xyz123__.non_existent__"); ASSERT_TRUE(dir == nullptr); ASSERT_ERRNO_EQ(ENOENT); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } TEST(LlvmLibcDirentTest, OpenFile) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ::DIR *dir = LIBC_NAMESPACE::opendir("testdata/file1.txt"); ASSERT_TRUE(dir == nullptr); ASSERT_ERRNO_EQ(ENOTDIR); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } diff --git a/libc/test/src/errno/errno_test.cpp b/libc/test/src/errno/errno_test.cpp index b0db22a85f3b..de82b0077f17 100644 --- a/libc/test/src/errno/errno_test.cpp +++ b/libc/test/src/errno/errno_test.cpp @@ -6,11 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "test/UnitTest/Test.h" TEST(LlvmLibcErrnoTest, Basic) { int test_val = 123; - LIBC_NAMESPACE::libc_errno = test_val; + libc_errno = test_val; ASSERT_ERRNO_EQ(test_val); } diff --git a/libc/test/src/fcntl/creat_test.cpp b/libc/test/src/fcntl/creat_test.cpp index 4c9d2cbc33f4..d60c98493470 100644 --- a/libc/test/src/fcntl/creat_test.cpp +++ b/libc/test/src/fcntl/creat_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/fcntl/creat.h" #include "src/fcntl/open.h" #include "src/unistd/close.h" diff --git a/libc/test/src/fcntl/fcntl_test.cpp b/libc/test/src/fcntl/fcntl_test.cpp index 1a21afe51085..082c42481777 100644 --- a/libc/test/src/fcntl/fcntl_test.cpp +++ b/libc/test/src/fcntl/fcntl_test.cpp @@ -9,7 +9,7 @@ #include "hdr/fcntl_macros.h" #include "hdr/stdio_macros.h" #include "hdr/types/struct_flock.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/fcntl/fcntl.h" #include "src/fcntl/open.h" #include "src/unistd/close.h" @@ -166,7 +166,7 @@ TEST(LlvmLibcFcntlTest, UseAfterClose) { } TEST(LlvmLibcFcntlTest, SetGetOwnerTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; pid_t pid = LIBC_NAMESPACE::getpid(); ASSERT_GT(pid, -1); diff --git a/libc/test/src/fcntl/openat_test.cpp b/libc/test/src/fcntl/openat_test.cpp index 213b074799c8..1997476f16a6 100644 --- a/libc/test/src/fcntl/openat_test.cpp +++ b/libc/test/src/fcntl/openat_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/fcntl/open.h" #include "src/fcntl/openat.h" #include "src/unistd/close.h" diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h index 77b465a3a0e6..6af9cfea0e0a 100644 --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -55,7 +55,7 @@ private: void test_one_input(RoundToIntegerFunc func, FloatType input, IntType expected, bool expectError) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); ASSERT_EQ(func(input), expected); diff --git a/libc/test/src/math/acosf_test.cpp b/libc/test/src/math/acosf_test.cpp index 2e4c8eb2ab96..aa0128fee999 100644 --- a/libc/test/src/math/acosf_test.cpp +++ b/libc/test/src/math/acosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; using LlvmLibcAcosfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acosf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/acoshf16_test.cpp b/libc/test/src/math/acoshf16_test.cpp index 7348018396bd..2eb95215e4e8 100644 --- a/libc/test/src/math/acoshf16_test.cpp +++ b/libc/test/src/math/acoshf16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acoshf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/acoshf_test.cpp b/libc/test/src/math/acoshf_test.cpp index 18ed5a11d50a..3d3b827411a4 100644 --- a/libc/test/src/math/acoshf_test.cpp +++ b/libc/test/src/math/acoshf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acoshf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcAcoshfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcAcoshfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acoshf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/asin_test.cpp b/libc/test/src/math/asin_test.cpp index 385e341318ae..03ae963e9f92 100644 --- a/libc/test/src/math/asin_test.cpp +++ b/libc/test/src/math/asin_test.cpp @@ -38,7 +38,7 @@ TEST_F(LlvmLibcAsinTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::asin(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/asinf_test.cpp b/libc/test/src/math/asinf_test.cpp index 5197810d8bd5..1eaa6b8a5135 100644 --- a/libc/test/src/math/asinf_test.cpp +++ b/libc/test/src/math/asinf_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -22,7 +22,7 @@ using LlvmLibcAsinfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcAsinfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::asinf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/asinhf_test.cpp b/libc/test/src/math/asinhf_test.cpp index ac125c3520c4..8c78f939cabf 100644 --- a/libc/test/src/math/asinhf_test.cpp +++ b/libc/test/src/math/asinhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcAsinhfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcAsinhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::asinhf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/atan2f_test.cpp b/libc/test/src/math/atan2f_test.cpp index 331f4281af83..50ab38208089 100644 --- a/libc/test/src/math/atan2f_test.cpp +++ b/libc/test/src/math/atan2f_test.cpp @@ -81,7 +81,7 @@ TEST_F(LlvmLibcAtan2fTest, InFloatRange) { if (FPBits(w).is_nan() || FPBits(w).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::atan2f(x, y); ++total_count; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/atan_test.cpp b/libc/test/src/math/atan_test.cpp index 7f52578b9efe..7fa0dffd607e 100644 --- a/libc/test/src/math/atan_test.cpp +++ b/libc/test/src/math/atan_test.cpp @@ -39,7 +39,7 @@ TEST_F(LlvmLibcAtanTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::atan(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/atanf_test.cpp b/libc/test/src/math/atanf_test.cpp index 575ec89bd493..a4bdf1867c39 100644 --- a/libc/test/src/math/atanf_test.cpp +++ b/libc/test/src/math/atanf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -23,7 +23,7 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; // TODO: This test needs to have its checks for exceptions, errno // tightened TEST_F(LlvmLibcAtanfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanf(aNaN)); // TODO: Uncomment these checks later, RoundingMode affects running diff --git a/libc/test/src/math/atanhf_test.cpp b/libc/test/src/math/atanhf_test.cpp index 8b9db1dfdd97..32272ef482ab 100644 --- a/libc/test/src/math/atanhf_test.cpp +++ b/libc/test/src/math/atanhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -25,7 +25,7 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; // tightened https://github.com/llvm/llvm-project/issues/88819. TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN)); // TODO: Uncomment these checks later, RoundingMode affects running diff --git a/libc/test/src/math/cosf_test.cpp b/libc/test/src/math/cosf_test.cpp index 2143c36f3d30..90dc8ff6a0ea 100644 --- a/libc/test/src/math/cosf_test.cpp +++ b/libc/test/src/math/cosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -23,7 +23,7 @@ using LlvmLibcCosfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcCosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cosf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/coshf_test.cpp b/libc/test/src/math/coshf_test.cpp index 0d1c322b8e62..bdaba50f1f14 100644 --- a/libc/test/src/math/coshf_test.cpp +++ b/libc/test/src/math/coshf_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/coshf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -22,7 +22,7 @@ using LlvmLibcCoshfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcCoshfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::coshf(aNaN)); EXPECT_MATH_ERRNO(0); @@ -41,7 +41,7 @@ TEST_F(LlvmLibcCoshfTest, SpecialNumbers) { } TEST_F(LlvmLibcCoshfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::coshf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/cospif_test.cpp b/libc/test/src/math/cospif_test.cpp index 37ec2516f6a3..cb88bfcade0d 100644 --- a/libc/test/src/math/cospif_test.cpp +++ b/libc/test/src/math/cospif_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cospif.h" #include "test/UnitTest/FPMatcher.h" #include "test/src/math/sdcomp26094.h" @@ -19,7 +19,7 @@ using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcCospifTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cospif(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/exp10_test.cpp b/libc/test/src/math/exp10_test.cpp index 6fb1d2d9d925..6126e5f211ff 100644 --- a/libc/test/src/math/exp10_test.cpp +++ b/libc/test/src/math/exp10_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -105,7 +105,7 @@ TEST_F(LlvmLibcExp10Test, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::exp10(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/exp10f_test.cpp b/libc/test/src/math/exp10f_test.cpp index 001b37809d93..89915961c9b9 100644 --- a/libc/test/src/math/exp10f_test.cpp +++ b/libc/test/src/math/exp10f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcExp10fTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcExp10fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::exp10f(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExp10fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp10fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::exp10f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -55,7 +55,7 @@ TEST_F(LlvmLibcExp10fTest, Overflow) { } TEST_F(LlvmLibcExp10fTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( 0.0f, LIBC_NAMESPACE::exp10f(FPBits(0xff7fffffU).get_val()), FE_UNDERFLOW); @@ -97,7 +97,7 @@ TEST_F(LlvmLibcExp10fTest, TrickyInputs) { 0x41200000, // x = 10.0f }; for (int i = 0; i < N; ++i) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float x = FPBits(INPUTS[i]).get_val(); EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10f(x), 0.5); @@ -113,15 +113,14 @@ TEST_F(LlvmLibcExp10fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::exp10f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10f(x), 0.5); diff --git a/libc/test/src/math/exp10m1f_test.cpp b/libc/test/src/math/exp10m1f_test.cpp index aee273384f1a..01802bd68f7e 100644 --- a/libc/test/src/math/exp10m1f_test.cpp +++ b/libc/test/src/math/exp10m1f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10m1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -69,7 +69,7 @@ TEST_F(LlvmLibcExp10m1fTest, TrickyInputs) { }; for (float x : INPUTS) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10m1, x, LIBC_NAMESPACE::exp10m1f(x), 0.5); } @@ -82,14 +82,14 @@ TEST_F(LlvmLibcExp10m1fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_inf_or_nan()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::exp10m1f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_inf_or_nan() || LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_inf_or_nan() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10m1, x, LIBC_NAMESPACE::exp10m1f(x), 0.5); diff --git a/libc/test/src/math/exp2_test.cpp b/libc/test/src/math/exp2_test.cpp index adfceceeef4b..4cd95dd5486e 100644 --- a/libc/test/src/math/exp2_test.cpp +++ b/libc/test/src/math/exp2_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -80,7 +80,7 @@ TEST_F(LlvmLibcExp2Test, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::exp2(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/exp2f_test.cpp b/libc/test/src/math/exp2f_test.cpp index 0c4c82153439..aeecb3e74b07 100644 --- a/libc/test/src/math/exp2f_test.cpp +++ b/libc/test/src/math/exp2f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcExp2fTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcExp2fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::exp2f(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExp2fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp2fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::exp2f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -71,7 +71,7 @@ TEST_F(LlvmLibcExp2fTest, TrickyInputs) { 0xc3150000U, /*-0x1.2ap+7f*/ }; for (int i = 0; i < N; ++i) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float x = FPBits(INPUTS[i]).get_val(); EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, LIBC_NAMESPACE::exp2f(x), 0.5); @@ -80,7 +80,7 @@ TEST_F(LlvmLibcExp2fTest, TrickyInputs) { } TEST_F(LlvmLibcExp2fTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( 0.0f, LIBC_NAMESPACE::exp2f(FPBits(0xff7fffffU).get_val()), FE_UNDERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -108,15 +108,14 @@ TEST_F(LlvmLibcExp2fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::exp2f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, LIBC_NAMESPACE::exp2f(x), 0.5); diff --git a/libc/test/src/math/exp2m1f_test.cpp b/libc/test/src/math/exp2m1f_test.cpp index 793cf0cc2cbb..0c87657abc08 100644 --- a/libc/test/src/math/exp2m1f_test.cpp +++ b/libc/test/src/math/exp2m1f_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2m1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -38,7 +38,7 @@ TEST_F(LlvmLibcExp2m1fTest, TrickyInputs) { }; for (float x : INPUTS) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, LIBC_NAMESPACE::exp2m1f(x), 0.5); } @@ -51,15 +51,14 @@ TEST_F(LlvmLibcExp2m1fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::exp2m1f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, LIBC_NAMESPACE::exp2m1f(x), 0.5); diff --git a/libc/test/src/math/exp_test.cpp b/libc/test/src/math/exp_test.cpp index 0ab3a4e54346..83addaeb943d 100644 --- a/libc/test/src/math/exp_test.cpp +++ b/libc/test/src/math/exp_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -78,7 +78,7 @@ TEST_F(LlvmLibcExpTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::exp(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/expf_test.cpp b/libc/test/src/math/expf_test.cpp index 26a0bca4ce25..3c10812ff5bc 100644 --- a/libc/test/src/math/expf_test.cpp +++ b/libc/test/src/math/expf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcExpfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcExpfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::expf(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExpfTest, SpecialNumbers) { } TEST_F(LlvmLibcExpfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::expf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -55,7 +55,7 @@ TEST_F(LlvmLibcExpfTest, Overflow) { } TEST_F(LlvmLibcExpfTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( 0.0f, LIBC_NAMESPACE::expf(FPBits(0xff7fffffU).get_val()), FE_UNDERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -76,7 +76,7 @@ TEST_F(LlvmLibcExpfTest, Underflow) { TEST_F(LlvmLibcExpfTest, Borderline) { float x; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; x = FPBits(0x42affff8U).get_val(); ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x, LIBC_NAMESPACE::expf(x), 0.5); @@ -110,15 +110,14 @@ TEST_F(LlvmLibcExpfTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::expf(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x, LIBC_NAMESPACE::expf(x), 0.5); diff --git a/libc/test/src/math/expm1_test.cpp b/libc/test/src/math/expm1_test.cpp index 9720773d9f96..0cf07e2e4973 100644 --- a/libc/test/src/math/expm1_test.cpp +++ b/libc/test/src/math/expm1_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expm1.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -64,7 +64,7 @@ TEST_F(LlvmLibcExpm1Test, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::expm1(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/expm1f_test.cpp b/libc/test/src/math/expm1f_test.cpp index 274fe3bb7afb..cf3fe9c26ae1 100644 --- a/libc/test/src/math/expm1f_test.cpp +++ b/libc/test/src/math/expm1f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expm1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcExpm1fTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcExpm1fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::expm1f(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExpm1fTest, SpecialNumbers) { } TEST_F(LlvmLibcExpm1fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::expm1f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); @@ -55,7 +55,7 @@ TEST_F(LlvmLibcExpm1fTest, Overflow) { } TEST_F(LlvmLibcExpm1fTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(-1.0f, LIBC_NAMESPACE::expm1f(FPBits(0xff7fffffU).get_val())); float x = FPBits(0xc2cffff8U).get_val(); @@ -70,7 +70,7 @@ TEST_F(LlvmLibcExpm1fTest, Underflow) { TEST_F(LlvmLibcExpm1fTest, Borderline) { float x; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; x = FPBits(0x42affff8U).get_val(); ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Expm1, x, LIBC_NAMESPACE::expm1f(x), 0.5); @@ -119,15 +119,14 @@ TEST_F(LlvmLibcExpm1fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::expm1f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Expm1, x, LIBC_NAMESPACE::expm1f(x), 0.5); diff --git a/libc/test/src/math/log10_test.cpp b/libc/test/src/math/log10_test.cpp index 01aa1f82ae5d..e9529d87c388 100644 --- a/libc/test/src/math/log10_test.cpp +++ b/libc/test/src/math/log10_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log10.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -101,7 +101,7 @@ TEST_F(LlvmLibcLog10Test, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::log10(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/log1p_test.cpp b/libc/test/src/math/log1p_test.cpp index 107e965a0d3a..e5747b7e5ec0 100644 --- a/libc/test/src/math/log1p_test.cpp +++ b/libc/test/src/math/log1p_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log1p.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -102,7 +102,7 @@ TEST_F(LlvmLibcLog1pTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::log1p(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/log1pf_test.cpp b/libc/test/src/math/log1pf_test.cpp index bb181dc5e43b..ffe2dd2c33dd 100644 --- a/libc/test/src/math/log1pf_test.cpp +++ b/libc/test/src/math/log1pf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log1pf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -75,7 +75,7 @@ TEST_F(LlvmLibcLog1pfTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log1p, x, LIBC_NAMESPACE::log1pf(x), 0.5); } diff --git a/libc/test/src/math/log2_test.cpp b/libc/test/src/math/log2_test.cpp index 8a07991a6888..fc440c09b42b 100644 --- a/libc/test/src/math/log2_test.cpp +++ b/libc/test/src/math/log2_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log2.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -100,7 +100,7 @@ TEST_F(LlvmLibcLog2Test, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::log2(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/log2f_test.cpp b/libc/test/src/math/log2f_test.cpp index 83691fb75300..92226c763f45 100644 --- a/libc/test/src/math/log2f_test.cpp +++ b/libc/test/src/math/log2f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -52,14 +52,13 @@ TEST_F(LlvmLibcLog2fTest, InFloatRange) { float x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::log2f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (FPBits(result).is_nan() || FPBits(result).is_inf() || - LIBC_NAMESPACE::libc_errno != 0) + if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log2, x, LIBC_NAMESPACE::log2f(x), 0.5); diff --git a/libc/test/src/math/log_test.cpp b/libc/test/src/math/log_test.cpp index 969a469b2e1c..54afaa33d135 100644 --- a/libc/test/src/math/log_test.cpp +++ b/libc/test/src/math/log_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -99,7 +99,7 @@ TEST_F(LlvmLibcLogTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::log(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/powf_test.cpp b/libc/test/src/math/powf_test.cpp index 448dcc0035e9..4d189d813e58 100644 --- a/libc/test/src/math/powf_test.cpp +++ b/libc/test/src/math/powf_test.cpp @@ -78,7 +78,7 @@ TEST_F(LlvmLibcPowfTest, InFloatRange) { if (FPBits(w).is_nan() || FPBits(w).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float result = LIBC_NAMESPACE::powf(x, y); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/sin_test.cpp b/libc/test/src/math/sin_test.cpp index d4c6bd416a40..4d5d9ddf464b 100644 --- a/libc/test/src/math/sin_test.cpp +++ b/libc/test/src/math/sin_test.cpp @@ -71,7 +71,7 @@ TEST_F(LlvmLibcSinTest, InDoubleRange) { double x = FPBits(v).get_val(); if (FPBits(v).is_nan() || FPBits(v).is_inf()) continue; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; double result = LIBC_NAMESPACE::sin(x); ++cc; if (FPBits(result).is_nan() || FPBits(result).is_inf()) diff --git a/libc/test/src/math/sincosf_test.cpp b/libc/test/src/math/sincosf_test.cpp index 2823110331f3..ad2155f329cd 100644 --- a/libc/test/src/math/sincosf_test.cpp +++ b/libc/test/src/math/sincosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sincosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -24,7 +24,7 @@ using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcSinCosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float sin, cos; LIBC_NAMESPACE::sincosf(aNaN, &sin, &cos); diff --git a/libc/test/src/math/sinf_test.cpp b/libc/test/src/math/sinf_test.cpp index 8fd3ed1577ce..e0357e6157fd 100644 --- a/libc/test/src/math/sinf_test.cpp +++ b/libc/test/src/math/sinf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -24,7 +24,7 @@ using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcSinfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::sinf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/sinhf_test.cpp b/libc/test/src/math/sinhf_test.cpp index 6867c7aec57d..74f906ebaa98 100644 --- a/libc/test/src/math/sinhf_test.cpp +++ b/libc/test/src/math/sinhf_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -22,7 +22,7 @@ using LlvmLibcSinhfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcSinhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::sinhf(aNaN)); EXPECT_MATH_ERRNO(0); @@ -65,7 +65,7 @@ TEST_F(LlvmLibcSinhfTest, SmallValues) { } TEST_F(LlvmLibcSinhfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::sinhf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/sinpif_test.cpp b/libc/test/src/math/sinpif_test.cpp index d00fd77d288c..986c676761f0 100644 --- a/libc/test/src/math/sinpif_test.cpp +++ b/libc/test/src/math/sinpif_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinpif.h" #include "test/UnitTest/FPMatcher.h" #include "test/src/math/sdcomp26094.h" @@ -21,7 +21,7 @@ using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcSinpifTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::sinpif(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/FModTest.h b/libc/test/src/math/smoke/FModTest.h index 8fbcc2a27654..04cbc659ece5 100644 --- a/libc/test/src/math/smoke/FModTest.h +++ b/libc/test/src/math/smoke/FModTest.h @@ -10,7 +10,7 @@ #define LLVM_LIBC_TEST_SRC_MATH_FMODTEST_H #include "src/__support/FPUtil/FEnvImpl.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "test/UnitTest/FEnvSafeTest.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/RoundToIntegerTest.h b/libc/test/src/math/smoke/RoundToIntegerTest.h index 6ae97ce35a0d..745ccbc748ec 100644 --- a/libc/test/src/math/smoke/RoundToIntegerTest.h +++ b/libc/test/src/math/smoke/RoundToIntegerTest.h @@ -40,7 +40,7 @@ private: void test_one_input(RoundToIntegerFunc func, F input, I expected, bool expectError) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); ASSERT_EQ(func(input), expected); diff --git a/libc/test/src/math/smoke/acos_test.cpp b/libc/test/src/math/smoke/acos_test.cpp index 3a59bce26407..fe2caefb52ab 100644 --- a/libc/test/src/math/smoke/acos_test.cpp +++ b/libc/test/src/math/smoke/acos_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "hdr/fenv_macros.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acos.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ TEST_F(LlvmLibcAcosTest, SpecialNumbers) { EXPECT_FP_EQ(0x1.921fb54442d18p0, LIBC_NAMESPACE::acos(zero)); EXPECT_FP_EQ(0x1.921fb54442d18p0, LIBC_NAMESPACE::acos(neg_zero)); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acos(inf), FE_INVALID); EXPECT_MATH_ERRNO(EDOM); diff --git a/libc/test/src/math/smoke/acosf16_test.cpp b/libc/test/src/math/smoke/acosf16_test.cpp index c4274b824509..7103dc33fec3 100644 --- a/libc/test/src/math/smoke/acosf16_test.cpp +++ b/libc/test/src/math/smoke/acosf16_test.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acosf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcAcosf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcosf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::acosf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/acosf_test.cpp b/libc/test/src/math/smoke/acosf_test.cpp index 74f68e00011a..257c6a3d1d22 100644 --- a/libc/test/src/math/smoke/acosf_test.cpp +++ b/libc/test/src/math/smoke/acosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcAcosfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::acosf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/acoshf16_test.cpp b/libc/test/src/math/smoke/acoshf16_test.cpp index 7681c2a4e7fb..6b9c995cf992 100644 --- a/libc/test/src/math/smoke/acoshf16_test.cpp +++ b/libc/test/src/math/smoke/acoshf16_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acoshf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcAcoshf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcoshf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::acoshf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/acoshf_test.cpp b/libc/test/src/math/smoke/acoshf_test.cpp index c5ba88055ac5..b6abfab99929 100644 --- a/libc/test/src/math/smoke/acoshf_test.cpp +++ b/libc/test/src/math/smoke/acoshf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acoshf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcAcoshfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcoshfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::acoshf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/acospif16_test.cpp b/libc/test/src/math/smoke/acospif16_test.cpp index 66b94706eab9..4b2f6de3f7e3 100644 --- a/libc/test/src/math/smoke/acospif16_test.cpp +++ b/libc/test/src/math/smoke/acospif16_test.cpp @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/acospif16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" using LlvmLibcAcospif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAcospif16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::acospif16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/asinf16_test.cpp b/libc/test/src/math/smoke/asinf16_test.cpp index 9f675b08319c..b03f0a420a49 100644 --- a/libc/test/src/math/smoke/asinf16_test.cpp +++ b/libc/test/src/math/smoke/asinf16_test.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcAsinf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/asinf_test.cpp b/libc/test/src/math/smoke/asinf_test.cpp index d817d2b36619..2615a8ddd16b 100644 --- a/libc/test/src/math/smoke/asinf_test.cpp +++ b/libc/test/src/math/smoke/asinf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcAsinfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::asinf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/asinhf16_test.cpp b/libc/test/src/math/smoke/asinhf16_test.cpp index dcaab217331c..7f612ce3c467 100644 --- a/libc/test/src/math/smoke/asinhf16_test.cpp +++ b/libc/test/src/math/smoke/asinhf16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinhf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcAsinhf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinhf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinhf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/asinhf_test.cpp b/libc/test/src/math/smoke/asinhf_test.cpp index 4a8743c50075..d812a2dffe8a 100644 --- a/libc/test/src/math/smoke/asinhf_test.cpp +++ b/libc/test/src/math/smoke/asinhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/asinhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcAsinhfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::asinhf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/atan2f_test.cpp b/libc/test/src/math/smoke/atan2f_test.cpp index 1fbcfbe96b2d..7f8cfb9830d2 100644 --- a/libc/test/src/math/smoke/atan2f_test.cpp +++ b/libc/test/src/math/smoke/atan2f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atan2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcAtan2fTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtan2fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::atan2f(sNaN, sNaN), FE_INVALID); diff --git a/libc/test/src/math/smoke/atanf16_test.cpp b/libc/test/src/math/smoke/atanf16_test.cpp index af50287d9b22..ba1e3b2fc8be 100644 --- a/libc/test/src/math/smoke/atanf16_test.cpp +++ b/libc/test/src/math/smoke/atanf16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcAtanf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtanf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::atanf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/atanf_test.cpp b/libc/test/src/math/smoke/atanf_test.cpp index 7d09a28beaa3..b56b9d0162b9 100644 --- a/libc/test/src/math/smoke/atanf_test.cpp +++ b/libc/test/src/math/smoke/atanf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcAtanfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtanfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::atanf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/atanhf16_test.cpp b/libc/test/src/math/smoke/atanhf16_test.cpp index 81df6da8cee2..c2a520f7638f 100644 --- a/libc/test/src/math/smoke/atanhf16_test.cpp +++ b/libc/test/src/math/smoke/atanhf16_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanhf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcAtanhf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtanhf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/atanhf_test.cpp b/libc/test/src/math/smoke/atanhf_test.cpp index 73a5b81b0240..038cb30d89a4 100644 --- a/libc/test/src/math/smoke/atanhf_test.cpp +++ b/libc/test/src/math/smoke/atanhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/atanhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -20,7 +20,7 @@ using LIBC_NAMESPACE::Sign; using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::atanhf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); // TODO: Strengthen errno,exception checks and remove these assert macros diff --git a/libc/test/src/math/smoke/cosf16_test.cpp b/libc/test/src/math/smoke/cosf16_test.cpp index 2638551fb1d1..4362a5a3a4bd 100644 --- a/libc/test/src/math/smoke/cosf16_test.cpp +++ b/libc/test/src/math/smoke/cosf16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cosf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcCosf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCosf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::cosf16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/cosf_test.cpp b/libc/test/src/math/smoke/cosf_test.cpp index 99773583dcb1..470a876c63a7 100644 --- a/libc/test/src/math/smoke/cosf_test.cpp +++ b/libc/test/src/math/smoke/cosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcCosfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::cosf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/coshf16_test.cpp b/libc/test/src/math/smoke/coshf16_test.cpp index 08d05ecce86b..7bf62afa24c4 100644 --- a/libc/test/src/math/smoke/coshf16_test.cpp +++ b/libc/test/src/math/smoke/coshf16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/coshf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcCoshf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCoshf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::coshf16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcCoshf16Test, SpecialNumbers) { } TEST_F(LlvmLibcCoshf16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::coshf16(max_normal), FE_OVERFLOW | FE_INEXACT); diff --git a/libc/test/src/math/smoke/coshf_test.cpp b/libc/test/src/math/smoke/coshf_test.cpp index 1611ea1b9292..ee8f0199df3b 100644 --- a/libc/test/src/math/smoke/coshf_test.cpp +++ b/libc/test/src/math/smoke/coshf_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/coshf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -19,7 +19,7 @@ using LlvmLibcCoshfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCoshfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::coshf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -41,7 +41,7 @@ TEST_F(LlvmLibcCoshfTest, SpecialNumbers) { } TEST_F(LlvmLibcCoshfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::coshf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/cospif16_test.cpp b/libc/test/src/math/smoke/cospif16_test.cpp index edd8ed97b30f..fcde0cc79e35 100644 --- a/libc/test/src/math/smoke/cospif16_test.cpp +++ b/libc/test/src/math/smoke/cospif16_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cospif16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcCospif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCospif16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::cospif16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/cospif_test.cpp b/libc/test/src/math/smoke/cospif_test.cpp index 20153897dc45..3d48909cca93 100644 --- a/libc/test/src/math/smoke/cospif_test.cpp +++ b/libc/test/src/math/smoke/cospif_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/cospif.h" #include "test/UnitTest/FPMatcher.h" @@ -15,7 +15,7 @@ using LlvmLibcCospifTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcCospifTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::cospif(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/exp10_test.cpp b/libc/test/src/math/smoke/exp10_test.cpp index baf8a7681097..50d3de0c7fe7 100644 --- a/libc/test/src/math/smoke/exp10_test.cpp +++ b/libc/test/src/math/smoke/exp10_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/exp10f16_test.cpp b/libc/test/src/math/smoke/exp10f16_test.cpp index 1c4ef2aa08a7..bda40348f883 100644 --- a/libc/test/src/math/smoke/exp10f16_test.cpp +++ b/libc/test/src/math/smoke/exp10f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcExp10f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp10f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp10f16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExp10f16Test, SpecialNumbers) { } TEST_F(LlvmLibcExp10f16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp10f16(max_normal), FE_OVERFLOW); @@ -53,7 +53,7 @@ TEST_F(LlvmLibcExp10f16Test, Overflow) { } TEST_F(LlvmLibcExp10f16Test, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(zero, LIBC_NAMESPACE::exp10f16(neg_max_normal), FE_UNDERFLOW | FE_INEXACT); diff --git a/libc/test/src/math/smoke/exp10f_test.cpp b/libc/test/src/math/smoke/exp10f_test.cpp index bf39e2cc12d0..fcd334bb9e36 100644 --- a/libc/test/src/math/smoke/exp10f_test.cpp +++ b/libc/test/src/math/smoke/exp10f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcExp10fTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp10fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp10f(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -44,7 +44,7 @@ TEST_F(LlvmLibcExp10fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp10fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::exp10f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/exp10m1f16_test.cpp b/libc/test/src/math/smoke/exp10m1f16_test.cpp index dfa7fa477d3d..ed2d5a48b316 100644 --- a/libc/test/src/math/smoke/exp10m1f16_test.cpp +++ b/libc/test/src/math/smoke/exp10m1f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10m1f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcExp10m1f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp10m1f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp10m1f16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExp10m1f16Test, SpecialNumbers) { } TEST_F(LlvmLibcExp10m1f16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp10m1f16(max_normal), FE_OVERFLOW | FE_INEXACT); @@ -67,7 +67,7 @@ TEST_F(LlvmLibcExp10m1f16Test, Overflow) { } TEST_F(LlvmLibcExp10m1f16Test, ResultNearNegOne) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::exp10m1f16(neg_max_normal), diff --git a/libc/test/src/math/smoke/exp10m1f_test.cpp b/libc/test/src/math/smoke/exp10m1f_test.cpp index 2c2cfdbb08a3..19369a897aaa 100644 --- a/libc/test/src/math/smoke/exp10m1f_test.cpp +++ b/libc/test/src/math/smoke/exp10m1f_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp10m1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcExp10m1fTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp10m1fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp10m1f(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -34,7 +34,7 @@ TEST_F(LlvmLibcExp10m1fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp10m1fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp10m1f(0x1.fffffep+127f), FE_OVERFLOW); @@ -50,7 +50,7 @@ TEST_F(LlvmLibcExp10m1fTest, Overflow) { } TEST_F(LlvmLibcExp10m1fTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(-1.0f, LIBC_NAMESPACE::exp10m1f(-max_normal), FE_UNDERFLOW); diff --git a/libc/test/src/math/smoke/exp2_test.cpp b/libc/test/src/math/smoke/exp2_test.cpp index 9ab9129416da..aebf80835072 100644 --- a/libc/test/src/math/smoke/exp2_test.cpp +++ b/libc/test/src/math/smoke/exp2_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/exp2f16_test.cpp b/libc/test/src/math/smoke/exp2f16_test.cpp index f69b33a3cf37..1eb7343dcd22 100644 --- a/libc/test/src/math/smoke/exp2f16_test.cpp +++ b/libc/test/src/math/smoke/exp2f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcExp2f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp2f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2f16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExp2f16Test, SpecialNumbers) { } TEST_F(LlvmLibcExp2f16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2f16(max_normal), FE_OVERFLOW); @@ -53,7 +53,7 @@ TEST_F(LlvmLibcExp2f16Test, Overflow) { } TEST_F(LlvmLibcExp2f16Test, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(zero, LIBC_NAMESPACE::exp2f16(neg_max_normal), FE_UNDERFLOW | FE_INEXACT); diff --git a/libc/test/src/math/smoke/exp2f_test.cpp b/libc/test/src/math/smoke/exp2f_test.cpp index a928389cc41b..c5243273d9ed 100644 --- a/libc/test/src/math/smoke/exp2f_test.cpp +++ b/libc/test/src/math/smoke/exp2f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcExp2fTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp2fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp2f(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -45,7 +45,7 @@ TEST_F(LlvmLibcExp2fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp2fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::exp2f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/exp2m1f16_test.cpp b/libc/test/src/math/smoke/exp2m1f16_test.cpp index f423196a7036..635b7a6e187d 100644 --- a/libc/test/src/math/smoke/exp2m1f16_test.cpp +++ b/libc/test/src/math/smoke/exp2m1f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2m1f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcExp2m1f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExp2m1f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2m1f16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -39,7 +39,7 @@ TEST_F(LlvmLibcExp2m1f16Test, SpecialNumbers) { } TEST_F(LlvmLibcExp2m1f16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f16(max_normal), FE_OVERFLOW | FE_INEXACT); @@ -65,7 +65,7 @@ TEST_F(LlvmLibcExp2m1f16Test, Overflow) { } TEST_F(LlvmLibcExp2m1f16Test, ResultNearNegOne) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(-1.0, LIBC_NAMESPACE::exp2m1f16(neg_max_normal), FE_INEXACT); diff --git a/libc/test/src/math/smoke/exp2m1f_test.cpp b/libc/test/src/math/smoke/exp2m1f_test.cpp index 99bdf0035df0..63852e11655a 100644 --- a/libc/test/src/math/smoke/exp2m1f_test.cpp +++ b/libc/test/src/math/smoke/exp2m1f_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp2m1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LIBC_NAMESPACE::fputil::testing::ForceRoundingMode; using LIBC_NAMESPACE::fputil::testing::RoundingMode; TEST_F(LlvmLibcExp2m1fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp2m1f(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -34,7 +34,7 @@ TEST_F(LlvmLibcExp2m1fTest, SpecialNumbers) { } TEST_F(LlvmLibcExp2m1fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f(0x1.fffffep+127), FE_OVERFLOW); @@ -50,7 +50,7 @@ TEST_F(LlvmLibcExp2m1fTest, Overflow) { } TEST_F(LlvmLibcExp2m1fTest, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(-1.0f, LIBC_NAMESPACE::exp2m1f(-0x1.fffffep+127), FE_UNDERFLOW); diff --git a/libc/test/src/math/smoke/exp_test.cpp b/libc/test/src/math/smoke/exp_test.cpp index f86243092f1f..c3b2ae70e1d9 100644 --- a/libc/test/src/math/smoke/exp_test.cpp +++ b/libc/test/src/math/smoke/exp_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/exp.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/expf16_test.cpp b/libc/test/src/math/smoke/expf16_test.cpp index ab745a3cf6f5..863f694ffc41 100644 --- a/libc/test/src/math/smoke/expf16_test.cpp +++ b/libc/test/src/math/smoke/expf16_test.cpp @@ -9,7 +9,7 @@ #include "hdr/errno_macros.h" #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -17,7 +17,7 @@ using LlvmLibcExpf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExpf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::expf16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -41,7 +41,7 @@ TEST_F(LlvmLibcExpf16Test, SpecialNumbers) { } TEST_F(LlvmLibcExpf16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::expf16(max_normal), FE_OVERFLOW); @@ -54,7 +54,7 @@ TEST_F(LlvmLibcExpf16Test, Overflow) { } TEST_F(LlvmLibcExpf16Test, Underflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(zero, LIBC_NAMESPACE::expf16(neg_max_normal), FE_UNDERFLOW | FE_INEXACT); diff --git a/libc/test/src/math/smoke/expf_test.cpp b/libc/test/src/math/smoke/expf_test.cpp index eee830499927..d34151735afa 100644 --- a/libc/test/src/math/smoke/expf_test.cpp +++ b/libc/test/src/math/smoke/expf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcExpfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExpfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::expf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExpfTest, SpecialNumbers) { } TEST_F(LlvmLibcExpfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::expf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/expm1_test.cpp b/libc/test/src/math/smoke/expm1_test.cpp index bc71c53abc7a..c842fe3c45fe 100644 --- a/libc/test/src/math/smoke/expm1_test.cpp +++ b/libc/test/src/math/smoke/expm1_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expm1.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/expm1f16_test.cpp b/libc/test/src/math/smoke/expm1f16_test.cpp index f297c5dfc3c7..4d19a9bac5eb 100644 --- a/libc/test/src/math/smoke/expm1f16_test.cpp +++ b/libc/test/src/math/smoke/expm1f16_test.cpp @@ -9,7 +9,7 @@ #include "hdr/errno_macros.h" #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expm1f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -17,7 +17,7 @@ using LlvmLibcExpm1f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExpm1f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::expm1f16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExpm1f16Test, SpecialNumbers) { } TEST_F(LlvmLibcExpm1f16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::expm1f16(max_normal), FE_OVERFLOW | FE_INEXACT); @@ -67,7 +67,7 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) { } TEST_F(LlvmLibcExpm1f16Test, ResultNearNegOne) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(neg_max_normal), diff --git a/libc/test/src/math/smoke/expm1f_test.cpp b/libc/test/src/math/smoke/expm1f_test.cpp index dfb474d70fb6..214bfe8abd4d 100644 --- a/libc/test/src/math/smoke/expm1f_test.cpp +++ b/libc/test/src/math/smoke/expm1f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/expm1f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcExpm1fTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcExpm1fTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::expm1f(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcExpm1fTest, SpecialNumbers) { } TEST_F(LlvmLibcExpm1fTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::expm1f(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/log10_test.cpp b/libc/test/src/math/smoke/log10_test.cpp index ff73850c5210..49cfda85111a 100644 --- a/libc/test/src/math/smoke/log10_test.cpp +++ b/libc/test/src/math/smoke/log10_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log10.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/log10f16_test.cpp b/libc/test/src/math/smoke/log10f16_test.cpp index 471e19893332..53f5ac46aa60 100644 --- a/libc/test/src/math/smoke/log10f16_test.cpp +++ b/libc/test/src/math/smoke/log10f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log10f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcLog10f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcLog10f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::log10f16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/log1p_test.cpp b/libc/test/src/math/smoke/log1p_test.cpp index 631c24b8abcf..61c56cd2c6dd 100644 --- a/libc/test/src/math/smoke/log1p_test.cpp +++ b/libc/test/src/math/smoke/log1p_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log1p.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/log1pf_test.cpp b/libc/test/src/math/smoke/log1pf_test.cpp index bd828ad58c4c..dc3489fddf99 100644 --- a/libc/test/src/math/smoke/log1pf_test.cpp +++ b/libc/test/src/math/smoke/log1pf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log1pf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/log2_test.cpp b/libc/test/src/math/smoke/log2_test.cpp index 9993d442967c..0534d00b1f40 100644 --- a/libc/test/src/math/smoke/log2_test.cpp +++ b/libc/test/src/math/smoke/log2_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log2.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/log2f16_test.cpp b/libc/test/src/math/smoke/log2f16_test.cpp index 6d98482aa449..fd20652d2f00 100644 --- a/libc/test/src/math/smoke/log2f16_test.cpp +++ b/libc/test/src/math/smoke/log2f16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log2f16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcLog2f16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcLog2f16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::log2f16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/log2f_test.cpp b/libc/test/src/math/smoke/log2f_test.cpp index 8648b75b88b8..53d54ac36763 100644 --- a/libc/test/src/math/smoke/log2f_test.cpp +++ b/libc/test/src/math/smoke/log2f_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/log_test.cpp b/libc/test/src/math/smoke/log_test.cpp index d31eb0c1db73..09e9ab0a9a4d 100644 --- a/libc/test/src/math/smoke/log_test.cpp +++ b/libc/test/src/math/smoke/log_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/log.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/math/smoke/logf16_test.cpp b/libc/test/src/math/smoke/logf16_test.cpp index c7232aa1c1e3..2784f3d5fa54 100644 --- a/libc/test/src/math/smoke/logf16_test.cpp +++ b/libc/test/src/math/smoke/logf16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/logf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcLogf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcLogf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::logf16(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/sincosf_test.cpp b/libc/test/src/math/smoke/sincosf_test.cpp index 5f66868f12a1..8ba0d04347bb 100644 --- a/libc/test/src/math/smoke/sincosf_test.cpp +++ b/libc/test/src/math/smoke/sincosf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sincosf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcSinCosfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinCosfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; float sin, cos; LIBC_NAMESPACE::sincosf(sNaN, &sin, &cos); diff --git a/libc/test/src/math/smoke/sinf16_test.cpp b/libc/test/src/math/smoke/sinf16_test.cpp index a0e7a7ba321f..6b168ac040db 100644 --- a/libc/test/src/math/smoke/sinf16_test.cpp +++ b/libc/test/src/math/smoke/sinf16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcSinf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::sinf16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/sinf_test.cpp b/libc/test/src/math/smoke/sinf_test.cpp index de504b4f5335..8173969fb256 100644 --- a/libc/test/src/math/smoke/sinf_test.cpp +++ b/libc/test/src/math/smoke/sinf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcSinfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::sinf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/sinhf16_test.cpp b/libc/test/src/math/smoke/sinhf16_test.cpp index 4f21d33ba78e..d52739a9adb3 100644 --- a/libc/test/src/math/smoke/sinhf16_test.cpp +++ b/libc/test/src/math/smoke/sinhf16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinhf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcSinhf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinhf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::sinhf16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -38,7 +38,7 @@ TEST_F(LlvmLibcSinhf16Test, SpecialNumbers) { } TEST_F(LlvmLibcSinhf16Test, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::sinhf16(max_normal), FE_OVERFLOW | FE_INEXACT); diff --git a/libc/test/src/math/smoke/sinhf_test.cpp b/libc/test/src/math/smoke/sinhf_test.cpp index e22cfc7ea14d..ea6a4474a780 100644 --- a/libc/test/src/math/smoke/sinhf_test.cpp +++ b/libc/test/src/math/smoke/sinhf_test.cpp @@ -9,7 +9,7 @@ #include "hdr/math_macros.h" #include "src/__support/CPP/array.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -19,7 +19,7 @@ using LlvmLibcSinhfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::sinhf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); @@ -52,7 +52,7 @@ TEST_F(LlvmLibcSinhfTest, SmallValues) { } TEST_F(LlvmLibcSinhfTest, Overflow) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION( inf, LIBC_NAMESPACE::sinhf(FPBits(0x7f7fffffU).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); diff --git a/libc/test/src/math/smoke/sinpif16_test.cpp b/libc/test/src/math/smoke/sinpif16_test.cpp index b2db6fb9f862..9edf2cc663d4 100644 --- a/libc/test/src/math/smoke/sinpif16_test.cpp +++ b/libc/test/src/math/smoke/sinpif16_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinpif16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcSinpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinpif16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::sinpif16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/sinpif_test.cpp b/libc/test/src/math/smoke/sinpif_test.cpp index 1ba5c1d2b720..b840f3980eda 100644 --- a/libc/test/src/math/smoke/sinpif_test.cpp +++ b/libc/test/src/math/smoke/sinpif_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/sinpif.h" #include "test/UnitTest/FPMatcher.h" @@ -15,7 +15,7 @@ using LlvmLibcSinpifTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcSinpifTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::sinpif(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/tanf16_test.cpp b/libc/test/src/math/smoke/tanf16_test.cpp index f65b9fced72c..95d200cf5591 100644 --- a/libc/test/src/math/smoke/tanf16_test.cpp +++ b/libc/test/src/math/smoke/tanf16_test.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -15,7 +15,7 @@ using LlvmLibcTanf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcTanf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanf16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/tanf_test.cpp b/libc/test/src/math/smoke/tanf_test.cpp index 178e9065f430..12deca5cf941 100644 --- a/libc/test/src/math/smoke/tanf_test.cpp +++ b/libc/test/src/math/smoke/tanf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcTanfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcTanfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/tanhf16_test.cpp b/libc/test/src/math/smoke/tanhf16_test.cpp index fa6328e9ef0a..eb90f02a8d7c 100644 --- a/libc/test/src/math/smoke/tanhf16_test.cpp +++ b/libc/test/src/math/smoke/tanhf16_test.cpp @@ -8,7 +8,7 @@ #include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanhf16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -16,7 +16,7 @@ using LlvmLibcTanhf16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcTanhf16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tanhf16(aNaN)); EXPECT_MATH_ERRNO(0); @@ -40,7 +40,7 @@ TEST_F(LlvmLibcTanhf16Test, SpecialNumbers) { } TEST_F(LlvmLibcTanhf16Test, ResultNearBounds) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast(1.0), LIBC_NAMESPACE::tanhf16(max_normal), FE_INEXACT); diff --git a/libc/test/src/math/smoke/tanhf_test.cpp b/libc/test/src/math/smoke/tanhf_test.cpp index c09761ef531f..b12a331b3190 100644 --- a/libc/test/src/math/smoke/tanhf_test.cpp +++ b/libc/test/src/math/smoke/tanhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -18,7 +18,7 @@ using LlvmLibcTanhfTest = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcTanhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanhf(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/smoke/tanpif16_test.cpp b/libc/test/src/math/smoke/tanpif16_test.cpp index 74797d1649b1..ea896d7bb3e5 100644 --- a/libc/test/src/math/smoke/tanpif16_test.cpp +++ b/libc/test/src/math/smoke/tanpif16_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanpif16.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -14,7 +14,7 @@ using LlvmLibcTanpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcTanpif16Test, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanpif16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/tanf_test.cpp b/libc/test/src/math/tanf_test.cpp index 9061cf6fb30b..ecc70194b649 100644 --- a/libc/test/src/math/tanf_test.cpp +++ b/libc/test/src/math/tanf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -24,7 +24,7 @@ using LIBC_NAMESPACE::testing::SDCOMP26094_VALUES; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcTanfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/math/tanhf_test.cpp b/libc/test/src/math/tanhf_test.cpp index 389abe4d8589..966ce649e2b3 100644 --- a/libc/test/src/math/tanhf_test.cpp +++ b/libc/test/src/math/tanhf_test.cpp @@ -8,7 +8,7 @@ #include "hdr/math_macros.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/math/tanhf.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ using LlvmLibcTanhfTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcTanhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanhf(aNaN)); EXPECT_MATH_ERRNO(0); diff --git a/libc/test/src/poll/poll_test.cpp b/libc/test/src/poll/poll_test.cpp index 30f5e41c61ec..97b7b0271817 100644 --- a/libc/test/src/poll/poll_test.cpp +++ b/libc/test/src/poll/poll_test.cpp @@ -7,18 +7,18 @@ //===----------------------------------------------------------------------===// #include "hdr/limits_macros.h" // UINT_MAX -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/poll/poll.h" #include "test/UnitTest/Test.h" TEST(LlvmLibcPollTest, SmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; int ret = LIBC_NAMESPACE::poll(nullptr, 0, 0); ASSERT_ERRNO_SUCCESS(); ASSERT_EQ(0, ret); } TEST(LlvmLibcPollTest, SmokeFailureTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; int ret = LIBC_NAMESPACE::poll(nullptr, UINT_MAX, 0); ASSERT_ERRNO_EQ(EINVAL); ASSERT_EQ(-1, ret); diff --git a/libc/test/src/sched/affinity_test.cpp b/libc/test/src/sched/affinity_test.cpp index b5085203e5ce..b77f22f8e60d 100644 --- a/libc/test/src/sched/affinity_test.cpp +++ b/libc/test/src/sched/affinity_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/OSUtil/syscall.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_getaffinity.h" #include "src/sched/sched_setaffinity.h" #include "test/UnitTest/ErrnoSetterMatcher.h" @@ -17,7 +17,7 @@ TEST(LlvmLibcSchedAffinityTest, SmokeTest) { cpu_set_t mask; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; pid_t tid = LIBC_NAMESPACE::syscall_impl(SYS_gettid); ASSERT_GT(tid, pid_t(0)); @@ -32,15 +32,15 @@ TEST(LlvmLibcSchedAffinityTest, BadMask) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; pid_t tid = LIBC_NAMESPACE::syscall_impl(SYS_gettid); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT( LIBC_NAMESPACE::sched_getaffinity(tid, sizeof(cpu_set_t), nullptr), Fails(EFAULT)); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT( LIBC_NAMESPACE::sched_setaffinity(tid, sizeof(cpu_set_t), nullptr), Fails(EFAULT)); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } diff --git a/libc/test/src/sched/cpu_count_test.cpp b/libc/test/src/sched/cpu_count_test.cpp index 5250368a2616..919f1475e1d4 100644 --- a/libc/test/src/sched/cpu_count_test.cpp +++ b/libc/test/src/sched/cpu_count_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/OSUtil/syscall.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_getaffinity.h" #include "src/sched/sched_getcpucount.h" #include "test/UnitTest/ErrnoSetterMatcher.h" @@ -17,7 +17,7 @@ TEST(LlvmLibcSchedCpuCountTest, SmokeTest) { cpu_set_t mask; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; pid_t tid = LIBC_NAMESPACE::syscall_impl(SYS_gettid); ASSERT_GT(tid, pid_t(0)); diff --git a/libc/test/src/sched/get_priority_test.cpp b/libc/test/src/sched/get_priority_test.cpp index 59205c51e4a1..bb41dc0be201 100644 --- a/libc/test/src/sched/get_priority_test.cpp +++ b/libc/test/src/sched/get_priority_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_get_priority_max.h" #include "src/sched/sched_get_priority_min.h" #include "test/UnitTest/Test.h" @@ -58,7 +58,7 @@ TEST(LlvmLibcSchedGetPriorityTest, HandleBadPolicyTest) { } TEST(LlvmLibcSchedGetPriorityTest, SmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // We Test: // SCHED_OTHER, SCHED_FIFO, SCHED_RR diff --git a/libc/test/src/sched/param_and_scheduler_test.cpp b/libc/test/src/sched/param_and_scheduler_test.cpp index 747c7e3409e4..4f2b6e412a4b 100644 --- a/libc/test/src/sched/param_and_scheduler_test.cpp +++ b/libc/test/src/sched/param_and_scheduler_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_get_priority_max.h" #include "src/sched/sched_get_priority_min.h" #include "src/sched/sched_getparam.h" @@ -37,7 +37,7 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { public: void testSched(int policy, bool is_mandatory) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; int init_policy = LIBC_NAMESPACE::sched_getscheduler(0); ASSERT_GE(init_policy, 0); @@ -55,30 +55,29 @@ public: // Negative pid ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(-1, policy, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(-1), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // Invalid Policy ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy | 128, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // Out of bounds priority param.sched_priority = min_priority - 1; ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; param.sched_priority = max_priority + 1; ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, ¶m), -1); // A bit hard to test as depending on user privileges we can run into // different issues. - ASSERT_TRUE(LIBC_NAMESPACE::libc_errno == EINVAL || - LIBC_NAMESPACE::libc_errno == EPERM); - LIBC_NAMESPACE::libc_errno = 0; + ASSERT_TRUE(libc_errno == EINVAL || libc_errno == EPERM); + libc_errno = 0; param.sched_priority = min_priority; // Success/unsupported policy/missing permissions. @@ -87,10 +86,9 @@ public: ASSERT_TRUE(setscheduler_result == 0 || setscheduler_result == -1); ASSERT_TRUE( setscheduler_result != -1 - ? (LIBC_NAMESPACE::libc_errno == 0) - : ((!is_mandatory && LIBC_NAMESPACE::libc_errno == EINVAL) || - LIBC_NAMESPACE::libc_errno == EPERM)); - LIBC_NAMESPACE::libc_errno = 0; + ? (libc_errno == 0) + : ((!is_mandatory && libc_errno == EINVAL) || libc_errno == EPERM)); + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(0), setscheduler_result != -1 ? policy : init_policy); @@ -100,12 +98,12 @@ public: param.sched_priority = -1; ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; param.sched_priority = max_priority + 1; ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; for (int priority = min_priority; priority <= max_priority; ++priority) { ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, ¶m), 0); @@ -117,21 +115,20 @@ public: // Negative pid ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(-1, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(-1, ¶m), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // Success/unsupported policy/missing permissions int setparam_result = LIBC_NAMESPACE::sched_setparam(0, ¶m); ASSERT_TRUE(setparam_result == 0 || setparam_result == -1); ASSERT_TRUE(setparam_result != -1 - ? (LIBC_NAMESPACE::libc_errno == 0) - : ((setscheduler_result == -1 && - LIBC_NAMESPACE::libc_errno == EINVAL) || - LIBC_NAMESPACE::libc_errno == EPERM)); - LIBC_NAMESPACE::libc_errno = 0; + ? (libc_errno == 0) + : ((setscheduler_result == -1 && libc_errno == EINVAL) || + libc_errno == EPERM)); + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, ¶m), 0); ASSERT_ERRNO_SUCCESS(); @@ -143,7 +140,7 @@ public: // Null test ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, nullptr), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } }; @@ -161,13 +158,13 @@ LIST_SCHED_TESTS(SCHED_BATCH, true) LIST_SCHED_TESTS(SCHED_IDLE, true) TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, nullptr), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, nullptr), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } diff --git a/libc/test/src/sched/sched_rr_get_interval_test.cpp b/libc/test/src/sched/sched_rr_get_interval_test.cpp index c22a2c76d743..a0fe5edbe014 100644 --- a/libc/test/src/sched/sched_rr_get_interval_test.cpp +++ b/libc/test/src/sched/sched_rr_get_interval_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_get_priority_min.h" #include "src/sched/sched_getscheduler.h" #include "src/sched/sched_rr_get_interval.h" @@ -17,7 +17,7 @@ #include TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; auto SetSched = [&](int policy) { int min_priority = LIBC_NAMESPACE::sched_get_priority_min(policy); ASSERT_GE(min_priority, 0); @@ -58,19 +58,19 @@ TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) { // Null timespec ASSERT_EQ(LIBC_NAMESPACE::sched_rr_get_interval(0, nullptr), -1); ASSERT_ERRNO_EQ(EFAULT); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // Negative pid ASSERT_EQ(LIBC_NAMESPACE::sched_rr_get_interval(-1, &ts), -1); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; } // Negative tests don't have SCHED_RR set SetSched(SCHED_OTHER); ASSERT_EQ(LIBC_NAMESPACE::sched_rr_get_interval(0, &ts), 0); ASSERT_ERRNO_SUCCESS(); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // TODO: Missing unkown pid -> ESRCH. This is read only so safe to try a few // unlikely values. diff --git a/libc/test/src/sched/yield_test.cpp b/libc/test/src/sched/yield_test.cpp index f1627a71fa9a..4d13d50e25eb 100644 --- a/libc/test/src/sched/yield_test.cpp +++ b/libc/test/src/sched/yield_test.cpp @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sched/sched_yield.h" #include "test/UnitTest/Test.h" TEST(LlvmLibcSchedYieldTest, SmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; // sched_yield() always succeeds, just do a basic test that errno/ret are // properly 0. ASSERT_EQ(LIBC_NAMESPACE::sched_yield(), 0); diff --git a/libc/test/src/signal/sigaltstack_test.cpp b/libc/test/src/signal/sigaltstack_test.cpp index cc392da8f473..ce4dfddae248 100644 --- a/libc/test/src/signal/sigaltstack_test.cpp +++ b/libc/test/src/signal/sigaltstack_test.cpp @@ -8,7 +8,7 @@ #include "hdr/signal_macros.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include "src/signal/raise.h" #include "src/signal/sigaction.h" @@ -46,7 +46,7 @@ static void handler(int) { TEST(LlvmLibcSignalTest, SigaltstackRunOnAltStack) { struct sigaction action; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds(0)); action.sa_handler = handler; diff --git a/libc/test/src/signal/signal_test.cpp b/libc/test/src/signal/signal_test.cpp index bac9c3b8b68b..62b86bf44029 100644 --- a/libc/test/src/signal/signal_test.cpp +++ b/libc/test/src/signal/signal_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/signal/raise.h" #include "src/signal/signal.h" @@ -17,7 +17,7 @@ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; TEST(LlvmLibcSignal, Invalid) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; auto *valid = +[](int) {}; EXPECT_THAT((void *)LIBC_NAMESPACE::signal(0, valid), Fails(EINVAL, (void *)SIG_ERR)); diff --git a/libc/test/src/signal/sigprocmask_test.cpp b/libc/test/src/signal/sigprocmask_test.cpp index 12403f68b593..891eac0f5bf7 100644 --- a/libc/test/src/signal/sigprocmask_test.cpp +++ b/libc/test/src/signal/sigprocmask_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/signal/raise.h" #include "src/signal/sigaddset.h" #include "src/signal/sigemptyset.h" @@ -33,7 +33,7 @@ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; // This tests for invalid input. TEST_F(LlvmLibcSignalTest, SigprocmaskInvalid) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; sigset_t valid; // 17 and -4 are out of the range for sigprocmask's how paramater. diff --git a/libc/test/src/spawn/posix_spawn_file_actions_test.cpp b/libc/test/src/spawn/posix_spawn_file_actions_test.cpp index c1edf56bdbd8..01ccb8218ee2 100644 --- a/libc/test/src/spawn/posix_spawn_file_actions_test.cpp +++ b/libc/test/src/spawn/posix_spawn_file_actions_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/spawn/file_actions.h" #include "src/spawn/posix_spawn_file_actions_addclose.h" #include "src/spawn/posix_spawn_file_actions_adddup2.h" diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index 01904a30504e..4aa8b9588001 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -20,6 +20,7 @@ add_libc_test( libc.src.stdio.fread libc.src.stdio.fseek libc.src.stdio.fwrite + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( @@ -68,6 +69,7 @@ add_libc_test( libc.src.stdio.fread libc.src.stdio.fwrite libc.src.stdio.setvbuf + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( @@ -88,6 +90,7 @@ add_libc_test( libc.src.stdio.fread_unlocked libc.src.stdio.funlockfile libc.src.stdio.fwrite_unlocked + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( @@ -109,6 +112,7 @@ add_libc_test( libc.src.stdio.fread libc.src.stdio.fseek libc.src.stdio.fwrite + libc.test.UnitTest.ErrnoCheckingTest LINK_LIBRARIES LibcMemoryHelpers ) @@ -357,6 +361,18 @@ add_libc_test( libc.src.stdio.puts ) +add_libc_test( + perror_test + HERMETIC_TEST_ONLY # writes to libc's stderr + SUITE + libc_stdio_unittests + SRCS + perror_test.cpp + DEPENDS + libc.src.stdio.perror + libc.src.errno.errno +) + add_libc_test( fputs_test HERMETIC_TEST_ONLY # writes to libc's stdout and stderr @@ -426,6 +442,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux") libc.src.sys.stat.mkdirat libc.src.unistd.access libc.src.unistd.close + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( @@ -440,6 +457,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux") libc.src.stdio.rename libc.src.unistd.access libc.src.unistd.close + libc.test.UnitTest.ErrnoCheckingTest libc.test.UnitTest.ErrnoSetterMatcher ) @@ -456,6 +474,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux") libc.src.stdio.fgets libc.src.stdio.fputs libc.src.unistd.close + libc.test.UnitTest.ErrnoCheckingTest libc.test.UnitTest.ErrnoSetterMatcher ) endif() @@ -476,6 +495,8 @@ add_libc_test( libc.src.stdio.fopen libc.src.stdio.fwrite libc.src.stdio.getc + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher ) add_libc_test( @@ -498,6 +519,8 @@ add_libc_test( libc.src.stdio.funlockfile libc.src.stdio.fwrite libc.src.stdio.getc_unlocked + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher ) add_libc_test( @@ -515,6 +538,8 @@ add_libc_test( libc.src.stdio.fgets libc.src.stdio.fopen libc.src.stdio.fwrite + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher ) add_libc_test( diff --git a/libc/test/src/stdio/fdopen_test.cpp b/libc/test/src/stdio/fdopen_test.cpp index ef36cff2ffbd..b53184c30be3 100644 --- a/libc/test/src/stdio/fdopen_test.cpp +++ b/libc/test/src/stdio/fdopen_test.cpp @@ -9,20 +9,21 @@ #include "src/stdio/fdopen.h" #include "hdr/fcntl_macros.h" -#include "src/errno/libc_errno.h" #include "src/fcntl/open.h" #include "src/stdio/fclose.h" #include "src/stdio/fgets.h" #include "src/stdio/fputs.h" #include "src/unistd/close.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" #include // For S_IRWXU -TEST(LlvmLibcStdioFdopenTest, WriteAppendRead) { +using LlvmLibcStdioFdopenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcStdioFdopenTest, WriteAppendRead) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; - LIBC_NAMESPACE::libc_errno = 0; constexpr const char *TEST_FILE_NAME = "testdata/write_read_append.test"; auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME); int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); @@ -52,8 +53,7 @@ TEST(LlvmLibcStdioFdopenTest, WriteAppendRead) { ASSERT_ERRNO_SUCCESS(); } -TEST(LlvmLibcStdioFdopenTest, InvalidFd) { - LIBC_NAMESPACE::libc_errno = 0; +TEST_F(LlvmLibcStdioFdopenTest, InvalidFd) { constexpr const char *TEST_FILE_NAME = "testdata/invalid_fd.test"; auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME); int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC); @@ -64,8 +64,7 @@ TEST(LlvmLibcStdioFdopenTest, InvalidFd) { ASSERT_TRUE(nullptr == fp); } -TEST(LlvmLibcStdioFdopenTest, InvalidMode) { - LIBC_NAMESPACE::libc_errno = 0; +TEST_F(LlvmLibcStdioFdopenTest, InvalidMode) { constexpr const char *TEST_FILE_NAME = "testdata/invalid_mode.test"; auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME); int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_RDONLY, S_IRWXU); @@ -83,7 +82,6 @@ TEST(LlvmLibcStdioFdopenTest, InvalidMode) { auto *fp2 = LIBC_NAMESPACE::fdopen(fd, "w"); ASSERT_ERRNO_EQ(EINVAL); ASSERT_TRUE(nullptr == fp2); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::close(fd); ASSERT_ERRNO_SUCCESS(); } diff --git a/libc/test/src/stdio/fgetc_test.cpp b/libc/test/src/stdio/fgetc_test.cpp index 2cc8436bd66f..be2e50271b51 100644 --- a/libc/test/src/stdio/fgetc_test.cpp +++ b/libc/test/src/stdio/fgetc_test.cpp @@ -14,12 +14,15 @@ #include "src/stdio/fopen.h" #include "src/stdio/fwrite.h" #include "src/stdio/getc.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" #include "hdr/stdio_macros.h" -#include "src/errno/libc_errno.h" -class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::Test { +using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; + +class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { public: using GetcFunc = int(FILE *); void test_with_func(GetcFunc *func, const char *filename) { @@ -27,29 +30,28 @@ public: ASSERT_FALSE(file == nullptr); constexpr char CONTENT[] = "123456789"; constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1; - ASSERT_EQ(WRITE_SIZE, LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file)); + ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file), + Succeeds(WRITE_SIZE)); // This is a write-only file so reads should fail. - ASSERT_EQ(func(file), EOF); + ASSERT_THAT(func(file), Fails(EBADF, EOF)); // This is an error and not a real EOF. ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); file = LIBC_NAMESPACE::fopen(filename, "r"); ASSERT_FALSE(file == nullptr); for (size_t i = 0; i < WRITE_SIZE; ++i) { - int c = func(file); - ASSERT_EQ(c, int('1' + i)); + ASSERT_THAT(func(file), Succeeds(int('1' + i))); } // Reading more should return EOF but not set error. - ASSERT_EQ(func(file), EOF); + ASSERT_THAT(func(file), Succeeds(EOF)); ASSERT_NE(LIBC_NAMESPACE::feof(file), 0); ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0); - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); } }; diff --git a/libc/test/src/stdio/fgetc_unlocked_test.cpp b/libc/test/src/stdio/fgetc_unlocked_test.cpp index 46cf12c2c253..bef9dafd3d87 100644 --- a/libc/test/src/stdio/fgetc_unlocked_test.cpp +++ b/libc/test/src/stdio/fgetc_unlocked_test.cpp @@ -17,12 +17,15 @@ #include "src/stdio/funlockfile.h" #include "src/stdio/fwrite.h" #include "src/stdio/getc_unlocked.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" #include "hdr/stdio_macros.h" -#include "src/errno/libc_errno.h" -class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::Test { +using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; + +class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { public: using GetcFunc = int(FILE *); void test_with_func(GetcFunc *func, const char *filename) { @@ -30,31 +33,30 @@ public: ASSERT_FALSE(file == nullptr); constexpr char CONTENT[] = "123456789"; constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1; - ASSERT_EQ(WRITE_SIZE, LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file)); + ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file), + Succeeds(WRITE_SIZE)); // This is a write-only file so reads should fail. - ASSERT_EQ(func(file), EOF); + ASSERT_THAT(func(file), Fails(EBADF, EOF)); // This is an error and not a real EOF. ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); file = LIBC_NAMESPACE::fopen(filename, "r"); ASSERT_FALSE(file == nullptr); LIBC_NAMESPACE::flockfile(file); for (size_t i = 0; i < WRITE_SIZE; ++i) { - int c = func(file); - ASSERT_EQ(c, int('1' + i)); + ASSERT_THAT(func(file), Succeeds(int('1' + i))); } // Reading more should return EOF but not set error. - ASSERT_EQ(func(file), EOF); + ASSERT_THAT(func(file), Succeeds(EOF)); ASSERT_NE(LIBC_NAMESPACE::feof_unlocked(file), 0); ASSERT_EQ(LIBC_NAMESPACE::ferror_unlocked(file), 0); LIBC_NAMESPACE::funlockfile(file); - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); } }; diff --git a/libc/test/src/stdio/fgets_test.cpp b/libc/test/src/stdio/fgets_test.cpp index a8a2c62f07b5..8fc38b065918 100644 --- a/libc/test/src/stdio/fgets_test.cpp +++ b/libc/test/src/stdio/fgets_test.cpp @@ -12,11 +12,14 @@ #include "src/stdio/fgets.h" #include "src/stdio/fopen.h" #include "src/stdio/fwrite.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include "src/errno/libc_errno.h" +using LlvmLibcFgetsTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; +using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; -TEST(LlvmLibcFgetsTest, WriteAndReadCharacters) { +TEST_F(LlvmLibcFgetsTest, WriteAndReadCharacters) { constexpr char FILENAME[] = "testdata/fgets.test"; ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w"); ASSERT_FALSE(file == nullptr); @@ -29,15 +32,16 @@ TEST(LlvmLibcFgetsTest, WriteAndReadCharacters) { char buff[8]; char *output; - ASSERT_EQ(WRITE_SIZE, LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file)); + ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file), + Succeeds(WRITE_SIZE)); // This is a write-only file so reads should fail. - ASSERT_TRUE(LIBC_NAMESPACE::fgets(buff, 8, file) == nullptr); + ASSERT_THAT(LIBC_NAMESPACE::fgets(buff, 8, file), + Fails(EBADF, static_cast(nullptr))); // This is an error and not a real EOF. ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); file = LIBC_NAMESPACE::fopen(FILENAME, "r"); ASSERT_FALSE(file == nullptr); @@ -55,6 +59,7 @@ TEST(LlvmLibcFgetsTest, WriteAndReadCharacters) { // This is also implementation defined. output = LIBC_NAMESPACE::fgets(buff, 0, file); ASSERT_TRUE(output == nullptr); + ASSERT_ERRNO_SUCCESS(); #endif const char *output_arr[] = { @@ -86,5 +91,5 @@ TEST(LlvmLibcFgetsTest, WriteAndReadCharacters) { ASSERT_NE(LIBC_NAMESPACE::feof(file), 0); ASSERT_ERRNO_SUCCESS(); - ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); + ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); } diff --git a/libc/test/src/stdio/fileop_test.cpp b/libc/test/src/stdio/fileop_test.cpp index a0368d701a67..e097785832d5 100644 --- a/libc/test/src/stdio/fileop_test.cpp +++ b/libc/test/src/stdio/fileop_test.cpp @@ -17,17 +17,18 @@ #include "src/stdio/fread.h" #include "src/stdio/fseek.h" #include "src/stdio/fwrite.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" #include "hdr/stdio_macros.h" -#include "src/errno/libc_errno.h" +using LlvmLibcFILETest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::EQ; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::NE; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::returns; -TEST(LlvmLibcFILETest, SimpleFileOperations) { +TEST_F(LlvmLibcFILETest, SimpleFileOperations) { constexpr char FILENAME[] = "testdata/simple_operations.test"; ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w"); ASSERT_FALSE(file == nullptr); @@ -41,7 +42,6 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) { ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, sizeof(CONTENT), file), returns(EQ(size_t(0))).with_errno(NE(0))); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(file); ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0); @@ -72,7 +72,6 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) { ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, sizeof(CONTENT), file), returns(EQ(size_t(0))).with_errno(NE(0))); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(file); @@ -80,15 +79,12 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) { ASSERT_THAT(LIBC_NAMESPACE::fputs(CONTENT, file), returns(EQ(EOF)).with_errno(NE(0))); ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(file); ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::fwrite("nothing", 1, 1, file), returns(EQ(size_t(0))).with_errno(NE(0))); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0); @@ -103,10 +99,8 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) { ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0); // This is not a readable file. - LIBC_NAMESPACE::libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::fread(data, 1, 1, file), returns(EQ(0)).with_errno(NE(0))); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); @@ -121,21 +115,18 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) { // Check that the other functions correctly set libc_errno. - // LIBC_NAMESPACE::libc_errno = 0; // ASSERT_NE(LIBC_NAMESPACE::fseek(file, 0, SEEK_SET), 0); // ASSERT_ERRNO_FAILURE(); - // LIBC_NAMESPACE::libc_errno = 0; // ASSERT_NE(LIBC_NAMESPACE::fclose(file), 0); // ASSERT_ERRNO_FAILURE(); - // LIBC_NAMESPACE::libc_errno = 0; // ASSERT_EQ(LIBC_NAMESPACE::fopen("INVALID FILE NAME", "r"), // static_cast(nullptr)); // ASSERT_ERRNO_FAILURE(); } -TEST(LlvmLibcFILETest, FFlush) { +TEST_F(LlvmLibcFILETest, FFlush) { constexpr char FILENAME[] = "testdata/fflush.test"; ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w+"); ASSERT_FALSE(file == nullptr); @@ -156,7 +147,7 @@ TEST(LlvmLibcFILETest, FFlush) { ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0); } -TEST(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) { +TEST_F(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) { using MyStruct = struct { char c; unsigned long long i; @@ -165,7 +156,6 @@ TEST(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) { constexpr size_t WRITE_NMEMB = sizeof(WRITE_DATA) / sizeof(MyStruct); constexpr char FILENAME[] = "testdata/fread_fwrite.test"; - LIBC_NAMESPACE::libc_errno = 0; FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w"); ASSERT_FALSE(file == nullptr); ASSERT_EQ(size_t(0), LIBC_NAMESPACE::fwrite(WRITE_DATA, 0, 1, file)); diff --git a/libc/test/src/stdio/fopencookie_test.cpp b/libc/test/src/stdio/fopencookie_test.cpp index 61ce2a207fa1..bcf5e674141a 100644 --- a/libc/test/src/stdio/fopencookie_test.cpp +++ b/libc/test/src/stdio/fopencookie_test.cpp @@ -15,13 +15,15 @@ #include "src/stdio/fread.h" #include "src/stdio/fseek.h" #include "src/stdio/fwrite.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/MemoryMatcher.h" #include "test/UnitTest/Test.h" #include "hdr/stdio_macros.h" #include "hdr/types/size_t.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" +using LlvmLibcFOpenCookieTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; using MemoryView = LIBC_NAMESPACE::testing::MemoryView; struct StringStream { @@ -67,7 +69,7 @@ int seek_ss(void *cookie, off64_t *offset, int whence) { } else if (whence == SEEK_END) { new_offset = *offset + ss->endpos; } else { - LIBC_NAMESPACE::libc_errno = EINVAL; + libc_errno = EINVAL; return -1; } if (new_offset < 0 || size_t(new_offset) > ss->bufsize) @@ -88,7 +90,7 @@ int close_ss(void *cookie) { constexpr cookie_io_functions_t STRING_STREAM_FUNCS = {&read_ss, &write_ss, &seek_ss, &close_ss}; -TEST(LlvmLibcFOpenCookie, ReadOnlyCookieTest) { +TEST_F(LlvmLibcFOpenCookieTest, ReadOnlyCookieTest) { constexpr char CONTENT[] = "Hello,readonly!"; auto *ss = reinterpret_cast(malloc(sizeof(StringStream))); ss->buf = reinterpret_cast(malloc(sizeof(CONTENT))); @@ -115,7 +117,6 @@ TEST(LlvmLibcFOpenCookie, ReadOnlyCookieTest) { ASSERT_EQ(size_t(0), LIBC_NAMESPACE::fwrite(CONTENT, 1, sizeof(CONTENT), f)); ASSERT_NE(LIBC_NAMESPACE::ferror(f), 0); ASSERT_ERRNO_FAILURE(); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(f); ASSERT_EQ(LIBC_NAMESPACE::ferror(f), 0); @@ -124,7 +125,7 @@ TEST(LlvmLibcFOpenCookie, ReadOnlyCookieTest) { free(ss); } -TEST(LlvmLibcFOpenCookie, WriteOnlyCookieTest) { +TEST_F(LlvmLibcFOpenCookieTest, WriteOnlyCookieTest) { size_t INIT_BUFSIZE = 32; auto *ss = reinterpret_cast(malloc(sizeof(StringStream))); ss->buf = reinterpret_cast(malloc(INIT_BUFSIZE)); @@ -149,7 +150,6 @@ TEST(LlvmLibcFOpenCookie, WriteOnlyCookieTest) { LIBC_NAMESPACE::fread(read_data, 1, sizeof(WRITE_DATA), f)); ASSERT_NE(LIBC_NAMESPACE::ferror(f), 0); ASSERT_ERRNO_EQ(EBADF); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(f); ASSERT_EQ(LIBC_NAMESPACE::ferror(f), 0); @@ -158,7 +158,7 @@ TEST(LlvmLibcFOpenCookie, WriteOnlyCookieTest) { free(ss); } -TEST(LlvmLibcFOpenCookie, AppendOnlyCookieTest) { +TEST_F(LlvmLibcFOpenCookieTest, AppendOnlyCookieTest) { constexpr char INITIAL_CONTENT[] = "1234567890987654321"; constexpr char WRITE_DATA[] = "append"; auto *ss = reinterpret_cast(malloc(sizeof(StringStream))); @@ -178,7 +178,6 @@ TEST(LlvmLibcFOpenCookie, AppendOnlyCookieTest) { ASSERT_EQ(LIBC_NAMESPACE::fread(read_data, 1, READ_SIZE, f), size_t(0)); ASSERT_NE(LIBC_NAMESPACE::ferror(f), 0); ASSERT_ERRNO_FAILURE(); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr(f); ASSERT_EQ(LIBC_NAMESPACE::ferror(f), 0); @@ -192,7 +191,7 @@ TEST(LlvmLibcFOpenCookie, AppendOnlyCookieTest) { free(ss); } -TEST(LlvmLibcFOpenCookie, ReadUpdateCookieTest) { +TEST_F(LlvmLibcFOpenCookieTest, ReadUpdateCookieTest) { const char INITIAL_CONTENT[] = "1234567890987654321"; auto *ss = reinterpret_cast(malloc(sizeof(StringStream))); ss->buf = reinterpret_cast(malloc(sizeof(INITIAL_CONTENT))); @@ -223,7 +222,7 @@ TEST(LlvmLibcFOpenCookie, ReadUpdateCookieTest) { free(ss); } -TEST(LlvmLibcFOpenCookie, WriteUpdateCookieTest) { +TEST_F(LlvmLibcFOpenCookieTest, WriteUpdateCookieTest) { constexpr char WRITE_DATA[] = "hello, file"; auto *ss = reinterpret_cast(malloc(sizeof(StringStream))); ss->buf = reinterpret_cast(malloc(sizeof(WRITE_DATA))); diff --git a/libc/test/src/stdio/perror_test.cpp b/libc/test/src/stdio/perror_test.cpp new file mode 100644 index 000000000000..9a97be2eff21 --- /dev/null +++ b/libc/test/src/stdio/perror_test.cpp @@ -0,0 +1,32 @@ +//===-- Unittests for perror ---------------------------------------------===// +// +// 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 "src/stdio/perror.h" + +#include "src/__support/libc_errno.h" +#include "test/UnitTest/Test.h" + +// The standard says perror prints directly to stderr and returns nothing. This +// makes it rather difficult to test automatically. + +// TODO: figure out redirecting stderr so this test can check correctness. +TEST(LlvmLibcPerrorTest, PrintOut) { + LIBC_NAMESPACE::libc_errno = 0; + constexpr char simple[] = "A simple string"; + LIBC_NAMESPACE::perror(simple); + + // stick to stdc errno values, specifically 0, EDOM, ERANGE, and EILSEQ. + LIBC_NAMESPACE::libc_errno = EDOM; + LIBC_NAMESPACE::perror("Print this and an error"); + + LIBC_NAMESPACE::libc_errno = EILSEQ; + LIBC_NAMESPACE::perror("\0 shouldn't print this."); + + LIBC_NAMESPACE::libc_errno = ERANGE; + LIBC_NAMESPACE::perror(nullptr); +} diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp index 96a00ae598ec..bf088937e410 100644 --- a/libc/test/src/stdio/printf_core/converter_test.cpp +++ b/libc/test/src/stdio/printf_core/converter_test.cpp @@ -124,7 +124,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionSimple) { TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionHigh) { LIBC_NAMESPACE::printf_core::FormatSection high_precision_conv; high_precision_conv.has_conv = true; - high_precision_conv.raw_string = "%4s"; + high_precision_conv.raw_string = "%.4s"; high_precision_conv.conv_name = 's'; high_precision_conv.precision = 4; high_precision_conv.conv_val_ptr = const_cast("456"); diff --git a/libc/test/src/stdio/remove_test.cpp b/libc/test/src/stdio/remove_test.cpp index 72875600903a..296bff1f5dc1 100644 --- a/libc/test/src/stdio/remove_test.cpp +++ b/libc/test/src/stdio/remove_test.cpp @@ -11,16 +11,17 @@ #include "src/sys/stat/mkdirat.h" #include "src/unistd/access.h" #include "src/unistd/close.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include "src/errno/libc_errno.h" #include -TEST(LlvmLibcRemoveTest, CreateAndRemoveFile) { +using LlvmLibcRemoveTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcRemoveTest, CreateAndRemoveFile) { // The test strategy is to create a file and remove it, and also verify that // it was removed. - LIBC_NAMESPACE::libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; @@ -36,10 +37,9 @@ TEST(LlvmLibcRemoveTest, CreateAndRemoveFile) { ASSERT_THAT(LIBC_NAMESPACE::access(TEST_FILE, F_OK), Fails(ENOENT)); } -TEST(LlvmLibcRemoveTest, CreateAndRemoveDir) { +TEST_F(LlvmLibcRemoveTest, CreateAndRemoveDir) { // The test strategy is to create a dir and remove it, and also verify that // it was removed. - LIBC_NAMESPACE::libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *FILENAME = "remove.test.dir"; diff --git a/libc/test/src/stdio/rename_test.cpp b/libc/test/src/stdio/rename_test.cpp index a5dd734c6361..135fb98c07fb 100644 --- a/libc/test/src/stdio/rename_test.cpp +++ b/libc/test/src/stdio/rename_test.cpp @@ -8,18 +8,19 @@ #include "include/llvm-libc-macros/linux/sys-stat-macros.h" #include "include/llvm-libc-macros/linux/unistd-macros.h" -#include "src/errno/libc_errno.h" #include "src/fcntl/open.h" #include "src/stdio/rename.h" #include "src/unistd/access.h" #include "src/unistd/close.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -TEST(LlvmLibcRenameTest, CreateAndRenameFile) { +using LlvmLibcRenameTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcRenameTest, CreateAndRenameFile) { // The test strategy is to create a file and rename it, and also verify that // it was renamed. - LIBC_NAMESPACE::libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; @@ -40,7 +41,7 @@ TEST(LlvmLibcRenameTest, CreateAndRenameFile) { ASSERT_THAT(LIBC_NAMESPACE::access(TEST_FILEPATH0, F_OK), Fails(ENOENT)); } -TEST(LlvmLibcRenameTest, RenameNonExistent) { +TEST_F(LlvmLibcRenameTest, RenameNonExistent) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; constexpr const char *FILENAME1 = "rename.test.file1"; diff --git a/libc/test/src/stdio/setvbuf_test.cpp b/libc/test/src/stdio/setvbuf_test.cpp index a1e1fee25db3..a0936ba79ef7 100644 --- a/libc/test/src/stdio/setvbuf_test.cpp +++ b/libc/test/src/stdio/setvbuf_test.cpp @@ -11,12 +11,14 @@ #include "src/stdio/fread.h" #include "src/stdio/fwrite.h" #include "src/stdio/setvbuf.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/Test.h" #include "hdr/stdio_macros.h" -#include "src/errno/libc_errno.h" -TEST(LlvmLibcSetvbufTest, SetNBFBuffer) { +using LlvmLibcSetvbufTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcSetvbufTest, SetNBFBuffer) { // The idea in this test is that we open a file for writing and reading, and // then set a NBF buffer to the write handle. Since it is NBF, the data // written using the write handle should be immediately readable by the read @@ -52,7 +54,7 @@ TEST(LlvmLibcSetvbufTest, SetNBFBuffer) { ASSERT_EQ(0, LIBC_NAMESPACE::fclose(fr)); } -TEST(LlvmLibcSetvbufTest, SetLBFBuffer) { +TEST_F(LlvmLibcSetvbufTest, SetLBFBuffer) { // The idea in this test is that we open a file for writing and reading, and // then set a LBF buffer to the write handle. Since it is LBF, the data // written using the write handle should be available right after a '\n' is @@ -102,6 +104,5 @@ TEST(LlvmLibcSetbufTest, InvalidBufferMode) { 0); ASSERT_ERRNO_EQ(EINVAL); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(0, LIBC_NAMESPACE::fclose(f)); } diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp index f6af6ad3e364..f1b545ba546f 100644 --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -10,7 +10,7 @@ #include "src/stdio/sprintf.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "test/UnitTest/RoundingModeUtils.h" #include "test/UnitTest/Test.h" #include @@ -3228,46 +3228,46 @@ TEST(LlvmLibcSPrintfTest, StrerrorConv) { char buff[1000]; int written; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%m"); ASSERT_STREQ_LEN(written, buff, "Success"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%m"); ASSERT_STREQ_LEN(written, buff, "Numerical result out of range"); // Check that it correctly consumes no arguments. - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%m %d", 1); ASSERT_STREQ_LEN(written, buff, "Success 1"); // Width Tests - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%10m"); ASSERT_STREQ_LEN(written, buff, " Success"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%10m"); ASSERT_STREQ_LEN(written, buff, "Numerical result out of range"); // Precision Tests - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%.10m"); ASSERT_STREQ_LEN(written, buff, "Success"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%.10m"); ASSERT_STREQ_LEN(written, buff, "Numerical "); // Flag Tests (Only '-' since the others only affect ints) - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%-10m"); ASSERT_STREQ_LEN(written, buff, "Success "); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%-10m"); ASSERT_STREQ_LEN(written, buff, "Numerical result out of range"); @@ -3275,93 +3275,93 @@ TEST(LlvmLibcSPrintfTest, StrerrorConv) { // Since alt mode here is effectively a completely separate conversion, it // gets separate tests. - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%#m"); ASSERT_STREQ_LEN(written, buff, "0"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#m"); ASSERT_STREQ_LEN(written, buff, "-9999"); // Alt Mode Width - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%#10m"); ASSERT_STREQ_LEN(written, buff, " 0"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#10m"); ASSERT_STREQ_LEN(written, buff, " ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#10m"); ASSERT_STREQ_LEN(written, buff, " -9999"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#3m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#3m"); ASSERT_STREQ_LEN(written, buff, "-9999"); // Alt Mode Precision - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#.10m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#.10m"); ASSERT_STREQ_LEN(written, buff, "-0000009999"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#.3m"); ASSERT_STREQ_LEN(written, buff, "ERA"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#.3m"); ASSERT_STREQ_LEN(written, buff, "-9999"); // We don't test precision (or int flags) on errno = 0 because it behaves // weirdly, see the docs for more information. - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%#.1m"); ASSERT_STREQ_LEN(written, buff, "0"); // Alt Mode Flags // '-' flag - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; written = LIBC_NAMESPACE::sprintf(buff, "%#-10m"); ASSERT_STREQ_LEN(written, buff, "0 "); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#-10m"); ASSERT_STREQ_LEN(written, buff, "ERANGE "); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#-10m"); ASSERT_STREQ_LEN(written, buff, "-9999 "); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#-3m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#-3m"); ASSERT_STREQ_LEN(written, buff, "-9999"); // '+' flag - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#+m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#+m"); ASSERT_STREQ_LEN(written, buff, "-9999"); @@ -3370,38 +3370,38 @@ TEST(LlvmLibcSPrintfTest, StrerrorConv) { // come up, but I've avoided it for the other %m tests for ease of // refactoring if necessary. Here it needs to be positive to test that the // flags that only affect positive signed integers are properly passed along. - LIBC_NAMESPACE::libc_errno = 9999; + libc_errno = 9999; written = LIBC_NAMESPACE::sprintf(buff, "%#+m"); ASSERT_STREQ_LEN(written, buff, "+9999"); // ' ' flag - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%# m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%# m"); ASSERT_STREQ_LEN(written, buff, "-9999"); - LIBC_NAMESPACE::libc_errno = 9999; + libc_errno = 9999; written = LIBC_NAMESPACE::sprintf(buff, "%# m"); ASSERT_STREQ_LEN(written, buff, " 9999"); // '0' flag - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#010m"); ASSERT_STREQ_LEN(written, buff, " ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#010m"); ASSERT_STREQ_LEN(written, buff, "-000009999"); - LIBC_NAMESPACE::libc_errno = ERANGE; + libc_errno = ERANGE; written = LIBC_NAMESPACE::sprintf(buff, "%#03m"); ASSERT_STREQ_LEN(written, buff, "ERANGE"); - LIBC_NAMESPACE::libc_errno = -9999; + libc_errno = -9999; written = LIBC_NAMESPACE::sprintf(buff, "%#03m"); ASSERT_STREQ_LEN(written, buff, "-9999"); } diff --git a/libc/test/src/stdio/unlocked_fileop_test.cpp b/libc/test/src/stdio/unlocked_fileop_test.cpp index 67f1b0ff513b..e99b382d1211 100644 --- a/libc/test/src/stdio/unlocked_fileop_test.cpp +++ b/libc/test/src/stdio/unlocked_fileop_test.cpp @@ -15,11 +15,12 @@ #include "src/stdio/fread_unlocked.h" #include "src/stdio/funlockfile.h" #include "src/stdio/fwrite_unlocked.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/Test.h" -#include "src/errno/libc_errno.h" +using LlvmLibcFILETest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; -TEST(LlvmLibcFILETest, UnlockedReadAndWrite) { +TEST_F(LlvmLibcFILETest, UnlockedReadAndWrite) { constexpr char fNAME[] = "testdata/unlocked_read_and_write.test"; ::FILE *f = LIBC_NAMESPACE::fopen(fNAME, "w"); ASSERT_FALSE(f == nullptr); @@ -36,7 +37,6 @@ TEST(LlvmLibcFILETest, UnlockedReadAndWrite) { LIBC_NAMESPACE::fread_unlocked(data, 1, sizeof(READ_SIZE), f)); ASSERT_NE(LIBC_NAMESPACE::ferror_unlocked(f), 0); ASSERT_ERRNO_FAILURE(); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr_unlocked(f); ASSERT_EQ(LIBC_NAMESPACE::ferror_unlocked(f), 0); @@ -57,7 +57,6 @@ TEST(LlvmLibcFILETest, UnlockedReadAndWrite) { LIBC_NAMESPACE::fwrite_unlocked(CONTENT, 1, sizeof(CONTENT), f)); ASSERT_NE(LIBC_NAMESPACE::ferror_unlocked(f), 0); ASSERT_ERRNO_FAILURE(); - LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::clearerr_unlocked(f); ASSERT_EQ(LIBC_NAMESPACE::ferror_unlocked(f), 0); diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt index 302971a078c1..45fd49b6d352 100644 --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -9,6 +9,7 @@ add_libc_test( DEPENDS libc.src.errno.errno libc.src.stdlib.atof + libc.test.UnitTest.ErrnoCheckingTest ) add_header_library( @@ -64,6 +65,7 @@ add_fp_unittest( libc.src.errno.errno libc.src.stdlib.strtod libc.src.__support.FPUtil.fenv_impl + libc.test.UnitTest.ErrnoCheckingTest ) add_fp_unittest( @@ -76,6 +78,7 @@ add_fp_unittest( libc.src.errno.errno libc.src.stdlib.strtof libc.src.__support.FPUtil.fenv_impl + libc.test.UnitTest.ErrnoCheckingTest ) add_header_library( @@ -86,6 +89,7 @@ add_header_library( libc.src.__support.CPP.limits libc.src.__support.CPP.type_traits libc.src.errno.errno + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( @@ -133,6 +137,7 @@ add_libc_test( libc.src.errno.errno libc.src.__support.uint128 libc.src.stdlib.strtold + libc.test.UnitTest.ErrnoCheckingTest ) add_libc_test( diff --git a/libc/test/src/stdlib/StrtolTest.h b/libc/test/src/stdlib/StrtolTest.h index ed302f14d03e..03f0a6539c78 100644 --- a/libc/test/src/stdlib/StrtolTest.h +++ b/libc/test/src/stdlib/StrtolTest.h @@ -10,7 +10,7 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/ctype_utils.h" #include "src/__support/macros/properties/architectures.h" -#include "src/errno/libc_errno.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/Test.h" #include @@ -18,7 +18,7 @@ using LIBC_NAMESPACE::cpp::is_signed_v; template -struct StrtoTest : public LIBC_NAMESPACE::testing::Test { +struct StrtoTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { using FunctionT = ReturnT (*)(const char *, char **, int); static constexpr ReturnT T_MAX = @@ -28,7 +28,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { void InvalidBase(FunctionT func) { const char *ten = "10"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(ten, nullptr, -1), ReturnT(0)); ASSERT_ERRNO_EQ(EINVAL); } @@ -38,23 +37,19 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // TODO: Look into collapsing these repeated segments. const char *ten = "10"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(ten, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - ten, ptrdiff_t(2)); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(ten, nullptr, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); const char *hundred = "100"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(hundred, &str_end, 10), ReturnT(100)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - hundred, ptrdiff_t(3)); const char *big_number = "1234567890"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(big_number, &str_end, 10), ReturnT(1234567890)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - big_number, ptrdiff_t(10)); @@ -62,7 +57,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // This number is larger than 2^32, meaning that if long is only 32 bits // wide, strtol will return LONG_MAX. const char *bigger_number = "12345678900"; - LIBC_NAMESPACE::libc_errno = 0; if constexpr (sizeof(ReturnT) < 8) { ASSERT_EQ(func(bigger_number, &str_end, 10), T_MAX); ASSERT_ERRNO_EQ(ERANGE); @@ -73,14 +67,12 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { EXPECT_EQ(str_end - bigger_number, ptrdiff_t(11)); const char *too_big_number = "123456789012345678901"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(too_big_number, &str_end, 10), T_MAX); ASSERT_ERRNO_EQ(ERANGE); EXPECT_EQ(str_end - too_big_number, ptrdiff_t(21)); const char *long_number_range_test = "10000000000000000000000000000000000000000000000000"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(long_number_range_test, &str_end, 10), T_MAX); ASSERT_ERRNO_EQ(ERANGE); EXPECT_EQ(str_end - long_number_range_test, ptrdiff_t(50)); @@ -88,19 +80,16 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // For most negative numbers, the unsigned functions treat it the same as // casting a negative variable to an unsigned type. const char *negative = "-100"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(negative, &str_end, 10), ReturnT(-100)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - negative, ptrdiff_t(4)); const char *big_negative_number = "-1234567890"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(big_negative_number, &str_end, 10), ReturnT(-1234567890)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - big_negative_number, ptrdiff_t(11)); const char *too_big_negative_number = "-123456789012345678901"; - LIBC_NAMESPACE::libc_errno = 0; // If the number is signed, it should return the smallest negative number // for the current type, but if it's unsigned it should max out and return // the largest positive number for the current type. From the standard: @@ -118,73 +107,61 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { char *str_end = nullptr; const char *spaces_before = " 10"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(spaces_before, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - spaces_before, ptrdiff_t(7)); const char *spaces_after = "10 "; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(spaces_after, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - spaces_after, ptrdiff_t(2)); const char *word_before = "word10"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(word_before, &str_end, 10), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - word_before, ptrdiff_t(0)); const char *word_after = "10word"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(word_after, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - word_after, ptrdiff_t(2)); const char *two_numbers = "10 999"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(two_numbers, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - two_numbers, ptrdiff_t(2)); const char *two_signs = "--10 999"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(two_signs, &str_end, 10), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - two_signs, ptrdiff_t(0)); const char *sign_before = "+2=4"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(sign_before, &str_end, 10), ReturnT(2)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - sign_before, ptrdiff_t(2)); const char *sign_after = "2+2=4"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(sign_after, &str_end, 10), ReturnT(2)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - sign_after, ptrdiff_t(1)); const char *tab_before = "\t10"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(tab_before, &str_end, 10), ReturnT(10)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - tab_before, ptrdiff_t(3)); const char *all_together = "\t -12345and+67890"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(all_together, &str_end, 10), ReturnT(-12345)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - all_together, ptrdiff_t(9)); const char *just_spaces = " "; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_spaces, &str_end, 10), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0)); const char *just_space_and_sign = " +"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_space_and_sign, &str_end, 10), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0)); @@ -203,12 +180,10 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { small_string[0] = static_cast( LIBC_NAMESPACE::internal::int_to_b36_char(first_digit)); if (first_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), static_cast(first_digit)); ASSERT_ERRNO_SUCCESS(); } else { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); } @@ -223,18 +198,15 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { small_string[1] = static_cast( LIBC_NAMESPACE::internal::int_to_b36_char(second_digit)); if (first_digit < base && second_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ( func(small_string, nullptr, base), static_cast(second_digit + (first_digit * base))); ASSERT_ERRNO_SUCCESS(); } else if (first_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), static_cast(first_digit)); ASSERT_ERRNO_SUCCESS(); } else { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); } @@ -255,14 +227,12 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { if (first_digit < base && second_digit < base && third_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), static_cast(third_digit + (second_digit * base) + (first_digit * base * base))); ASSERT_ERRNO_SUCCESS(); } else if (first_digit < base && second_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ( func(small_string, nullptr, base), static_cast(second_digit + (first_digit * base))); @@ -272,23 +242,19 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // The number is treated as a one digit hexadecimal. if (base == 16 && first_digit == 0 && second_digit == 33) { if (third_digit < base) { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), static_cast(third_digit)); ASSERT_ERRNO_SUCCESS(); } else { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); } } else { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), static_cast(first_digit)); ASSERT_ERRNO_SUCCESS(); } } else { - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(small_string, nullptr, base), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); } @@ -302,19 +268,16 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { char *str_end = nullptr; const char *no_prefix = "123abc"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(no_prefix, &str_end, 16), ReturnT(0x123abc)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - no_prefix, ptrdiff_t(6)); const char *yes_prefix = "0x456def"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(yes_prefix, &str_end, 16), ReturnT(0x456def)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - yes_prefix, ptrdiff_t(8)); const char *letter_after_prefix = "0xabc123"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(letter_after_prefix, &str_end, 16), ReturnT(0xabc123)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - letter_after_prefix, ptrdiff_t(8)); @@ -325,7 +288,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // Max size for unsigned 32 bit numbers const char *max_32_bit_value = "0xFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(max_32_bit_value, &str_end, 0), ((is_signed_v && sizeof(ReturnT) == 4) ? T_MAX @@ -334,7 +296,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { EXPECT_EQ(str_end - max_32_bit_value, ptrdiff_t(10)); const char *negative_max_32_bit_value = "-0xFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(negative_max_32_bit_value, &str_end, 0), ((is_signed_v && sizeof(ReturnT) == 4) ? T_MIN @@ -345,13 +306,11 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // Max size for signed 32 bit numbers const char *max_31_bit_value = "0x7FFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(max_31_bit_value, &str_end, 0), ReturnT(0x7FFFFFFF)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - max_31_bit_value, ptrdiff_t(10)); const char *negative_max_31_bit_value = "-0x7FFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(negative_max_31_bit_value, &str_end, 0), -ReturnT(0x7FFFFFFF)); ASSERT_ERRNO_SUCCESS(); @@ -360,7 +319,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // Max size for unsigned 64 bit numbers const char *max_64_bit_value = "0xFFFFFFFFFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(max_64_bit_value, &str_end, 0), (is_signed_v || sizeof(ReturnT) < 8 ? T_MAX @@ -371,7 +329,6 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // See the end of CleanBase10Decode for an explanation of how this large // negative number can end up as T_MAX. const char *negative_max_64_bit_value = "-0xFFFFFFFFFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ( func(negative_max_64_bit_value, &str_end, 0), (is_signed_v @@ -383,14 +340,12 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { // Max size for signed 64 bit numbers const char *max_63_bit_value = "0x7FFFFFFFFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(max_63_bit_value, &str_end, 0), (sizeof(ReturnT) < 8 ? T_MAX : ReturnT(0x7FFFFFFFFFFFFFFF))); ASSERT_ERRNO_EQ(sizeof(ReturnT) < 8 ? ERANGE : 0); EXPECT_EQ(str_end - max_63_bit_value, ptrdiff_t(18)); const char *negative_max_63_bit_value = "-0x7FFFFFFFFFFFFFFF"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(negative_max_63_bit_value, &str_end, 0), (sizeof(ReturnT) >= 8 ? -ReturnT(0x7FFFFFFFFFFFFFFF) : (is_signed_v ? T_MIN : T_MAX))); @@ -402,23 +357,19 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { char *str_end = nullptr; const char *just_prefix = "0x"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_prefix, &str_end, 16), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_prefix, ptrdiff_t(1)); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_prefix, &str_end, 0), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_prefix, ptrdiff_t(1)); const char *prefix_with_x_after = "0xx"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(prefix_with_x_after, &str_end, 16), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - prefix_with_x_after, ptrdiff_t(1)); - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(prefix_with_x_after, &str_end, 0), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - prefix_with_x_after, ptrdiff_t(1)); @@ -428,43 +379,36 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test { char *str_end = nullptr; const char *base_ten = "12345"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(base_ten, &str_end, 0), ReturnT(12345)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - base_ten, ptrdiff_t(5)); const char *base_sixteen_no_prefix = "123abc"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(base_sixteen_no_prefix, &str_end, 0), ReturnT(123)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - base_sixteen_no_prefix, ptrdiff_t(3)); const char *base_sixteen_with_prefix = "0x456def"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(base_sixteen_with_prefix, &str_end, 0), ReturnT(0x456def)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - base_sixteen_with_prefix, ptrdiff_t(8)); const char *base_eight_with_prefix = "012345"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(base_eight_with_prefix, &str_end, 0), ReturnT(012345)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6)); const char *just_zero = "0"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_zero, &str_end, 0), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_zero, ptrdiff_t(1)); const char *just_zero_x = "0x"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_zero_x, &str_end, 0), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1)); const char *just_zero_eight = "08"; - LIBC_NAMESPACE::libc_errno = 0; ASSERT_EQ(func(just_zero_eight, &str_end, 0), ReturnT(0)); ASSERT_ERRNO_SUCCESS(); EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1)); diff --git a/libc/test/src/stdlib/atof_test.cpp b/libc/test/src/stdlib/atof_test.cpp index 1e4259b792d7..92b904ecad94 100644 --- a/libc/test/src/stdlib/atof_test.cpp +++ b/libc/test/src/stdlib/atof_test.cpp @@ -7,29 +7,28 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" #include "src/stdlib/atof.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" #include +using LlvmLibcAToFTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; // This is just a simple test to make sure that this function works at all. It's // functionally identical to strtod so the bulk of the testing is there. -TEST(LlvmLibcAToFTest, SimpleTest) { +TEST_F(LlvmLibcAToFTest, SimpleTest) { LIBC_NAMESPACE::fputil::FPBits expected_fp = LIBC_NAMESPACE::fputil::FPBits(uint64_t(0x405ec00000000000)); - LIBC_NAMESPACE::libc_errno = 0; EXPECT_THAT(LIBC_NAMESPACE::atof("123"), Succeeds(expected_fp.get_val())); } -TEST(LlvmLibcAToFTest, FailedParsingTest) { - LIBC_NAMESPACE::libc_errno = 0; +TEST_F(LlvmLibcAToFTest, FailedParsingTest) { // atof does not flag errors. EXPECT_THAT(LIBC_NAMESPACE::atof("???"), Succeeds(0.0)); } diff --git a/libc/test/src/stdlib/strtod_test.cpp b/libc/test/src/stdlib/strtod_test.cpp index 92d14640e653..db3c1d73bd22 100644 --- a/libc/test/src/stdlib/strtod_test.cpp +++ b/libc/test/src/stdlib/strtod_test.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" #include "src/stdlib/strtod.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/RoundingModeUtils.h" #include "test/UnitTest/Test.h" @@ -22,7 +22,7 @@ using LIBC_NAMESPACE::fputil::testing::RoundingMode; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; -class LlvmLibcStrToDTest : public LIBC_NAMESPACE::testing::Test, +class LlvmLibcStrToDTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest, ForceRoundingModeTest { public: void run_test(const char *inputString, const ptrdiff_t expectedStrLen, @@ -46,7 +46,6 @@ public: LIBC_NAMESPACE::fputil::FPBits expected_fp = LIBC_NAMESPACE::fputil::FPBits(expectedRawData); - LIBC_NAMESPACE::libc_errno = 0; double result = LIBC_NAMESPACE::strtod(inputString, &str_end); if (expectedErrno == 0) EXPECT_THAT(result, Succeeds(expected_fp.get_val())); diff --git a/libc/test/src/stdlib/strtof_test.cpp b/libc/test/src/stdlib/strtof_test.cpp index 6a716c956291..6df1ddda93bf 100644 --- a/libc/test/src/stdlib/strtof_test.cpp +++ b/libc/test/src/stdlib/strtof_test.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/__support/FPUtil/FPBits.h" -#include "src/errno/libc_errno.h" #include "src/stdlib/strtof.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/RoundingModeUtils.h" #include "test/UnitTest/Test.h" @@ -19,7 +19,7 @@ using LIBC_NAMESPACE::fputil::testing::ForceRoundingModeTest; using LIBC_NAMESPACE::fputil::testing::RoundingMode; -class LlvmLibcStrToFTest : public LIBC_NAMESPACE::testing::Test, +class LlvmLibcStrToFTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest, ForceRoundingModeTest { public: void run_test(const char *inputString, const ptrdiff_t expectedStrLen, @@ -43,7 +43,6 @@ public: LIBC_NAMESPACE::fputil::FPBits expected_fp = LIBC_NAMESPACE::fputil::FPBits(expectedRawData); - LIBC_NAMESPACE::libc_errno = 0; float result = LIBC_NAMESPACE::strtof(inputString, &str_end); EXPECT_EQ(str_end - inputString, expectedStrLen); diff --git a/libc/test/src/stdlib/strtoint32_test.cpp b/libc/test/src/stdlib/strtoint32_test.cpp index 17df432fc8e6..e6da692714d2 100644 --- a/libc/test/src/stdlib/strtoint32_test.cpp +++ b/libc/test/src/stdlib/strtoint32_test.cpp @@ -8,9 +8,9 @@ #include +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" #include "StrtolTest.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ int32_t strtoint32(const char *__restrict str, char **__restrict str_end, int base) { auto result = internal::strtointeger(str, base); if (result.has_error()) - LIBC_NAMESPACE::libc_errno = result.error; + libc_errno = result.error; if (str_end != nullptr) *str_end = const_cast(str + result.parsed_len); @@ -33,7 +33,7 @@ uint32_t strtouint32(const char *__restrict str, char **__restrict str_end, int base) { auto result = internal::strtointeger(str, base); if (result.has_error()) - LIBC_NAMESPACE::libc_errno = result.error; + libc_errno = result.error; if (str_end != nullptr) *str_end = const_cast(str + result.parsed_len); diff --git a/libc/test/src/stdlib/strtoint64_test.cpp b/libc/test/src/stdlib/strtoint64_test.cpp index b5fe69dfaa70..2c5d948f5fae 100644 --- a/libc/test/src/stdlib/strtoint64_test.cpp +++ b/libc/test/src/stdlib/strtoint64_test.cpp @@ -8,9 +8,9 @@ #include +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" -#include "src/errno/libc_errno.h" #include "StrtolTest.h" #include "test/UnitTest/Test.h" @@ -21,7 +21,7 @@ int64_t strtoint64(const char *__restrict str, char **__restrict str_end, int base) { auto result = internal::strtointeger(str, base); if (result.has_error()) - LIBC_NAMESPACE::libc_errno = result.error; + libc_errno = result.error; if (str_end != nullptr) *str_end = const_cast(str + result.parsed_len); @@ -33,7 +33,7 @@ uint64_t strtouint64(const char *__restrict str, char **__restrict str_end, int base) { auto result = internal::strtointeger(str, base); if (result.has_error()) - LIBC_NAMESPACE::libc_errno = result.error; + libc_errno = result.error; if (str_end != nullptr) *str_end = const_cast(str + result.parsed_len); diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp index b209c85b88e3..eb4056dc7ba6 100644 --- a/libc/test/src/stdlib/strtold_test.cpp +++ b/libc/test/src/stdlib/strtold_test.cpp @@ -8,9 +8,9 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/uint128.h" -#include "src/errno/libc_errno.h" #include "src/stdlib/strtold.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/Test.h" #include @@ -25,7 +25,7 @@ #error "Unknown long double type" #endif -class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::Test { +class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { public: #if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) void run_test(const char *inputString, const ptrdiff_t expectedStrLen, @@ -80,7 +80,6 @@ public: FPBits(static_cast(expectedRawData)); const int expected_errno = expectedErrno; - LIBC_NAMESPACE::libc_errno = 0; long double result = LIBC_NAMESPACE::strtold(inputString, &str_end); LIBC_NAMESPACE::fputil::FPBits actual_fp = diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index a675373938e9..ced60750a45c 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -168,6 +168,7 @@ add_libc_test( DEPENDS libc.src.string.strdup libc.src.errno.errno + libc.test.UnitTest.ErrnoCheckingTest ) # FIXME: This is failing on the bot for some reason, disable for now. diff --git a/libc/test/src/string/strdup_test.cpp b/libc/test/src/string/strdup_test.cpp index 20b85c37637d..4b18fc7f1bde 100644 --- a/libc/test/src/string/strdup_test.cpp +++ b/libc/test/src/string/strdup_test.cpp @@ -6,14 +6,15 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" #include "src/string/strdup.h" +#include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/Test.h" -TEST(LlvmLibcStrDupTest, EmptyString) { +using LlvmLibcStrDupTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcStrDupTest, EmptyString) { const char *empty = ""; - LIBC_NAMESPACE::libc_errno = 0; char *result = LIBC_NAMESPACE::strdup(empty); ASSERT_ERRNO_SUCCESS(); @@ -23,10 +24,9 @@ TEST(LlvmLibcStrDupTest, EmptyString) { ::free(result); } -TEST(LlvmLibcStrDupTest, AnyString) { +TEST_F(LlvmLibcStrDupTest, AnyString) { const char *abc = "abc"; - LIBC_NAMESPACE::libc_errno = 0; char *result = LIBC_NAMESPACE::strdup(abc); ASSERT_ERRNO_SUCCESS(); @@ -36,8 +36,7 @@ TEST(LlvmLibcStrDupTest, AnyString) { ::free(result); } -TEST(LlvmLibcStrDupTest, NullPtr) { - LIBC_NAMESPACE::libc_errno = 0; +TEST_F(LlvmLibcStrDupTest, NullPtr) { char *result = LIBC_NAMESPACE::strdup(nullptr); ASSERT_ERRNO_SUCCESS(); diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt index 224cc7905ad3..13bf91eef04b 100644 --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -13,3 +13,4 @@ add_subdirectory(auxv) add_subdirectory(epoll) add_subdirectory(uio) add_subdirectory(time) +add_subdirectory(ioctl) diff --git a/libc/test/src/sys/ioctl/CMakeLists.txt b/libc/test/src/sys/ioctl/CMakeLists.txt new file mode 100644 index 000000000000..b4bbe81c92ff --- /dev/null +++ b/libc/test/src/sys/ioctl/CMakeLists.txt @@ -0,0 +1,3 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${LIBC_TARGET_OS}) +endif() diff --git a/libc/test/src/sys/ioctl/linux/CMakeLists.txt b/libc/test/src/sys/ioctl/linux/CMakeLists.txt new file mode 100644 index 000000000000..2df67e9d9cbd --- /dev/null +++ b/libc/test/src/sys/ioctl/linux/CMakeLists.txt @@ -0,0 +1,18 @@ +add_custom_target(libc_sys_ioctl_unittests) + +add_libc_unittest( + ioctl_test + SUITE + libc_sys_ioctl_unittests + SRCS + ioctl_test.cpp + DEPENDS + libc.hdr.sys_ioctl_macros + libc.src.sys.ioctl.ioctl + libc.src.errno.errno + libc.src.fcntl.open + libc.src.unistd.close + libc.src.unistd.read + libc.src.unistd.write +) + diff --git a/libc/test/src/sys/ioctl/linux/ioctl_test.cpp b/libc/test/src/sys/ioctl/linux/ioctl_test.cpp new file mode 100644 index 000000000000..b76dc14824c9 --- /dev/null +++ b/libc/test/src/sys/ioctl/linux/ioctl_test.cpp @@ -0,0 +1,75 @@ +//===-- Unittests for ioctl -----------------------------------------------===// +// +// 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 "src/__support/libc_errno.h" +#include "src/fcntl/open.h" +#include "src/sys/ioctl/ioctl.h" +#include "src/unistd/close.h" +#include "src/unistd/read.h" +#include "src/unistd/write.h" + +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" + +#include "hdr/sys_stat_macros.h" + +#include "hdr/sys_ioctl_macros.h" + +using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + +TEST(LlvmLibcSysIoctlTest, InvalidCommandAndFIONREAD) { + LIBC_NAMESPACE::libc_errno = 0; + + // Setup the test file + constexpr const char *TEST_FILE_NAME = "ioctl.test"; + constexpr const char TEST_MSG[] = "ioctl test"; + constexpr int TEST_MSG_SIZE = sizeof(TEST_MSG) - 1; + auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME); + int new_test_file_fd = LIBC_NAMESPACE::open( + TEST_FILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + ASSERT_THAT( + (int)LIBC_NAMESPACE::write(new_test_file_fd, TEST_MSG, TEST_MSG_SIZE), + Succeeds(TEST_MSG_SIZE)); + ASSERT_ERRNO_SUCCESS(); + ASSERT_THAT(LIBC_NAMESPACE::close(new_test_file_fd), Succeeds(0)); + ASSERT_ERRNO_SUCCESS(); + + // Reopen the file for testing + int fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDONLY); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(fd, 0); + + // FIONREAD reports the number of available bytes to read for the passed fd + // This will report the full size of the file, as we haven't read anything yet + int n = -1; + int ret = LIBC_NAMESPACE::ioctl(fd, FIONREAD, &n); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(ret, -1); + ASSERT_EQ(n, TEST_MSG_SIZE); + + // But if we read some bytes... + constexpr int READ_COUNT = 5; + char read_buffer[READ_COUNT]; + ASSERT_THAT((int)LIBC_NAMESPACE::read(fd, read_buffer, READ_COUNT), + Succeeds(READ_COUNT)); + + // ... n should have decreased by the number of bytes we've read + int n_after_reading = -1; + ret = LIBC_NAMESPACE::ioctl(fd, FIONREAD, &n_after_reading); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(ret, -1); + ASSERT_EQ(n - READ_COUNT, n_after_reading); + + // 0xDEADBEEF is just a random nonexistent command; + // calling this should always fail with ENOTTY + ret = LIBC_NAMESPACE::ioctl(fd, 0xDEADBEEF, NULL); + ASSERT_ERRNO_EQ(ENOTTY); + ASSERT_EQ(ret, -1); + + ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); +} diff --git a/libc/test/src/sys/mman/linux/mlock_test.cpp b/libc/test/src/sys/mman/linux/mlock_test.cpp index 88abacad554e..6b81411ca604 100644 --- a/libc/test/src/sys/mman/linux/mlock_test.cpp +++ b/libc/test/src/sys/mman/linux/mlock_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/OSUtil/syscall.h" // For internal syscall function. -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/sys/mman/madvise.h" #include "src/sys/mman/mincore.h" #include "src/sys/mman/mlock.h" @@ -149,9 +149,8 @@ TEST_F(LlvmLibcMlockTest, MLockAll) { Succeeds()); auto retval = LIBC_NAMESPACE::mlockall(MCL_CURRENT); if (retval == -1) { - EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || - LIBC_NAMESPACE::libc_errno == EPERM); - LIBC_NAMESPACE::libc_errno = 0; + EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM); + libc_errno = 0; return; } unsigned char vec; @@ -163,9 +162,8 @@ TEST_F(LlvmLibcMlockTest, MLockAll) { { auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE); if (retval == -1) { - EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || - LIBC_NAMESPACE::libc_errno == EPERM); - LIBC_NAMESPACE::libc_errno = 0; + EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM); + libc_errno = 0; return; } PageHolder holder; @@ -180,9 +178,8 @@ TEST_F(LlvmLibcMlockTest, MLockAll) { { auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE | MCL_ONFAULT); if (retval == -1) { - EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || - LIBC_NAMESPACE::libc_errno == EPERM); - LIBC_NAMESPACE::libc_errno = 0; + EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM); + libc_errno = 0; return; } PageHolder holder; diff --git a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp index 455a82678e18..ba0ee4f09109 100644 --- a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp +++ b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/fcntl/open.h" #include "src/sys/stat/mkdirat.h" #include "src/sys/statvfs/fstatvfs.h" @@ -41,7 +41,7 @@ TEST_F(LlvmLibcSysFStatvfsTest, FStatvfsInvalidPath) { // Always delete the folder so that we start in a consistent state. LIBC_NAMESPACE::rmdir(TEST_DIR); - LIBC_NAMESPACE::libc_errno = 0; // Reset errno + libc_errno = 0; // Reset errno ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU), Succeeds(0)); diff --git a/libc/test/src/sys/statvfs/linux/statvfs_test.cpp b/libc/test/src/sys/statvfs/linux/statvfs_test.cpp index f356bb3d277b..327dec07a1b7 100644 --- a/libc/test/src/sys/statvfs/linux/statvfs_test.cpp +++ b/libc/test/src/sys/statvfs/linux/statvfs_test.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "hdr/fcntl_macros.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" -#include "src/errno/libc_errno.h" #include "src/sys/stat/mkdirat.h" #include "src/sys/statvfs/statvfs.h" #include "src/unistd/rmdir.h" @@ -37,7 +37,7 @@ TEST_F(LlvmLibcSysStatvfsTest, StatvfsInvalidPath) { // Always delete the folder so that we start in a consistent state. LIBC_NAMESPACE::rmdir(TEST_DIR); - LIBC_NAMESPACE::libc_errno = 0; // Reset errno + libc_errno = 0; // Reset errno ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU), Succeeds(0)); diff --git a/libc/test/src/sys/time/setitimer_test.cpp b/libc/test/src/sys/time/setitimer_test.cpp index 16d33fdf1e4f..115f9e662ed4 100644 --- a/libc/test/src/sys/time/setitimer_test.cpp +++ b/libc/test/src/sys/time/setitimer_test.cpp @@ -24,7 +24,7 @@ static bool timer_fired(false); extern "C" void handle_sigalrm(int) { timer_fired = true; } TEST_F(LlvmLibcSysTimeSetitimerTest, SmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; struct sigaction sa; sa.sa_handler = handle_sigalrm; LIBC_NAMESPACE::sigemptyset(&sa.sa_mask); diff --git a/libc/test/src/termios/termios_test.cpp b/libc/test/src/termios/termios_test.cpp index f8fc09a8bbf0..5ec169a886b1 100644 --- a/libc/test/src/termios/termios_test.cpp +++ b/libc/test/src/termios/termios_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/fcntl/open.h" #include "src/termios/cfgetispeed.h" #include "src/termios/cfgetospeed.h" @@ -30,21 +30,21 @@ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; TEST(LlvmLibcTermiosTest, SpeedSmokeTest) { struct termios t; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, B50), Succeeds(0)); ASSERT_EQ(LIBC_NAMESPACE::cfgetispeed(&t), speed_t(B50)); ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, B75), Succeeds(0)); ASSERT_EQ(LIBC_NAMESPACE::cfgetospeed(&t), speed_t(B75)); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, ~CBAUD), Fails(EINVAL)); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, ~CBAUD), Fails(EINVAL)); } TEST(LlvmLibcTermiosTest, GetAttrSmokeTest) { struct termios t; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; int fd = LIBC_NAMESPACE::open("/dev/tty", O_RDONLY); if (fd < 0) return; // When /dev/tty is not available, no point continuing. @@ -54,7 +54,7 @@ TEST(LlvmLibcTermiosTest, GetAttrSmokeTest) { } TEST(LlvmLibcTermiosTest, TcGetSidSmokeTest) { - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; int fd = LIBC_NAMESPACE::open("/dev/tty", O_RDONLY); if (fd < 0) return; // When /dev/tty is not available, no point continuing. diff --git a/libc/test/src/time/asctime_r_test.cpp b/libc/test/src/time/asctime_r_test.cpp index b595cfe02486..d840248b7df4 100644 --- a/libc/test/src/time/asctime_r_test.cpp +++ b/libc/test/src/time/asctime_r_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/asctime_r.h" #include "src/time/time_constants.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/time/asctime_test.cpp b/libc/test/src/time/asctime_test.cpp index 169a7463a303..cad25fffc65a 100644 --- a/libc/test/src/time/asctime_test.cpp +++ b/libc/test/src/time/asctime_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/asctime.h" #include "test/UnitTest/Test.h" #include "test/src/time/TmHelper.h" diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp index 27011b7e0fbd..fe43877aa499 100644 --- a/libc/test/src/time/ctime_r_test.cpp +++ b/libc/test/src/time/ctime_r_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/ctime_r.h" #include "src/time/time_constants.h" #include "test/UnitTest/Test.h" diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp index 6f1168f0b668..5ff69f6619b4 100644 --- a/libc/test/src/time/ctime_test.cpp +++ b/libc/test/src/time/ctime_test.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/ctime.h" #include "test/UnitTest/Test.h" #include "test/src/time/TmHelper.h" diff --git a/libc/test/src/time/gmtime_test.cpp b/libc/test/src/time/gmtime_test.cpp index 6af5a18d3699..41236665d2ea 100644 --- a/libc/test/src/time/gmtime_test.cpp +++ b/libc/test/src/time/gmtime_test.cpp @@ -8,7 +8,7 @@ #include "hdr/types/struct_tm.h" #include "src/__support/CPP/limits.h" // INT_MAX, INT_MIN -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/gmtime.h" #include "src/time/time_constants.h" #include "test/UnitTest/ErrnoSetterMatcher.h" @@ -30,7 +30,7 @@ TEST(LlvmLibcGmTime, OutOfRange) { EXPECT_TRUE(tm_data == nullptr); ASSERT_ERRNO_EQ(EOVERFLOW); - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; seconds = INT_MIN * static_cast( diff --git a/libc/test/src/time/nanosleep_test.cpp b/libc/test/src/time/nanosleep_test.cpp index d4f98e29bd98..e0200ff3aaa2 100644 --- a/libc/test/src/time/nanosleep_test.cpp +++ b/libc/test/src/time/nanosleep_test.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "hdr/types/struct_timespec.h" -#include "src/errno/libc_errno.h" +#include "src/__support/libc_errno.h" #include "src/time/nanosleep.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" @@ -17,7 +17,7 @@ namespace cpp = LIBC_NAMESPACE::cpp; TEST(LlvmLibcNanosleep, SmokeTest) { // TODO: When we have the code to read clocks, test that time has passed. using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; - LIBC_NAMESPACE::libc_errno = 0; + libc_errno = 0; struct timespec tim = {1, 500}; struct timespec tim2 = {0, 0}; diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 6293e8e3d55c..184e482c895b 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -23,6 +23,20 @@ add_libc_test( libc.src.wchar.btowc ) +add_libc_test( + mbrtowc_test + SUITE + libc_wchar_unittests + SRCS + mbrtowc_test.cpp + DEPENDS + libc.src.__support.libc_errno + libc.src.string.memset + libc.src.wchar.mbrtowc + libc.hdr.types.mbstate_t + libc.hdr.types.wchar_t +) + add_libc_test( wctob_test SUITE @@ -33,6 +47,20 @@ add_libc_test( libc.src.wchar.wctob ) +add_libc_test( + wcrtomb_test + SUITE + libc_wchar_unittests + SRCS + wcrtomb_test.cpp + DEPENDS + libc.src.wchar.wcrtomb + libc.src.string.memset + libc.hdr.types.wchar_t + libc.hdr.types.mbstate_t + libc.src.__support.libc_errno +) + add_libc_test( wmemset_test SUITE @@ -145,6 +173,16 @@ add_libc_test( libc.src.wchar.wmemcpy ) +add_libc_test( + wmemmove_test + SUITE + libc_wchar_unittests + SRCS + wmemmove_test.cpp + DEPENDS + libc.src.wchar.wmemmove +) + add_libc_test( wcsncpy_test SUITE diff --git a/libc/test/src/wchar/mbrtowc_test.cpp b/libc/test/src/wchar/mbrtowc_test.cpp new file mode 100644 index 000000000000..69dcf00fde20 --- /dev/null +++ b/libc/test/src/wchar/mbrtowc_test.cpp @@ -0,0 +1,172 @@ +//===-- Unittests for mbrtowc ---------------------------------------------===// +// +// 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 "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/libc_errno.h" +#include "src/string/memset.h" +#include "src/wchar/mbrtowc.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcMBRToWC, OneByte) { + const char *ch = "A"; + wchar_t dest[2]; + // Testing if it works with nullptr mbstate_t + mbstate_t *mb = nullptr; + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(*dest), 'A'); + ASSERT_EQ(static_cast(n), 1); + + // Should fail since we have not read enough + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 0, mb); + ASSERT_EQ(static_cast(n), -2); +} + +TEST(LlvmLibcMBRToWC, TwoByte) { + const char ch[2] = {static_cast(0xC2), + static_cast(0x8E)}; // Ž car symbol + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, mb); + ASSERT_EQ(static_cast(*dest), 142); + ASSERT_EQ(static_cast(n), 2); + + // Should fail since we have not read enough + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(n), -2); + // Should pass after reading one more byte + n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 1, mb); + ASSERT_EQ(static_cast(n), 1); + ASSERT_EQ(static_cast(*dest), 142); +} + +TEST(LlvmLibcMBRToWC, ThreeByte) { + const char ch[3] = {static_cast(0xE2), static_cast(0x88), + static_cast(0x91)}; // ∑ sigma symbol + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 3, mb); + ASSERT_EQ(static_cast(*dest), 8721); + ASSERT_EQ(static_cast(n), 3); + + // Should fail since we have not read enough + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(n), -2); + // Should pass after reading two more bytes + n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 2, mb); + ASSERT_EQ(static_cast(n), 2); + ASSERT_EQ(static_cast(*dest), 8721); +} + +TEST(LlvmLibcMBRToWC, FourByte) { + const char ch[4] = {static_cast(0xF0), static_cast(0x9F), + static_cast(0xA4), + static_cast(0xA1)}; // 🤡 clown emoji + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, mb); + ASSERT_EQ(static_cast(*dest), 129313); + ASSERT_EQ(static_cast(n), 4); + + // Should fail since we have not read enough + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, mb); + ASSERT_EQ(static_cast(n), -2); + // Should pass after reading two more bytes + n = LIBC_NAMESPACE::mbrtowc(dest, ch + 2, 2, mb); + ASSERT_EQ(static_cast(n), 2); + ASSERT_EQ(static_cast(*dest), 129313); +} + +TEST(LlvmLibcMBRToWC, InvalidByte) { + const char ch[1] = {static_cast(0x80)}; + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(n), -1); + ASSERT_EQ(static_cast(libc_errno), EILSEQ); +} + +TEST(LlvmLibcMBRToWC, InvalidMultiByte) { + const char ch[4] = {static_cast(0x80), static_cast(0x00), + static_cast(0x80), + static_cast(0x00)}; // invalid sequence of bytes + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // Trying to push all 4 should error + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, mb); + ASSERT_EQ(static_cast(n), -1); + ASSERT_EQ(static_cast(libc_errno), EILSEQ); + // Trying to push just the first one should error + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(n), -1); + ASSERT_EQ(static_cast(libc_errno), EILSEQ); + // Trying to push the second and third should correspond to null wc + n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 2, mb); + ASSERT_EQ(static_cast(n), 0); + ASSERT_TRUE(*dest == L'\0'); +} + +TEST(LlvmLibcMBRToWC, InvalidLastByte) { + // Last byte is invalid since it does not have correct starting sequence. + // 0xC0 --> 11000000 starting sequence should be 10xxxxxx + const char ch[4] = {static_cast(0xF1), static_cast(0x80), + static_cast(0x80), static_cast(0xC0)}; + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // Trying to push all 4 should error + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, mb); + ASSERT_EQ(static_cast(n), -1); + ASSERT_EQ(static_cast(libc_errno), EILSEQ); +} + +TEST(LlvmLibcMBRToWC, ValidTwoByteWithExtraRead) { + const char ch[3] = {static_cast(0xC2), static_cast(0x8E), + static_cast(0x80)}; + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // Trying to push all 3 should return valid 2 byte + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 3, mb); + ASSERT_EQ(static_cast(n), 2); + ASSERT_EQ(static_cast(*dest), 142); +} + +TEST(LlvmLibcMBRToWC, TwoValidTwoBytes) { + const char ch[4] = {static_cast(0xC2), static_cast(0x8E), + static_cast(0xC7), static_cast(0x8C)}; + wchar_t dest[2]; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // mbstate should reset after reading first one + size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, mb); + ASSERT_EQ(static_cast(n), 2); + ASSERT_EQ(static_cast(*dest), 142); + n = LIBC_NAMESPACE::mbrtowc(dest + 1, ch + 2, 2, mb); + ASSERT_EQ(static_cast(n), 2); + ASSERT_EQ(static_cast(*(dest + 1)), 460); +} + +TEST(LlvmLibcMBRToWC, NullString) { + wchar_t dest[2] = {L'O', L'K'}; + mbstate_t *mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // reading on nullptr should return 0 + size_t n = LIBC_NAMESPACE::mbrtowc(dest, nullptr, 2, mb); + ASSERT_EQ(static_cast(n), 0); + ASSERT_TRUE(dest[0] == L'O'); + // reading a null terminator should return 0 + const char *ch = "\0"; + n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb); + ASSERT_EQ(static_cast(n), 0); +} diff --git a/libc/test/src/wchar/wcrtomb_test.cpp b/libc/test/src/wchar/wcrtomb_test.cpp new file mode 100644 index 000000000000..c06b39ae0143 --- /dev/null +++ b/libc/test/src/wchar/wcrtomb_test.cpp @@ -0,0 +1,93 @@ +//===-- Unittests for wcrtomb --------------------------------------------===// +// +// 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 "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/libc_errno.h" +#include "src/string/memset.h" +#include "src/wchar/wcrtomb.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWCRToMBTest, OneByte) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + wchar_t wc = L'U'; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state); + ASSERT_EQ(cnt, static_cast(1)); + ASSERT_EQ(mb[0], 'U'); +} + +TEST(LlvmLibcWCRToMBTest, TwoByte) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + // testing utf32: 0xff -> utf8: 0xc3 0xbf + wchar_t wc = 0xff; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state); + ASSERT_EQ(cnt, static_cast(2)); + ASSERT_EQ(mb[0], static_cast(0xc3)); + ASSERT_EQ(mb[1], static_cast(0xbf)); +} + +TEST(LlvmLibcWCRToMBTest, ThreeByte) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + // testing utf32: 0xac15 -> utf8: 0xea 0xb0 0x95 + wchar_t wc = 0xac15; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state); + ASSERT_EQ(cnt, static_cast(3)); + ASSERT_EQ(mb[0], static_cast(0xea)); + ASSERT_EQ(mb[1], static_cast(0xb0)); + ASSERT_EQ(mb[2], static_cast(0x95)); +} + +TEST(LlvmLibcWCRToMBTest, FourByte) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + // testing utf32: 0x1f921 -> utf8: 0xf0 0x9f 0xa4 0xa1 + wchar_t wc = 0x1f921; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state); + ASSERT_EQ(cnt, static_cast(4)); + ASSERT_EQ(mb[0], static_cast(0xf0)); + ASSERT_EQ(mb[1], static_cast(0x9f)); + ASSERT_EQ(mb[2], static_cast(0xa4)); + ASSERT_EQ(mb[3], static_cast(0xa1)); +} + +TEST(LlvmLibcWCRToMBTest, NullString) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + wchar_t wc = L'A'; + char mb[4]; + + // should be equivalent to the call wcrtomb(buf, L'\0', state) + size_t cnt1 = LIBC_NAMESPACE::wcrtomb(nullptr, wc, &state); + size_t cnt2 = LIBC_NAMESPACE::wcrtomb(mb, L'\0', &state); + + ASSERT_EQ(cnt1, cnt2); +} + +TEST(LlvmLibcWCRToMBTest, NullState) { + wchar_t wc = L'A'; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, nullptr); + ASSERT_EQ(cnt, static_cast(1)); +} + +TEST(LlvmLibcWCRToMBTest, InvalidWchar) { + mbstate_t state; + LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t)); + wchar_t wc = 0x12ffff; + char mb[4]; + size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state); + ASSERT_EQ(cnt, static_cast(-1)); + ASSERT_EQ(static_cast(libc_errno), EILSEQ); +} diff --git a/libc/test/src/wchar/wmemmove_test.cpp b/libc/test/src/wchar/wmemmove_test.cpp new file mode 100644 index 000000000000..d23aa0f0b3af --- /dev/null +++ b/libc/test/src/wchar/wmemmove_test.cpp @@ -0,0 +1,111 @@ +//===-- Unittests for wmemmove --------------------------------------------===// +// +// 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 "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/wchar/wmemmove.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWMemmoveTest, MoveZeroByte) { + wchar_t buffer[] = {L'a', L'b', L'y', L'z'}; + + wchar_t *ret = LIBC_NAMESPACE::wmemmove(buffer, buffer + 2, 0); + EXPECT_EQ(ret, buffer); + + const wchar_t expected[] = {L'a', L'b', L'y', L'z'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); + EXPECT_TRUE(buffer[2] == expected[2]); + EXPECT_TRUE(buffer[3] == expected[3]); +} + +TEST(LlvmLibcWMemmoveTest, DstAndSrcPointToSameAddress) { + wchar_t buffer[] = {L'a', L'b'}; + + wchar_t *ret = LIBC_NAMESPACE::wmemmove(buffer, buffer, 1); + EXPECT_EQ(ret, buffer); + + const wchar_t expected[] = {L'a', L'b'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); +} + +TEST(LlvmLibcWMemmoveTest, DstStartsBeforeSrc) { + // Set boundary at beginning and end for not overstepping when + // copy forward or backward. + wchar_t buffer[] = {L'z', L'a', L'b', L'c', L'z'}; + + wchar_t *dst = buffer + 1; + wchar_t *ret = LIBC_NAMESPACE::wmemmove(dst, buffer + 2, 2); + EXPECT_EQ(ret, dst); + + const wchar_t expected[] = {L'z', L'b', L'c', L'c', L'z'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); + EXPECT_TRUE(buffer[2] == expected[2]); + EXPECT_TRUE(buffer[3] == expected[3]); + EXPECT_TRUE(buffer[4] == expected[4]); +} + +TEST(LlvmLibcWMemmoveTest, DstStartsAfterSrc) { + wchar_t buffer[] = {L'z', L'a', L'b', L'c', L'z'}; + + wchar_t *dst = buffer + 2; + wchar_t *ret = LIBC_NAMESPACE::wmemmove(dst, buffer + 1, 2); + EXPECT_EQ(ret, dst); + + const wchar_t expected[] = {L'z', L'a', L'a', L'b', L'z'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); + EXPECT_TRUE(buffer[2] == expected[2]); + EXPECT_TRUE(buffer[3] == expected[3]); + EXPECT_TRUE(buffer[4] == expected[4]); +} + +// e.g. `Dst` follow `src`. +// str: [abcdefghij] +// [__src_____] +// [_____Dst__] +TEST(LlvmLibcWMemmoveTest, SrcFollowDst) { + wchar_t buffer[] = {L'z', L'a', L'b', L'z'}; + + wchar_t *dst = buffer + 1; + wchar_t *ret = LIBC_NAMESPACE::wmemmove(dst, buffer + 2, 1); + EXPECT_EQ(ret, dst); + + const char expected[] = {L'z', L'b', L'b', L'z'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); + EXPECT_TRUE(buffer[2] == expected[2]); + EXPECT_TRUE(buffer[3] == expected[3]); +} + +TEST(LlvmLibcWMemmoveTest, DstFollowSrc) { + wchar_t buffer[] = {L'z', L'a', L'b', L'z'}; + + wchar_t *dst = buffer + 2; + wchar_t *ret = LIBC_NAMESPACE::wmemmove(dst, buffer + 1, 1); + EXPECT_EQ(ret, dst); + + const char expected[] = {L'z', L'a', L'a', L'z'}; + EXPECT_TRUE(buffer[0] == expected[0]); + EXPECT_TRUE(buffer[1] == expected[1]); + EXPECT_TRUE(buffer[2] == expected[2]); + EXPECT_TRUE(buffer[3] == expected[3]); +} + +#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER) +TEST(LlvmLibcWMemmoveTest, NullptrCrash) { + wchar_t buffer[] = {L'a', L'b'}; + // Passing in a nullptr should crash the program. + EXPECT_DEATH([&buffer] { LIBC_NAMESPACE::wmemmove(buffer, nullptr, 2); }, + WITH_SIGNAL(-1)); + EXPECT_DEATH([&buffer] { LIBC_NAMESPACE::wmemmove(nullptr, buffer, 2); }, + WITH_SIGNAL(-1)); +} +#endif // LIBC_HAS_ADDRESS_SANITIZER diff --git a/libcxx/cmake/caches/AndroidNDK.cmake b/libcxx/cmake/caches/AndroidNDK.cmake index 298518781e9b..1a04b7fbb217 100644 --- a/libcxx/cmake/caches/AndroidNDK.cmake +++ b/libcxx/cmake/caches/AndroidNDK.cmake @@ -33,5 +33,5 @@ set(CMAKE_CXX_COMPILER_WORKS ON CACHE BOOL "") # Use adb to push tests to a locally-connected device (e.g. emulator) and run # them. -set(LIBCXX_TEST_CONFIG "llvm-libc++-android-ndk.cfg.in" CACHE STRING "") -set(LIBCXXABI_TEST_CONFIG "llvm-libc++abi-android-ndk.cfg.in" CACHE STRING "") +set(LIBCXX_TEST_CONFIG "llvm-libc++-android.cfg.in" CACHE STRING "") +set(LIBCXXABI_TEST_CONFIG "llvm-libc++abi-android.cfg.in" CACHE STRING "") diff --git a/libcxx/docs/ABIGuarantees.rst b/libcxx/docs/ABIGuarantees.rst index c25aaa8e4233..c7d5afe1080b 100644 --- a/libcxx/docs/ABIGuarantees.rst +++ b/libcxx/docs/ABIGuarantees.rst @@ -40,7 +40,7 @@ significantly. ``_LIBCPP_ABI_NO_ITERATOR_BASES`` --------------------------------- This removes the ``iterator`` base class from ``back_insert_iterator``, ``front_insert_iterator``, ``insert_iterator``, -``istream_iterator``, ``ostream_iterator``, ``ostreambuf_itreator``, ``reverse_iterator``, and ``raw_storage_iterator``. +``istream_iterator``, ``ostream_iterator``, ``ostreambuf_iterator``, ``reverse_iterator``, and ``raw_storage_iterator``. This doesn't directly affect the layout of these types in most cases, but may result in more padding being used when they are used in combination, for example ``reverse_iterator>``. @@ -63,7 +63,7 @@ removes these workarounds for platforms that don't care about ABI compatibility. ``_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING`` ------------------------------------------ -This removes artifical padding from ``_LIBCPP_COMPRESSED_PAIR`` and ``_LIBCPP_COMPRESSED_TRIPLE``. +This removes artificial padding from ``_LIBCPP_COMPRESSED_PAIR`` and ``_LIBCPP_COMPRESSED_TRIPLE``. These macros are used inside the associative and unordered containers, ``deque``, ``forward_list``, ``future``, ``list``, ``basic_string``, ``function``, ``shared_ptr``, ``unique_ptr``, and ``vector`` to stay ABI compatible with the @@ -83,7 +83,7 @@ flag removes that artificial padding. Linking TUs which have been compiled against different releases of libc++ ========================================================================= -libc++ supports linking TUs which have beeen compiled against different releases of libc++ by marking symbols with +libc++ supports linking TUs which have been compiled against different releases of libc++ by marking symbols with hidden visibility and changing the mangling of header-only functions in every release. @@ -92,7 +92,7 @@ Linking TUs which have been compiled with different flags affecting code gen There are a lot of compiler (and library) flags which change the code generated for functions. This includes flags like ``-O1``, which are guaranteed by the compiler to not change the observable behaviour of a correct program, as well as flags like ``-fexceptions``, which **do** change the observable behaviour. libc++ allows linking of TUs which have been -compiled whith specific flags only and makes no guarantees for any of the flags not listed below. +compiled with specific flags only and makes no guarantees for any of the flags not listed below. The flags allowed (in any combination) are: - ``-f[no-]exceptions`` @@ -104,7 +104,7 @@ behave as the flags say. Availability of symbols in the built library (both static and shared) ===================================================================== -In general, libc++ does not make any guarantees about forwards-compability. That is, a TU compiled against new headers +In general, libc++ does not make any guarantees about forwards-compatibility. That is, a TU compiled against new headers may not work with an older library. Vendors who require such support can leverage availability markup. On the other hand, backwards compatibility is generally guaranteed. @@ -166,7 +166,7 @@ There are multiple ABI flags which change which type an alias references: ``_LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE`` ----------------------------------------- -This changes ``deque::iterator`` to avoid requring complete types for ``deque``. +This changes ``deque::iterator`` to avoid requiring complete types for ``deque``. ``_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE`` ------------------------------------------------- @@ -198,7 +198,7 @@ This changes the value of ``regex_constants::syntax_option-type::ECMAScript`` to ``_LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION`` ------------------------------------------- This flag fixes the implementation of CityHash used for ``hash``. The incorrect implementation of -CityHash has the roblem that it drops some bits on the floor. Fixing the implementation changes the hash of values, +CityHash has the problem that it drops some bits on the floor. Fixing the implementation changes the hash of values, resulting in an ABI break. inline namespaces diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index a89d4038785c..3c635e5e46bb 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -376,7 +376,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges_iota`` ``202202L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_ranges_join_with`` *unimplemented* + ``__cpp_lib_ranges_join_with`` ``202202L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges_repeat`` ``202207L`` ---------------------------------------------------------- ----------------- @@ -420,6 +420,10 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_constexpr_algorithms`` ``202306L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_forward_list`` ``202502L`` + ---------------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_list`` ``202502L`` + ---------------------------------------------------------- ----------------- ``__cpp_lib_constexpr_new`` ``202406L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_constexpr_queue`` ``202502L`` diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 6cbc0baf2948..c52bc54f412b 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -47,6 +47,10 @@ Implemented Papers - P1222R4: A Standard ``flat_set`` (`Github `__) - P2897R7: ``aligned_accessor``: An mdspan accessor expressing pointer over-alignment (`Github `__) - P3247R2: Deprecate the notion of trivial types (`Github `__) +- P3372R3: ``constexpr`` containers and adaptors (`Github `__) (Only ``constexpr flat_map`` is implemented) +- P2441R2: ``views::join_with`` (`Github `__) +- P2711R1: Making multi-param constructors of ``views`` ``explicit`` (`Github `__) +- P2770R0: Stashing stashing ``iterators`` for proper flattening (`Github `__) Improvements and New Features ----------------------------- @@ -70,8 +74,9 @@ Improvements and New Features - The segmented iterator optimization for ``std::for_each`` has been backported to C++11. Previously it was only available in C++23 and later. -- The ``std::for_each_n`` algorithm has been optimized for segmented iterators, resulting in a performance improvement of - up to 17.7x for ``std::deque`` iterators, and up to 13.9x for ``std::join_view>>`` iterators. +- The ``std::for_each_n``, ``std::ranges::for_each`` and ``std::ranges::for_each_n`` algorithms have been optimized for + segmented iterators, resulting in a performance improvement of up to 17.7x for ``std::deque`` iterators, and up + to 13.9x for ``std::join_view>>`` iterators. - The ``bitset::to_string`` function has been optimized, resulting in a performance improvement of up to 8.3x for bitsets with uniformly distributed zeros and ones, and up to 13.5x and 16.1x for sparse and dense bitsets, respectively. @@ -99,6 +104,11 @@ Potentially breaking changes - User-defined specializations of ``std::common_reference`` are diagnosed now. To customize the common reference type, ``std::basic_common_reference`` should be specialized instead. +- ``std::function`` used to have allocator support, which was removed from the Standard by `http://wg21.link/p0302r1` + due to issues with its design and inconsistent support from implementations. Previously, libc++ would provide + allocator-aware APIs in ``std::function`` in C++11 and C++14, but ignores the allocator argument in all places but + one. Starting in this release, the allocator argument is always ignored. + Announcements About Future Releases ----------------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index c26363bcda79..574675175a4c 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -47,7 +47,7 @@ "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" "`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","Only ``ranges::iota`` is implemented." -"`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|In Progress|","","" +"`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","" "`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","" "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","" "","","","","","" @@ -103,9 +103,9 @@ "`P2708R1 `__","No Further Fundamentals TSes","2022-11 (Kona)","|Nothing To Do|","","" "","","","","","" "`P0290R4 `__","``apply()`` for ``synchronized_value``","2023-02 (Issaquah)","","","" -"`P2770R0 `__","Stashing stashing ``iterators`` for proper flattening","2023-02 (Issaquah)","|Partial|","","``join_with_view`` hasn't been done yet since this type isn't implemented yet" +"`P2770R0 `__","Stashing stashing ``iterators`` for proper flattening","2023-02 (Issaquah)","|Complete|","21","" "`P2164R9 `__","``views::enumerate``","2023-02 (Issaquah)","","","" -"`P2711R1 `__","Making multi-param constructors of ``views`` ``explicit``","2023-02 (Issaquah)","|In Progress|","","``join_with_view`` hasn't been done yet since this type isn't implemented yet" +"`P2711R1 `__","Making multi-param constructors of ``views`` ``explicit``","2023-02 (Issaquah)","|Complete|","21","" "`P2609R3 `__","Relaxing Ranges Just A Smidge","2023-02 (Issaquah)","|Complete|","20","Implemented as a DR in C++20. Other implementations will do the same." "`P2713R1 `__","Escaping improvements in ``std::format``","2023-02 (Issaquah)","|Complete|","19","" "`P2675R1 `__","``format``'s width estimation is too approximate and not forward compatible","2023-02 (Issaquah)","|Complete|","17","" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index fdf381862d87..d3feecf6513e 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -66,7 +66,7 @@ "`LWG4060 `__","``submdspan`` preconditions do not forbid creating invalid pointer","2024-06 (St. Louis)","","","" "`LWG4061 `__","Should ``std::basic_format_context`` be default-constructible/copyable/movable?","2024-06 (St. Louis)","|Complete|","19","" "`LWG4071 `__","``reference_wrapper`` comparisons are not SFINAE-friendly","2024-06 (St. Louis)","|Complete|","19","" -"`LWG4074 `__","``compatible-joinable-ranges`` is underconstrained","2024-06 (St. Louis)","","","" +"`LWG4074 `__","``compatible-joinable-ranges`` is underconstrained","2024-06 (St. Louis)","|Complete|","21","" "`LWG4076 `__","``concat_view`` should be freestanding","2024-06 (St. Louis)","","","" "`LWG4079 `__","Missing Preconditions in ``concat_view::iterator``\`s conversion constructor","2024-06 (St. Louis)","","","" "`LWG4082 `__","``views::concat(r)`` is well-formed when ``r`` is an ``output_range``","2024-06 (St. Louis)","","","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 3809446a5789..2eb192106977 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -59,7 +59,7 @@ "`P2248R8 `__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","","" "`P2810R4 `__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","" "`P1068R11 `__","Vector API for random number generation","2024-03 (Tokyo)","","","" -"`P2944R3 `__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","Implemented changes to ``reference_wrapper`` and ``pair``" +"`P2944R3 `__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented" "`P2642R6 `__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","" "`P3029R1 `__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19","" "","","","","","" @@ -104,7 +104,7 @@ "`P3137R3 `__","``views::to_input``","2025-02 (Hagenberg)","","","" "`P0472R3 `__","Put ``std::monostate`` in ````","2025-02 (Hagenberg)","|Complete|","21","" "`P3349R1 `__","Converting contiguous iterators to pointers","2025-02 (Hagenberg)","","","" -"`P3372R3 `__","constexpr containers and adaptors","2025-02 (Hagenberg)","","","" +"`P3372R3 `__","constexpr containers and adaptors","2025-02 (Hagenberg)","|In Progress|","","" "`P3378R2 `__","constexpr exception types","2025-02 (Hagenberg)","","","" "`P3441R2 `__","Rename ``simd_split`` to ``simd_chunk``","2025-02 (Hagenberg)","","","" "`P3287R3 `__","Exploration of namespaces for ``std::simd``","2025-02 (Hagenberg)","","","" diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index 9c957e9d20cb..ae9cc87c797f 100644 --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -135,7 +135,7 @@ Compiler Versions Restrictions Support policy Clang 19, 20, 21-git latest two stable releases per `LLVM's release page `_ and the development version AppleClang 15 latest stable release per `Xcode's release page `_ Open XL 17.1.3 (AIX) latest stable release per `Open XL's documentation page `_ -GCC 14 In C++11 or later only latest stable release per `GCC's release page `_ +GCC 15 In C++11 or later only latest stable release per `GCC's release page `_ ============ =================== ========================== ===================== Libc++ also supports common platforms and architectures: diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 90d578384067..039e03026105 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -706,6 +706,7 @@ set(files __ranges/iota_view.h __ranges/istream_view.h __ranges/join_view.h + __ranges/join_with_view.h __ranges/lazy_split_view.h __ranges/movable_box.h __ranges/non_propagating_cache.h diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h index b6c2c7c056ed..4167eec3506e 100644 --- a/libcxx/include/__algorithm/for_each.h +++ b/libcxx/include/__algorithm/for_each.h @@ -12,41 +12,54 @@ #include <__algorithm/for_each_segment.h> #include <__config> +#include <__functional/identity.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/enable_if.h> +#include <__type_traits/invoke.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __for_each(_InputIterator __first, _Sent __last, _Func& __f) { +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +__for_each(_InputIterator __first, _Sent __last, _Func& __f, _Proj& __proj) { for (; __first != __last; ++__first) - __f(*__first); + std::__invoke(__f, std::__invoke(__proj, *__first)); + return __first; } #ifndef _LIBCPP_CXX03_LANG template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function& __func) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator +__for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Func& __func, _Proj& __proj) { using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { - std::__for_each(__lfirst, __llast, __func); + std::__for_each(__lfirst, __llast, __func, __proj); }); + return __last; } #endif // !_LIBCPP_CXX03_LANG -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function -for_each(_InputIterator __first, _InputIterator __last, _Function __f) { - std::__for_each(__first, __last, __f); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Func +for_each(_InputIterator __first, _InputIterator __last, _Func __f) { + __identity __proj; + std::__for_each(__first, __last, __f, __proj); return __f; } _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_FOR_EACH_H diff --git a/libcxx/include/__algorithm/for_each_n.h b/libcxx/include/__algorithm/for_each_n.h index 29351ec39f4e..9a6c6bb5175d 100644 --- a/libcxx/include/__algorithm/for_each_n.h +++ b/libcxx/include/__algorithm/for_each_n.h @@ -13,10 +13,12 @@ #include <__algorithm/for_each.h> #include <__algorithm/for_each_n_segment.h> #include <__config> +#include <__functional/identity.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> #include <__type_traits/disjunction.h> #include <__type_traits/enable_if.h> +#include <__type_traits/invoke.h> #include <__type_traits/negation.h> #include <__utility/convert_to_integral.h> #include <__utility/move.h> @@ -33,16 +35,17 @@ _LIBCPP_BEGIN_NAMESPACE_STD template ::value && _Or< _Not<__is_segmented_iterator<_InputIterator> >, _Not<__has_random_access_local_iterator<_InputIterator> > >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator -__for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f) { +__for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) { typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; _IntegralSize __n = __orig_n; while (__n > 0) { - __f(*__first); + std::__invoke(__f, std::__invoke(__proj, *__first)); ++__first; --__n; } @@ -52,39 +55,42 @@ __for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f) { template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandIter -__for_each_n(_RandIter __first, _Size __orig_n, _Func& __f) { +__for_each_n(_RandIter __first, _Size __orig_n, _Func& __f, _Proj& __proj) { typename std::iterator_traits<_RandIter>::difference_type __n = __orig_n; auto __last = __first + __n; - std::__for_each(__first, __last, __f); - return std::move(__last); + std::__for_each(__first, __last, __f, __proj); + return __last; } #ifndef _LIBCPP_CXX03_LANG template ::value && __is_segmented_iterator<_SegmentedIterator>::value && __has_random_access_iterator_category< typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator -__for_each_n(_SegmentedIterator __first, _Size __orig_n, _Func& __f) { +__for_each_n(_SegmentedIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) { using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; return std::__for_each_n_segment(__first, __orig_n, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { - std::__for_each(__lfirst, __llast, __f); + std::__for_each(__lfirst, __llast, __f, __proj); }); } #endif // !_LIBCPP_CXX03_LANG #if _LIBCPP_STD_VER >= 17 -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator -for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) { - return std::__for_each_n(__first, __orig_n, __f); +for_each_n(_InputIterator __first, _Size __orig_n, _Func __f) { + __identity __proj; + return std::__for_each_n(__first, __orig_n, __f, __proj); } #endif // _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/ranges_for_each.h b/libcxx/include/__algorithm/ranges_for_each.h index de39bc552275..e9c84e8583f8 100644 --- a/libcxx/include/__algorithm/ranges_for_each.h +++ b/libcxx/include/__algorithm/ranges_for_each.h @@ -9,10 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H #define _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H +#include <__algorithm/for_each.h> +#include <__algorithm/for_each_n.h> #include <__algorithm/in_fun_result.h> +#include <__concepts/assignable.h> #include <__config> #include <__functional/identity.h> -#include <__functional/invoke.h> #include <__iterator/concepts.h> #include <__iterator/projected.h> #include <__ranges/access.h> @@ -41,9 +43,17 @@ private: template _LIBCPP_HIDE_FROM_ABI constexpr static for_each_result<_Iter, _Func> __for_each_impl(_Iter __first, _Sent __last, _Func& __func, _Proj& __proj) { - for (; __first != __last; ++__first) - std::invoke(__func, std::invoke(__proj, *__first)); - return {std::move(__first), std::move(__func)}; + // In the case where we have different iterator and sentinel types, the segmented iterator optimization + // in std::for_each will not kick in. Therefore, we prefer std::for_each_n in that case (whenever we can + // obtain the `n`). + if constexpr (!std::assignable_from<_Iter&, _Sent> && std::sized_sentinel_for<_Sent, _Iter>) { + auto __n = __last - __first; + auto __end = std::__for_each_n(std::move(__first), __n, __func, __proj); + return {std::move(__end), std::move(__func)}; + } else { + auto __end = std::__for_each(std::move(__first), std::move(__last), __func, __proj); + return {std::move(__end), std::move(__func)}; + } } public: diff --git a/libcxx/include/__algorithm/ranges_for_each_n.h b/libcxx/include/__algorithm/ranges_for_each_n.h index 603cb723233c..3aab1b79c10a 100644 --- a/libcxx/include/__algorithm/ranges_for_each_n.h +++ b/libcxx/include/__algorithm/ranges_for_each_n.h @@ -9,10 +9,10 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_FOR_EACH_N_H #define _LIBCPP___ALGORITHM_RANGES_FOR_EACH_N_H +#include <__algorithm/for_each_n.h> #include <__algorithm/in_fun_result.h> #include <__config> #include <__functional/identity.h> -#include <__functional/invoke.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> @@ -40,11 +40,8 @@ struct __for_each_n { template > _Func> _LIBCPP_HIDE_FROM_ABI constexpr for_each_n_result<_Iter, _Func> operator()(_Iter __first, iter_difference_t<_Iter> __count, _Func __func, _Proj __proj = {}) const { - while (__count-- > 0) { - std::invoke(__func, std::invoke(__proj, *__first)); - ++__first; - } - return {std::move(__first), std::move(__func)}; + auto __last = std::__for_each_n(std::move(__first), __count, __func, __proj); + return {std::move(__last), std::move(__func)}; } }; diff --git a/libcxx/include/__config b/libcxx/include/__config index eb691469ab64..3c44433ab5a8 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -505,13 +505,6 @@ typedef __char32_t char32_t; # define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI # endif -// TODO: Remove this workaround once we drop support for Clang 16 -# if __has_warning("-Wc++23-extensions") -# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++23-extensions") -# else -# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++2b-extensions") -# endif - // Clang modules take a significant compile time hit when pushing and popping diagnostics. // Since all the headers are marked as system headers unless _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER is defined, we can // simply disable this pushing and popping when _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER isn't defined. @@ -522,7 +515,7 @@ typedef __char32_t char32_t; _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ - _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++23-extensions") \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h index 8f01882934b7..bf193f6d3c62 100644 --- a/libcxx/include/__flat_map/flat_map.h +++ b/libcxx/include/__flat_map/flat_map.h @@ -114,11 +114,12 @@ public: class value_compare { private: _LIBCPP_NO_UNIQUE_ADDRESS key_compare __comp_; - _LIBCPP_HIDE_FROM_ABI value_compare(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare(key_compare __c) : __comp_(__c) {} friend flat_map; public: - _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool + operator()(const_reference __x, const_reference __y) const { return __comp_(__x.first, __y.first); } }; @@ -137,14 +138,14 @@ private: public: // [flat.map.cons], construct/copy/destroy - _LIBCPP_HIDE_FROM_ABI flat_map() noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map() noexcept( is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_MappedContainer> && is_nothrow_default_constructible_v<_Compare>) : __containers_(), __compare_() {} _LIBCPP_HIDE_FROM_ABI flat_map(const flat_map&) = default; - _LIBCPP_HIDE_FROM_ABI flat_map(flat_map&& __other) noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(flat_map&& __other) noexcept( is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_MappedContainer> && is_nothrow_move_constructible_v<_Compare>) # if _LIBCPP_HAS_EXCEPTIONS @@ -165,7 +166,7 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(const flat_map& __other, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(const flat_map& __other, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_tag{}, __alloc, __other.__containers_.keys, @@ -174,7 +175,7 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(flat_map&& __other, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(flat_map&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try # endif // _LIBCPP_HAS_EXCEPTIONS @@ -191,7 +192,7 @@ public: # endif // _LIBCPP_HAS_EXCEPTIONS } - _LIBCPP_HIDE_FROM_ABI flat_map( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map( key_container_type __key_cont, mapped_container_type __mapped_cont, const key_compare& __comp = key_compare()) : __containers_{.keys = std::move(__key_cont), .values = std::move(__mapped_cont)}, __compare_(__comp) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(), @@ -201,7 +202,7 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(const key_container_type& __key_cont, const mapped_container_type& __mapped_cont, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(), @@ -211,7 +212,7 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(const key_container_type& __key_cont, const mapped_container_type& __mapped_cont, const key_compare& __comp, @@ -222,7 +223,7 @@ public: __sort_and_unique(); } - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, key_container_type __key_cont, mapped_container_type __mapped_cont, @@ -236,7 +237,7 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, const key_container_type& __key_cont, const mapped_container_type& __mapped_cont, @@ -250,12 +251,12 @@ public: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI - flat_map(sorted_unique_t, - const key_container_type& __key_cont, - const mapped_container_type& __mapped_cont, - const key_compare& __comp, - const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map( + sorted_unique_t, + const key_container_type& __key_cont, + const mapped_container_type& __mapped_cont, + const key_compare& __comp, + const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_tag{}, __alloc, __key_cont, __mapped_cont, __comp) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__containers_.keys.size() == __containers_.values.size(), "flat_map keys and mapped containers have different size"); @@ -263,21 +264,22 @@ public: __is_sorted_and_unique(__containers_.keys), "Either the key container is not sorted or it contains duplicates"); } - _LIBCPP_HIDE_FROM_ABI explicit flat_map(const key_compare& __comp) : __containers_(), __compare_(__comp) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_map(const key_compare& __comp) + : __containers_(), __compare_(__comp) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(const key_compare& __comp, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(const key_compare& __comp, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI explicit flat_map(const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_map(const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc) {} template requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) : __containers_(), __compare_(__comp) { insert(__first, __last); @@ -285,7 +287,7 @@ public: template requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert(__first, __last); @@ -293,99 +295,105 @@ public: template requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) - _LIBCPP_HIDE_FROM_ABI flat_map(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(__first, __last); } template <_ContainerCompatibleRange _Range> - _LIBCPP_HIDE_FROM_ABI flat_map(from_range_t __fr, _Range&& __rg) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(from_range_t __fr, _Range&& __rg) : flat_map(__fr, std::forward<_Range>(__rg), key_compare()) {} template <_ContainerCompatibleRange _Range, class _Allocator> requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(from_range_t, _Range&& __rg, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(from_range_t, _Range&& __rg, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range> - _LIBCPP_HIDE_FROM_ABI flat_map(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_map(__comp) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(from_range_t, _Range&& __rg, const key_compare& __comp) + : flat_map(__comp) { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange _Range, class _Allocator> requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert_range(std::forward<_Range>(__rg)); } template requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) : __containers_(), __compare_(__comp) { insert(sorted_unique, __first, __last); } template requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) - _LIBCPP_HIDE_FROM_ABI - flat_map(sorted_unique_t, - _InputIterator __first, - _InputIterator __last, - const key_compare& __comp, - const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map( + sorted_unique_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc, __comp) { insert(sorted_unique, __first, __last); } template requires(__has_input_iterator_category<_InputIterator>::value && __allocator_ctor_constraint<_Allocator>) - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : flat_map(__ctor_uses_allocator_empty_tag{}, __alloc) { insert(sorted_unique, __first, __last); } - _LIBCPP_HIDE_FROM_ABI flat_map(initializer_list __il, const key_compare& __comp = key_compare()) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(initializer_list __il, const key_compare& __comp = key_compare()) : flat_map(__il.begin(), __il.end(), __comp) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_map(__il.begin(), __il.end(), __comp, __alloc) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(initializer_list __il, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(initializer_list __il, const _Allocator& __alloc) : flat_map(__il.begin(), __il.end(), __alloc) {} - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, initializer_list __il, const key_compare& __comp = key_compare()) : flat_map(sorted_unique, __il.begin(), __il.end(), __comp) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map(sorted_unique_t, initializer_list __il, const key_compare& __comp, const _Allocator& __alloc) : flat_map(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {} template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(sorted_unique_t, initializer_list __il, const _Allocator& __alloc) : flat_map(sorted_unique, __il.begin(), __il.end(), __alloc) {} - _LIBCPP_HIDE_FROM_ABI flat_map& operator=(initializer_list __il) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map& operator=(initializer_list __il) { clear(); insert(__il); return *this; } - _LIBCPP_HIDE_FROM_ABI flat_map& operator=(const flat_map&) = default; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map& operator=(const flat_map&) = default; - _LIBCPP_HIDE_FROM_ABI flat_map& operator=(flat_map&& __other) noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map& operator=(flat_map&& __other) noexcept( is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_MappedContainer> && is_nothrow_move_assignable_v<_Compare>) { // No matter what happens, we always want to clear the other container before returning @@ -402,49 +410,65 @@ public: } // iterators - _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { return iterator(__containers_.keys.begin(), __containers_.values.begin()); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept { return const_iterator(__containers_.keys.begin(), __containers_.values.begin()); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { return iterator(__containers_.keys.end(), __containers_.values.end()); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept { return const_iterator(__containers_.keys.end(), __containers_.values.end()); } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { return begin(); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { return end(); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(end()); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(begin()); + } // [flat.map.capacity], capacity - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __containers_.keys.empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool empty() const noexcept { + return __containers_.keys.empty(); + } - _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __containers_.keys.size(); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { + return __containers_.keys.size(); + } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept { return std::min(__containers_.keys.max_size(), __containers_.values.max_size()); } // [flat.map.access], element access - _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](const key_type& __x) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& operator[](const key_type& __x) requires is_constructible_v { return try_emplace(__x).first->second; } - _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](key_type&& __x) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& operator[](key_type&& __x) requires is_constructible_v { return try_emplace(std::move(__x)).first->second; @@ -453,11 +477,11 @@ public: template requires(__is_compare_transparent && is_constructible_v && is_constructible_v && !is_convertible_v<_Kp &&, const_iterator> && !is_convertible_v<_Kp &&, iterator>) - _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](_Kp&& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& operator[](_Kp&& __x) { return try_emplace(std::forward<_Kp>(__x)).first->second; } - _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const key_type& __x) { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const key_type&): Key does not exist"); @@ -465,7 +489,7 @@ public: return __it->second; } - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const key_type& __x) const { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const key_type&) const: Key does not exist"); @@ -475,7 +499,7 @@ public: template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI mapped_type& at(const _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const _Kp& __x) { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const K&): Key does not exist"); @@ -485,7 +509,7 @@ public: template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const _Kp& __x) const { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const K&) const: Key does not exist"); @@ -496,45 +520,49 @@ public: // [flat.map.modifiers], modifiers template requires is_constructible_v, _Args...> - _LIBCPP_HIDE_FROM_ABI pair emplace(_Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair emplace(_Args&&... __args) { std::pair __pair(std::forward<_Args>(__args)...); return __try_emplace(std::move(__pair.first), std::move(__pair.second)); } template requires is_constructible_v, _Args...> - _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __hint, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator emplace_hint(const_iterator __hint, _Args&&... __args) { std::pair __pair(std::forward<_Args>(__args)...); return __try_emplace_hint(__hint, std::move(__pair.first), std::move(__pair.second)).first; } - _LIBCPP_HIDE_FROM_ABI pair insert(const value_type& __x) { return emplace(__x); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair insert(const value_type& __x) { + return emplace(__x); + } - _LIBCPP_HIDE_FROM_ABI pair insert(value_type&& __x) { return emplace(std::move(__x)); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair insert(value_type&& __x) { + return emplace(std::move(__x)); + } - _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const_iterator __hint, const value_type& __x) { return emplace_hint(__hint, __x); } - _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const_iterator __hint, value_type&& __x) { return emplace_hint(__hint, std::move(__x)); } template requires is_constructible_v, _PairLike> - _LIBCPP_HIDE_FROM_ABI pair insert(_PairLike&& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair insert(_PairLike&& __x) { return emplace(std::forward<_PairLike>(__x)); } template requires is_constructible_v, _PairLike> - _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _PairLike&& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator insert(const_iterator __hint, _PairLike&& __x) { return emplace_hint(__hint, std::forward<_PairLike>(__x)); } template requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(_InputIterator __first, _InputIterator __last) { if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { __reserve(__last - __first); } @@ -543,7 +571,8 @@ public: template requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) { if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) { __reserve(__last - __first); } @@ -552,7 +581,7 @@ public: } template <_ContainerCompatibleRange _Range> - _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(_Range&& __range) { if constexpr (ranges::sized_range<_Range>) { __reserve(ranges::size(__range)); } @@ -560,19 +589,22 @@ public: __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); } - _LIBCPP_HIDE_FROM_ABI void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list __il) { + insert(__il.begin(), __il.end()); + } - _LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, initializer_list __il) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(sorted_unique_t, initializer_list __il) { insert(sorted_unique, __il.begin(), __il.end()); } - _LIBCPP_HIDE_FROM_ABI containers extract() && { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 containers extract() && { auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); auto __ret = std::move(__containers_); return __ret; } - _LIBCPP_HIDE_FROM_ABI void replace(key_container_type&& __key_cont, mapped_container_type&& __mapped_cont) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + replace(key_container_type&& __key_cont, mapped_container_type&& __mapped_cont) { _LIBCPP_ASSERT_VALID_INPUT_RANGE( __key_cont.size() == __mapped_cont.size(), "flat_map keys and mapped containers have different size"); @@ -586,13 +618,15 @@ public: template requires is_constructible_v - _LIBCPP_HIDE_FROM_ABI pair try_emplace(const key_type& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + try_emplace(const key_type& __key, _Args&&... __args) { return __try_emplace(__key, std::forward<_Args>(__args)...); } template requires is_constructible_v - _LIBCPP_HIDE_FROM_ABI pair try_emplace(key_type&& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + try_emplace(key_type&& __key, _Args&&... __args) { return __try_emplace(std::move(__key), std::forward<_Args>(__args)...); } @@ -600,75 +634,84 @@ public: requires(__is_compare_transparent && is_constructible_v && is_constructible_v && !is_convertible_v<_Kp &&, const_iterator> && !is_convertible_v<_Kp &&, iterator>) - _LIBCPP_HIDE_FROM_ABI pair try_emplace(_Kp&& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair try_emplace(_Kp&& __key, _Args&&... __args) { return __try_emplace(std::forward<_Kp>(__key), std::forward<_Args>(__args)...); } template requires is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator try_emplace(const_iterator __hint, const key_type& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + try_emplace(const_iterator __hint, const key_type& __key, _Args&&... __args) { return __try_emplace_hint(__hint, __key, std::forward<_Args>(__args)...).first; } template requires is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator try_emplace(const_iterator __hint, key_type&& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + try_emplace(const_iterator __hint, key_type&& __key, _Args&&... __args) { return __try_emplace_hint(__hint, std::move(__key), std::forward<_Args>(__args)...).first; } template requires __is_compare_transparent && is_constructible_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator try_emplace(const_iterator __hint, _Kp&& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + try_emplace(const_iterator __hint, _Kp&& __key, _Args&&... __args) { return __try_emplace_hint(__hint, std::forward<_Kp>(__key), std::forward<_Args>(__args)...).first; } template requires is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI pair insert_or_assign(const key_type& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + insert_or_assign(const key_type& __key, _Mapped&& __obj) { return __insert_or_assign(__key, std::forward<_Mapped>(__obj)); } template requires is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI pair insert_or_assign(key_type&& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + insert_or_assign(key_type&& __key, _Mapped&& __obj) { return __insert_or_assign(std::move(__key), std::forward<_Mapped>(__obj)); } template requires __is_compare_transparent && is_constructible_v && is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI pair insert_or_assign(_Kp&& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + insert_or_assign(_Kp&& __key, _Mapped&& __obj) { return __insert_or_assign(std::forward<_Kp>(__key), std::forward<_Mapped>(__obj)); } template requires is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator insert_or_assign(const_iterator __hint, const key_type& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + insert_or_assign(const_iterator __hint, const key_type& __key, _Mapped&& __obj) { return __insert_or_assign(__hint, __key, std::forward<_Mapped>(__obj)); } template requires is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator insert_or_assign(const_iterator __hint, key_type&& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + insert_or_assign(const_iterator __hint, key_type&& __key, _Mapped&& __obj) { return __insert_or_assign(__hint, std::move(__key), std::forward<_Mapped>(__obj)); } template requires __is_compare_transparent && is_constructible_v && is_assignable_v && is_constructible_v - _LIBCPP_HIDE_FROM_ABI iterator insert_or_assign(const_iterator __hint, _Kp&& __key, _Mapped&& __obj) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + insert_or_assign(const_iterator __hint, _Kp&& __key, _Mapped&& __obj) { return __insert_or_assign(__hint, std::forward<_Kp>(__key), std::forward<_Mapped>(__obj)); } - _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(iterator __position) { return __erase(__position.__key_iter_, __position.__mapped_iter_); } - _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __position) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(const_iterator __position) { return __erase(__position.__key_iter_, __position.__mapped_iter_); } - _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type erase(const key_type& __x) { auto __iter = find(__x); if (__iter != end()) { erase(__iter); @@ -680,14 +723,14 @@ public: template requires(__is_compare_transparent && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) - _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type erase(_Kp&& __x) { auto [__first, __last] = equal_range(__x); auto __res = __last - __first; erase(__first, __last); return __res; } - _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(const_iterator __first, const_iterator __last) { auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); auto __key_it = __containers_.keys.erase(__first.__key_iter_, __last.__key_iter_); auto __mapped_it = __containers_.values.erase(__first.__mapped_iter_, __last.__mapped_iter_); @@ -695,7 +738,7 @@ public: return iterator(std::move(__key_it), std::move(__mapped_it)); } - _LIBCPP_HIDE_FROM_ABI void swap(flat_map& __y) noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __y) noexcept { // warning: The spec has unconditional noexcept, which means that // if any of the following functions throw an exception, // std::terminate will be called. @@ -705,133 +748,156 @@ public: ranges::swap(__containers_.values, __y.__containers_.values); } - _LIBCPP_HIDE_FROM_ABI void clear() noexcept { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __containers_.keys.clear(); __containers_.values.clear(); } // observers - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return value_compare(__compare_); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare value_comp() const { + return value_compare(__compare_); + } - _LIBCPP_HIDE_FROM_ABI const key_container_type& keys() const noexcept { return __containers_.keys; } - _LIBCPP_HIDE_FROM_ABI const mapped_container_type& values() const noexcept { return __containers_.values; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const key_container_type& keys() const noexcept { + return __containers_.keys; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_container_type& values() const noexcept { + return __containers_.values; + } // map operations - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const key_type& __x) { + return __find_impl(*this, __x); + } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } - - template - requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) { return __find_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } - template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const { + return __find_impl(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); } - template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const { + return contains(__x) ? 1 : 0; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const { return find(__x) != end(); } - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { return __lower_bound(*this, __x); } + template + requires __is_compare_transparent + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const { + return find(__x) != end(); + } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) { + return __lower_bound(*this, __x); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const key_type& __x) const { return __lower_bound(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) { return __lower_bound(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const { return __lower_bound(*this, __x); } - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { return __upper_bound(*this, __x); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) { + return __upper_bound(*this, __x); + } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const key_type& __x) const { return __upper_bound(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) { return __upper_bound(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const { return __upper_bound(*this, __x); } - _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair equal_range(const key_type& __x) { return __equal_range_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + equal_range(const key_type& __x) const { return __equal_range_impl(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair equal_range(const _Kp& __x) { return __equal_range_impl(*this, __x); } template requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI pair equal_range(const _Kp& __x) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + equal_range(const _Kp& __x) const { return __equal_range_impl(*this, __x); } - friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_map& __x, const flat_map& __y) { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator==(const flat_map& __x, const flat_map& __y) { return ranges::equal(__x, __y); } - friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_map& __x, const flat_map& __y) { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 auto + operator<=>(const flat_map& __x, const flat_map& __y) { return std::lexicographical_compare_three_way( __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } - friend _LIBCPP_HIDE_FROM_ABI void swap(flat_map& __x, flat_map& __y) noexcept { __x.swap(__y); } + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __x, flat_map& __y) noexcept { + __x.swap(__y); + } private: struct __ctor_uses_allocator_tag { - explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_tag() = default; + explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __ctor_uses_allocator_tag() = default; }; struct __ctor_uses_allocator_empty_tag { - explicit _LIBCPP_HIDE_FROM_ABI __ctor_uses_allocator_empty_tag() = default; + explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __ctor_uses_allocator_empty_tag() = default; }; template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI - flat_map(__ctor_uses_allocator_tag, - const _Allocator& __alloc, - _KeyCont&& __key_cont, - _MappedCont&& __mapped_cont, - _CompArg&&... __comp) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_map( + __ctor_uses_allocator_tag, + const _Allocator& __alloc, + _KeyCont&& __key_cont, + _MappedCont&& __mapped_cont, + _CompArg&&... __comp) : __containers_{.keys = std::make_obj_using_allocator( __alloc, std::forward<_KeyCont>(__key_cont)), .values = std::make_obj_using_allocator( @@ -840,12 +906,13 @@ private: template requires __allocator_ctor_constraint<_Allocator> - _LIBCPP_HIDE_FROM_ABI flat_map(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_map(__ctor_uses_allocator_empty_tag, const _Allocator& __alloc, _CompArg&&... __comp) : __containers_{.keys = std::make_obj_using_allocator(__alloc), .values = std::make_obj_using_allocator(__alloc)}, __compare_(std::forward<_CompArg>(__comp)...) {} - _LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool __is_sorted_and_unique(auto&& __key_container) const { auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); } @@ -853,7 +920,7 @@ private: // This function is only used in constructors. So there is not exception handling in this function. // If the function exits via an exception, there will be no flat_map object constructed, thus, there // is no invariant state to preserve - _LIBCPP_HIDE_FROM_ABI void __sort_and_unique() { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __sort_and_unique() { auto __zv = ranges::views::zip(__containers_.keys, __containers_.values); ranges::sort(__zv, __compare_, [](const auto& __p) -> decltype(auto) { return std::get<0>(__p); }); auto __dup_start = ranges::unique(__zv, __key_equiv(__compare_)).begin(); @@ -863,14 +930,16 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static auto __corresponding_mapped_it(_Self&& __self, _KeyIter&& __key_iter) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto + __corresponding_mapped_it(_Self&& __self, _KeyIter&& __key_iter) { return __self.__containers_.values.begin() + static_cast>( ranges::distance(__self.__containers_.keys.begin(), __key_iter)); } template - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + __append_sort_merge_unique(_InputIterator __first, _Sentinel __last) { auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); size_t __num_of_appended = __flat_map_utils::__append(*this, std::move(__first), std::move(__last)); if (__num_of_appended != 0) { @@ -898,7 +967,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto __find_impl(_Self&& __self, const _Kp& __key) { auto __it = __self.lower_bound(__key); auto __last = __self.end(); if (__it == __last || __self.__compare_(__key, __it->first)) { @@ -908,7 +977,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static auto __key_equal_range(_Self&& __self, const _Kp& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto __key_equal_range(_Self&& __self, const _Kp& __key) { auto __it = std::lower_bound(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __key, __self.__compare_); auto __last = __self.__containers_.keys.end(); @@ -919,7 +988,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { auto [__key_first, __key_last] = __key_equal_range(__self, __key); using __iterator_type = ranges::iterator_t; return std::make_pair(__iterator_type(__key_first, __corresponding_mapped_it(__self, __key_first)), @@ -927,7 +996,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static _Res __lower_bound(_Self&& __self, _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static _Res __lower_bound(_Self&& __self, _Kp& __x) { auto __key_iter = std::lower_bound(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __x, __self.__compare_); auto __mapped_iter = __corresponding_mapped_it(__self, __key_iter); @@ -935,7 +1004,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI static _Res __upper_bound(_Self&& __self, _Kp& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static _Res __upper_bound(_Self&& __self, _Kp& __x) { auto __key_iter = std::upper_bound(__self.__containers_.keys.begin(), __self.__containers_.keys.end(), __x, __self.__compare_); auto __mapped_iter = __corresponding_mapped_it(__self, __key_iter); @@ -943,7 +1012,8 @@ private: } template - _LIBCPP_HIDE_FROM_ABI pair __try_emplace(_KeyArg&& __key, _MArgs&&... __mapped_args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + __try_emplace(_KeyArg&& __key, _MArgs&&... __mapped_args) { auto __key_it = std::lower_bound(__containers_.keys.begin(), __containers_.keys.end(), __key, __compare_); auto __mapped_it = __containers_.values.begin() + ranges::distance(__containers_.keys.begin(), __key_it); @@ -962,7 +1032,7 @@ private: } template - _LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool __is_hint_correct(const_iterator __hint, _Kp&& __key) { if (__hint != cbegin() && !__compare_((__hint - 1)->first, __key)) { return false; } @@ -973,7 +1043,8 @@ private: } template - _LIBCPP_HIDE_FROM_ABI pair __try_emplace_hint(const_iterator __hint, _Kp&& __key, _Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + __try_emplace_hint(const_iterator __hint, _Kp&& __key, _Args&&... __args) { if (__is_hint_correct(__hint, __key)) { if (__hint == cend() || __compare_(__key, __hint->first)) { return {__flat_map_utils::__emplace_exact_pos( @@ -994,7 +1065,8 @@ private: } template - _LIBCPP_HIDE_FROM_ABI pair __insert_or_assign(_Kp&& __key, _Mapped&& __mapped) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair + __insert_or_assign(_Kp&& __key, _Mapped&& __mapped) { auto __r = try_emplace(std::forward<_Kp>(__key), std::forward<_Mapped>(__mapped)); if (!__r.second) { __r.first->second = std::forward<_Mapped>(__mapped); @@ -1003,7 +1075,8 @@ private: } template - _LIBCPP_HIDE_FROM_ABI iterator __insert_or_assign(const_iterator __hint, _Kp&& __key, _Mapped&& __mapped) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + __insert_or_assign(const_iterator __hint, _Kp&& __key, _Mapped&& __mapped) { auto __r = __try_emplace_hint(__hint, std::forward<_Kp>(__key), std::forward<_Mapped>(__mapped)); if (!__r.second) { __r.first->second = std::forward<_Mapped>(__mapped); @@ -1011,7 +1084,7 @@ private: return __r.first; } - _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __reserve(size_t __size) { if constexpr (__container_traits<_KeyContainer>::__reservable) { __containers_.keys.reserve(__size); } @@ -1022,7 +1095,8 @@ private: } template - _LIBCPP_HIDE_FROM_ABI iterator __erase(_KIter __key_iter_to_remove, _MIter __mapped_iter_to_remove) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator + __erase(_KIter __key_iter_to_remove, _MIter __mapped_iter_to_remove) { auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); auto __key_iter = __containers_.keys.erase(__key_iter_to_remove); auto __mapped_iter = __containers_.values.erase(__mapped_iter_to_remove); @@ -1032,7 +1106,8 @@ private: template friend typename flat_map<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>::size_type - erase_if(flat_map<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate); + _LIBCPP_CONSTEXPR_SINCE_CXX26 + erase_if(flat_map<_Key2, _Tp2, _Compare2, _KeyContainer2, _MappedContainer2>&, _Predicate); friend __flat_map_utils; @@ -1040,8 +1115,9 @@ private: _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; struct __key_equiv { - _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} - _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_equiv(key_compare __c) : __comp_(__c) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool + operator()(const_reference __x, const_reference __y) const { return !__comp_(std::get<0>(__x), std::get<0>(__y)) && !__comp_(std::get<0>(__y), std::get<0>(__x)); } key_compare __comp_; @@ -1164,8 +1240,9 @@ struct uses_allocator && uses_allocator_v<_MappedContainer, _Allocator>> {}; template -_LIBCPP_HIDE_FROM_ABI typename flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type -erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __flat_map, _Predicate __pred) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + typename flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type + erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __flat_map, _Predicate __pred) { auto __zv = ranges::views::zip(__flat_map.__containers_.keys, __flat_map.__containers_.values); auto __first = __zv.begin(); auto __last = __zv.end(); diff --git a/libcxx/include/__flat_map/key_value_iterator.h b/libcxx/include/__flat_map/key_value_iterator.h index 3ebb653deb19..f163dfc28706 100644 --- a/libcxx/include/__flat_map/key_value_iterator.h +++ b/libcxx/include/__flat_map/key_value_iterator.h @@ -46,7 +46,7 @@ private: struct __arrow_proxy { __reference __ref_; - _LIBCPP_HIDE_FROM_ABI __reference* operator->() { return std::addressof(__ref_); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference* operator->() { return std::addressof(__ref_); } }; __key_iterator __key_iter_; @@ -69,99 +69,113 @@ public: _LIBCPP_HIDE_FROM_ABI __key_value_iterator() = default; - _LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, !_Const> __i) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + __key_value_iterator(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, !_Const> __i) requires _Const && convertible_to && convertible_to : __key_iter_(std::move(__i.__key_iter_)), __mapped_iter_(std::move(__i.__mapped_iter_)) {} - _LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + __key_value_iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter) : __key_iter_(std::move(__key_iter)), __mapped_iter_(std::move(__mapped_iter)) {} - _LIBCPP_HIDE_FROM_ABI __reference operator*() const { return __reference(*__key_iter_, *__mapped_iter_); } - _LIBCPP_HIDE_FROM_ABI __arrow_proxy operator->() const { return __arrow_proxy{**this}; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference operator*() const { + return __reference(*__key_iter_, *__mapped_iter_); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __arrow_proxy operator->() const { return __arrow_proxy{**this}; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator++() { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator++() { ++__key_iter_; ++__mapped_iter_; return *this; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator operator++(int) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator operator++(int) { __key_value_iterator __tmp(*this); ++*this; return __tmp; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator--() { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator--() { --__key_iter_; --__mapped_iter_; return *this; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator operator--(int) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator operator--(int) { __key_value_iterator __tmp(*this); --*this; return __tmp; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator+=(difference_type __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator+=(difference_type __x) { __key_iter_ += __x; __mapped_iter_ += __x; return *this; } - _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator-=(difference_type __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator-=(difference_type __x) { __key_iter_ -= __x; __mapped_iter_ -= __x; return *this; } - _LIBCPP_HIDE_FROM_ABI __reference operator[](difference_type __n) const { return *(*this + __n); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference operator[](difference_type __n) const { + return *(*this + __n); + } - _LIBCPP_HIDE_FROM_ABI friend constexpr bool + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool operator==(const __key_value_iterator& __x, const __key_value_iterator& __y) { return __x.__key_iter_ == __y.__key_iter_; } - _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __key_value_iterator& __x, const __key_value_iterator& __y) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool + operator<(const __key_value_iterator& __x, const __key_value_iterator& __y) { return __x.__key_iter_ < __y.__key_iter_; } - _LIBCPP_HIDE_FROM_ABI friend bool operator>(const __key_value_iterator& __x, const __key_value_iterator& __y) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool + operator>(const __key_value_iterator& __x, const __key_value_iterator& __y) { return __y < __x; } - _LIBCPP_HIDE_FROM_ABI friend bool operator<=(const __key_value_iterator& __x, const __key_value_iterator& __y) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool + operator<=(const __key_value_iterator& __x, const __key_value_iterator& __y) { return !(__y < __x); } - _LIBCPP_HIDE_FROM_ABI friend bool operator>=(const __key_value_iterator& __x, const __key_value_iterator& __y) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool + operator>=(const __key_value_iterator& __x, const __key_value_iterator& __y) { return !(__x < __y); } - _LIBCPP_HIDE_FROM_ABI friend auto operator<=>(const __key_value_iterator& __x, const __key_value_iterator& __y) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend auto + operator<=>(const __key_value_iterator& __x, const __key_value_iterator& __y) requires three_way_comparable<__key_iterator> { return __x.__key_iter_ <=> __y.__key_iter_; } - _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator+(const __key_value_iterator& __i, difference_type __n) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator + operator+(const __key_value_iterator& __i, difference_type __n) { auto __tmp = __i; __tmp += __n; return __tmp; } - _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator+(difference_type __n, const __key_value_iterator& __i) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator + operator+(difference_type __n, const __key_value_iterator& __i) { return __i + __n; } - _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator-(const __key_value_iterator& __i, difference_type __n) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator + operator-(const __key_value_iterator& __i, difference_type __n) { auto __tmp = __i; __tmp -= __n; return __tmp; } - _LIBCPP_HIDE_FROM_ABI friend difference_type + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend difference_type operator-(const __key_value_iterator& __x, const __key_value_iterator& __y) { return difference_type(__x.__key_iter_ - __y.__key_iter_); } diff --git a/libcxx/include/__flat_map/utils.h b/libcxx/include/__flat_map/utils.h index acb7dca7ffe9..27687ae8de3b 100644 --- a/libcxx/include/__flat_map/utils.h +++ b/libcxx/include/__flat_map/utils.h @@ -35,7 +35,7 @@ struct __flat_map_utils { // roll back the changes it made to the map. If it cannot roll back the changes, it will // clear the map. template - _LIBCPP_HIDE_FROM_ABI static typename _Map::iterator __emplace_exact_pos( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static typename _Map::iterator __emplace_exact_pos( _Map& __map, _IterK&& __it_key, _IterM&& __it_mapped, _KeyArg&& __key, _MArgs&&... __mapped_args) { auto __on_key_failed = std::__make_exception_guard([&]() noexcept { using _KeyContainer = typename _Map::key_container_type; @@ -82,7 +82,7 @@ struct __flat_map_utils { // TODO: We could optimize this, see // https://github.com/llvm/llvm-project/issues/108624 template - _LIBCPP_HIDE_FROM_ABI static typename _Map::size_type + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static typename _Map::size_type __append(_Map& __map, _InputIterator __first, _Sentinel __last) { typename _Map::size_type __num_appended = 0; for (; __first != __last; ++__first) { diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h index 733f321925a4..dc112ebfd0fa 100644 --- a/libcxx/include/__functional/function.h +++ b/libcxx/include/__functional/function.h @@ -17,13 +17,7 @@ #include <__functional/binary_function.h> #include <__functional/invoke.h> #include <__functional/unary_function.h> -#include <__iterator/iterator_traits.h> #include <__memory/addressof.h> -#include <__memory/allocator.h> -#include <__memory/allocator_destructor.h> -#include <__memory/allocator_traits.h> -#include <__memory/compressed_pair.h> -#include <__memory/unique_ptr.h> #include <__type_traits/aligned_storage.h> #include <__type_traits/decay.h> #include <__type_traits/is_core_convertible.h> @@ -34,9 +28,7 @@ #include <__type_traits/strip_signature.h> #include <__utility/forward.h> #include <__utility/move.h> -#include <__utility/piecewise_construct.h> #include <__utility/swap.h> -#include <__verbose_abort> #include #include @@ -133,104 +125,6 @@ _LIBCPP_HIDE_FROM_ABI bool __not_null(_Rp (^__p)(_Args...)) { namespace __function { -// __alloc_func holds a functor and an allocator. - -template -class __alloc_func; -template -class __default_alloc_func; - -template -class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> { - _LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_); - -public: - using _Target _LIBCPP_NODEBUG = _Fp; - using _Alloc _LIBCPP_NODEBUG = _Ap; - - _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; } - - // WIN32 APIs may define __allocator, so use __get_allocator instead. - _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; } - - _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {} - - _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {} - - _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a) - : __func_(__f), __alloc_(std::move(__a)) {} - - _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a) - : __func_(std::move(__f)), __alloc_(std::move(__a)) {} - - _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) { - return std::__invoke_r<_Rp>(__func_, std::forward<_ArgTypes>(__arg)...); - } - - _LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const { - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA; - _AA __a(__alloc_); - typedef __allocator_destructor<_AA> _Dp; - unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); - ::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a)); - return __hold.release(); - } - - _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { - __func_.~_Fp(); - __alloc_.~_Alloc(); - } - - _LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) { - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __rebind_alloc<__alloc_traits, __alloc_func> _FunAlloc; - _FunAlloc __a(__f->__get_allocator()); - __f->destroy(); - __a.deallocate(__f, 1); - } -}; - -template -struct __deallocating_deleter { - _LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const { - std::__libcpp_deallocate<_Tp>(static_cast<_Tp*>(__p), __element_count(1)); - } -}; - -template -class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> { - _Fp __f_; - -public: - using _Target _LIBCPP_NODEBUG = _Fp; - - _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_; } - - _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(_Target&& __f) : __f_(std::move(__f)) {} - - _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(const _Target& __f) : __f_(__f) {} - - _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) { - return std::__invoke_r<_Rp>(__f_, std::forward<_ArgTypes>(__arg)...); - } - - _LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const { - using _Self = __default_alloc_func; - unique_ptr<_Self, __deallocating_deleter<_Self>> __hold(std::__libcpp_allocate<_Self>(__element_count(1))); - _Self* __res = ::new ((void*)__hold.get()) _Self(__f_); - (void)__hold.release(); - return __res; - } - - _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~_Target(); } - - _LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) { - __f->destroy(); - std::__libcpp_deallocate<__default_alloc_func>(__f, __element_count(1)); - } -}; - // __base provides an abstract interface for copyable functors. template @@ -257,84 +151,38 @@ public: // __func implements __base for a given functor type. -template +template class __func; -template -class __func<_Fp, _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { - __alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> __f_; +template +class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { + _Fp __func_; public: - _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f) : __f_(std::move(__f)) {} + _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f) : __func_(std::move(__f)) {} + _LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f) : __func_(__f) {} - _LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {} + _LIBCPP_HIDE_FROM_ABI_VIRTUAL __base<_Rp(_ArgTypes...)>* __clone() const override { return new __func(__func_); } - _LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, _Alloc&& __a) : __f_(__f, std::move(__a)) {} + _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __clone(__base<_Rp(_ArgTypes...)>* __p) const override { + ::new ((void*)__p) __func(__func_); + } - _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f, _Alloc&& __a) : __f_(std::move(__f), std::move(__a)) {} - - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const; - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual _Rp operator()(_ArgTypes&&... __arg); + _LIBCPP_HIDE_FROM_ABI_VIRTUAL void destroy() _NOEXCEPT override { __func_.~_Fp(); } + _LIBCPP_HIDE_FROM_ABI_VIRTUAL void destroy_deallocate() _NOEXCEPT override { delete this; } + _LIBCPP_HIDE_FROM_ABI_VIRTUAL _Rp operator()(_ArgTypes&&... __arg) override { + return std::__invoke_r<_Rp>(__func_, std::forward<_ArgTypes>(__arg)...); + } # if _LIBCPP_HAS_RTTI - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const void* target(const type_info&) const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const std::type_info& target_type() const _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL const void* target(const type_info& __ti) const _NOEXCEPT override { + if (__ti == typeid(_Fp)) + return std::addressof(__func_); + return nullptr; + } + _LIBCPP_HIDE_FROM_ABI_VIRTUAL const std::type_info& target_type() const _NOEXCEPT override { return typeid(_Fp); } # endif // _LIBCPP_HAS_RTTI }; -template -__base<_Rp(_ArgTypes...)>* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone() const { - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __rebind_alloc<__alloc_traits, __func> _Ap; - _Ap __a(__f_.__get_allocator()); - typedef __allocator_destructor<_Ap> _Dp; - unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); - ::new ((void*)__hold.get()) __func(__f_.__target(), _Alloc(__a)); - return __hold.release(); -} - -template -void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const { - ::new ((void*)__p) __func(__f_.__target(), __f_.__get_allocator()); -} - -template -void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() _NOEXCEPT { - __f_.destroy(); -} - -template -void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate() _NOEXCEPT { - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __rebind_alloc<__alloc_traits, __func> _Ap; - _Ap __a(__f_.__get_allocator()); - __f_.destroy(); - __a.deallocate(this, 1); -} - -template -_Rp __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) { - return __f_(std::forward<_ArgTypes>(__arg)...); -} - -# if _LIBCPP_HAS_RTTI - -template -const void* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target(const type_info& __ti) const _NOEXCEPT { - if (__ti == typeid(_Fp)) - return std::addressof(__f_.__target()); - return nullptr; -} - -template -const std::type_info& __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target_type() const _NOEXCEPT { - return typeid(_Fp); -} - -# endif // _LIBCPP_HAS_RTTI - // __value_func creates a value-type from a __func. template @@ -354,29 +202,19 @@ class __value_func<_Rp(_ArgTypes...)> { public: _LIBCPP_HIDE_FROM_ABI __value_func() _NOEXCEPT : __f_(nullptr) {} - template - _LIBCPP_HIDE_FROM_ABI __value_func(_Fp&& __f, const _Alloc& __a) : __f_(nullptr) { - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __function::__func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun; - typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc; + template , __value_func>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __f_(nullptr) { + typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _Fun; if (__function::__not_null(__f)) { - _FunAlloc __af(__a); - if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value && - is_nothrow_copy_constructible<_FunAlloc>::value) { - __f_ = ::new ((void*)&__buf_) _Fun(std::move(__f), _Alloc(__af)); + if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) { + __f_ = ::new (std::addressof(__buf_)) _Fun(std::move(__f)); } else { - typedef __allocator_destructor<_FunAlloc> _Dp; - unique_ptr<__func, _Dp> __hold(__af.allocate(1), _Dp(__af, 1)); - ::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__a)); - __f_ = __hold.release(); + __f_ = new _Fun(std::move(__f)); } } } - template , __value_func>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __value_func(std::forward<_Fp>(__f), allocator<_Fp>()) {} - _LIBCPP_HIDE_FROM_ABI __value_func(const __value_func& __f) { if (__f.__f_ == nullptr) __f_ = nullptr; @@ -539,12 +377,12 @@ private: template _LIBCPP_HIDE_FROM_ABI static void* __large_clone(const void* __s) { const _Fun* __f = static_cast(__s); - return __f->__clone(); + return new _Fun(*__f); } template _LIBCPP_HIDE_FROM_ABI static void __large_destroy(void* __s) { - _Fun::__destroy_and_delete(static_cast<_Fun*>(__s)); + delete static_cast<_Fun*>(__s); } template @@ -554,7 +392,7 @@ private: std::addressof(__large_destroy<_Fun>), false, # if _LIBCPP_HAS_RTTI - &typeid(typename _Fun::_Target) + &typeid(_Fun) # else nullptr # endif @@ -569,7 +407,7 @@ private: nullptr, false, # if _LIBCPP_HAS_RTTI - &typeid(typename _Fun::_Target) + &typeid(_Fun) # else nullptr # endif @@ -583,42 +421,7 @@ private: template using __fast_forward _LIBCPP_NODEBUG = __conditional_t::value, _Tp, _Tp&&>; -// __policy_invoker calls an instance of __alloc_func held in __policy_storage. - -template -struct __policy_invoker; - -template -struct __policy_invoker<_Rp(_ArgTypes...)> { - typedef _Rp (*__Call)(const __policy_storage*, __fast_forward<_ArgTypes>...); - - __Call __call_; - - // Creates an invoker that throws bad_function_call. - _LIBCPP_HIDE_FROM_ABI __policy_invoker() : __call_(&__call_empty) {} - - // Creates an invoker that calls the given instance of __func. - template - _LIBCPP_HIDE_FROM_ABI static __policy_invoker __create() { - return __policy_invoker(std::addressof(__call_impl<_Fun>)); - } - -private: - _LIBCPP_HIDE_FROM_ABI explicit __policy_invoker(__Call __c) : __call_(__c) {} - - _LIBCPP_HIDE_FROM_ABI static _Rp __call_empty(const __policy_storage*, __fast_forward<_ArgTypes>...) { - std::__throw_bad_function_call(); - } - - template - _LIBCPP_HIDE_FROM_ABI static _Rp __call_impl(const __policy_storage* __buf, __fast_forward<_ArgTypes>... __args) { - _Fun* __f = reinterpret_cast<_Fun*>(__use_small_storage<_Fun>::value ? &__buf->__small : __buf->__large); - return (*__f)(std::forward<_ArgTypes>(__args)...); - } -}; - -// __policy_func uses a __policy and __policy_invoker to create a type-erased, -// copyable functor. +// __policy_func uses a __policy to create a type-erased, copyable functor. template class __policy_func; @@ -628,69 +431,52 @@ class __policy_func<_Rp(_ArgTypes...)> { // Inline storage for small objects. __policy_storage __buf_; - // Calls the value stored in __buf_. This could technically be part of - // policy, but storing it here eliminates a level of indirection inside - // operator(). - typedef __function::__policy_invoker<_Rp(_ArgTypes...)> __invoker; - __invoker __invoker_; + using _ErasedFunc _LIBCPP_NODEBUG = _Rp(const __policy_storage*, __fast_forward<_ArgTypes>...); + + _ErasedFunc* __func_; // The policy that describes how to move / copy / destroy __buf_. Never // null, even if the function is empty. const __policy* __policy_; -public: - _LIBCPP_HIDE_FROM_ABI __policy_func() : __policy_(__policy::__create_empty()) {} - - template - _LIBCPP_HIDE_FROM_ABI __policy_func(_Fp&& __f, const _Alloc& __a) : __policy_(__policy::__create_empty()) { - typedef __alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun; - typedef allocator_traits<_Alloc> __alloc_traits; - typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc; - - if (__function::__not_null(__f)) { - __invoker_ = __invoker::template __create<_Fun>(); - __policy_ = __policy::__create<_Fun>(); - - _FunAlloc __af(__a); - if (__use_small_storage<_Fun>()) { - ::new ((void*)&__buf_.__small) _Fun(std::move(__f), _Alloc(__af)); - } else { - typedef __allocator_destructor<_FunAlloc> _Dp; - unique_ptr<_Fun, _Dp> __hold(__af.allocate(1), _Dp(__af, 1)); - ::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__af)); - __buf_.__large = __hold.release(); - } - } + _LIBCPP_HIDE_FROM_ABI static _Rp __empty_func(const __policy_storage*, __fast_forward<_ArgTypes>...) { + std::__throw_bad_function_call(); } + template + _LIBCPP_HIDE_FROM_ABI static _Rp __call_func(const __policy_storage* __buf, __fast_forward<_ArgTypes>... __args) { + _Fun* __func = reinterpret_cast<_Fun*>(__use_small_storage<_Fun>::value ? &__buf->__small : __buf->__large); + + return std::__invoke_r<_Rp>(*__func, std::forward<_ArgTypes>(__args)...); + } + +public: + _LIBCPP_HIDE_FROM_ABI __policy_func() : __func_(__empty_func), __policy_(__policy::__create_empty()) {} + template , __policy_func>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) { - typedef __default_alloc_func<_Fp, _Rp(_ArgTypes...)> _Fun; - if (__function::__not_null(__f)) { - __invoker_ = __invoker::template __create<_Fun>(); - __policy_ = __policy::__create<_Fun>(); - if (__use_small_storage<_Fun>()) { - ::new ((void*)&__buf_.__small) _Fun(std::move(__f)); + __func_ = __call_func<_Fp>; + __policy_ = __policy::__create<_Fp>(); + if (__use_small_storage<_Fp>()) { + ::new ((void*)&__buf_.__small) _Fp(std::move(__f)); } else { - unique_ptr<_Fun, __deallocating_deleter<_Fun>> __hold(std::__libcpp_allocate<_Fun>(__element_count(1))); - __buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f)); - (void)__hold.release(); + __buf_.__large = ::new _Fp(std::move(__f)); } } } _LIBCPP_HIDE_FROM_ABI __policy_func(const __policy_func& __f) - : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) { + : __buf_(__f.__buf_), __func_(__f.__func_), __policy_(__f.__policy_) { if (__policy_->__clone) __buf_.__large = __policy_->__clone(__f.__buf_.__large); } _LIBCPP_HIDE_FROM_ABI __policy_func(__policy_func&& __f) - : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) { + : __buf_(__f.__buf_), __func_(__f.__func_), __policy_(__f.__policy_) { if (__policy_->__destroy) { - __f.__policy_ = __policy::__create_empty(); - __f.__invoker_ = __invoker(); + __f.__policy_ = __policy::__create_empty(); + __f.__func_ = {}; } } @@ -700,30 +486,30 @@ public: } _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(__policy_func&& __f) { - *this = nullptr; - __buf_ = __f.__buf_; - __invoker_ = __f.__invoker_; - __policy_ = __f.__policy_; - __f.__policy_ = __policy::__create_empty(); - __f.__invoker_ = __invoker(); + *this = nullptr; + __buf_ = __f.__buf_; + __func_ = __f.__func_; + __policy_ = __f.__policy_; + __f.__policy_ = __policy::__create_empty(); + __f.__func_ = {}; return *this; } _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(nullptr_t) { const __policy* __p = __policy_; __policy_ = __policy::__create_empty(); - __invoker_ = __invoker(); + __func_ = {}; if (__p->__destroy) __p->__destroy(__buf_.__large); return *this; } _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __args) const { - return __invoker_.__call_(std::addressof(__buf_), std::forward<_ArgTypes>(__args)...); + return __func_(std::addressof(__buf_), std::forward<_ArgTypes>(__args)...); } _LIBCPP_HIDE_FROM_ABI void swap(__policy_func& __f) { - std::swap(__invoker_, __f.__invoker_); + std::swap(__func_, __f.__func_); std::swap(__policy_, __f.__policy_); std::swap(__buf_, __f.__buf_); } @@ -750,8 +536,8 @@ public: extern "C" void* _Block_copy(const void*); extern "C" void _Block_release(const void*); -template -class __func<_Rp1 (^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { +template +class __func<_Rp1 (^)(_ArgTypes1...), _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { typedef _Rp1 (^__block_type)(_ArgTypes1...); __block_type __f_; @@ -767,15 +553,6 @@ public: // [TODO] add && to save on a retain - _LIBCPP_HIDE_FROM_ABI explicit __func(__block_type __f, const _Alloc& /* unused */) -# if __has_feature(objc_arc) - : __f_(__f) -# else - : __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr)) -# endif - { - } - _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const { _LIBCPP_ASSERT_INTERNAL( false, @@ -954,7 +731,7 @@ function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(std::move(__f)) {} # if _LIBCPP_STD_VER <= 14 template template -function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc& __a, _Fp __f) : __f_(std::move(__f), __a) {} +function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&, _Fp __f) : __f_(std::move(__f)) {} # endif template diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h index b409ad7511f6..c46203a4ca9a 100644 --- a/libcxx/include/__functional/reference_wrapper.h +++ b/libcxx/include/__functional/reference_wrapper.h @@ -11,7 +11,6 @@ #define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H #include <__compare/synth_three_way.h> -#include <__concepts/boolean_testable.h> #include <__config> #include <__functional/weak_result_type.h> #include <__memory/addressof.h> @@ -19,6 +18,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> #include <__type_traits/is_const.h> +#include <__type_traits/is_core_convertible.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> @@ -75,7 +75,7 @@ public: _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) requires requires { - { __x.get() == __y.get() } -> __boolean_testable; + { __x.get() == __y.get() } -> __core_convertible_to; } { return __x.get() == __y.get(); @@ -83,7 +83,7 @@ public: _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y) requires requires { - { __x.get() == __y } -> __boolean_testable; + { __x.get() == __y } -> __core_convertible_to; } { return __x.get() == __y; @@ -91,7 +91,7 @@ public: _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) requires(!is_const_v<_Tp>) && requires { - { __x.get() == __y.get() } -> __boolean_testable; + { __x.get() == __y.get() } -> __core_convertible_to; } { return __x.get() == __y.get(); diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h index 221d36614db0..f727e8ff36df 100644 --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -71,23 +71,6 @@ struct random_access_iterator_tag : public bidirectional_iterator_tag {}; struct contiguous_iterator_tag : public random_access_iterator_tag {}; #endif -template -struct __has_iterator_typedefs { -private: - template - static false_type __test(...); - template - static true_type - __test(__void_t* = nullptr, - __void_t* = nullptr, - __void_t* = nullptr, - __void_t* = nullptr, - __void_t* = nullptr); - -public: - static const bool value = decltype(__test<_Tp>(nullptr, nullptr, nullptr, nullptr, nullptr))::value; -}; - #if _LIBCPP_STD_VER >= 20 // The `cpp17-*-iterator` exposition-only concepts have very similar names to the `Cpp17*Iterator` named requirements @@ -322,6 +305,23 @@ struct __iterator_traits<_Iter, true> is_convertible::value || is_convertible::value > {}; +template +struct __has_iterator_typedefs { +private: + template + static false_type __test(...); + template + static true_type + __test(__void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr); + +public: + static const bool value = decltype(__test<_Tp>(nullptr, nullptr, nullptr, nullptr, nullptr))::value; +}; + // iterator_traits will only have the nested types if Iterator::iterator_category // exists. Else iterator_traits will be an empty class. This is a // conforming extension which allows some programs to compile and behave as diff --git a/libcxx/include/__math/abs.h b/libcxx/include/__math/abs.h index fc3bf3a2c7c3..b780159f11eb 100644 --- a/libcxx/include/__math/abs.h +++ b/libcxx/include/__math/abs.h @@ -39,6 +39,30 @@ template ::value, int> = 0> return __builtin_fabs((double)__x); } +// abs + +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline float abs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); } +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline double abs(double __x) _NOEXCEPT { return __builtin_fabs(__x); } + +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long double abs(long double __x) _NOEXCEPT { + return __builtin_fabsl(__x); +} + +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline int abs(int __x) _NOEXCEPT { + return __builtin_abs(__x); +} + +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long abs(long __x) _NOEXCEPT { + return __builtin_labs(__x); +} + +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long long abs(long long __x) _NOEXCEPT { + return __builtin_llabs(__x); +} + } // namespace __math _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__memory/allocation_guard.h b/libcxx/include/__memory/allocation_guard.h index 66edcd92ed61..016e1a3a429b 100644 --- a/libcxx/include/__memory/allocation_guard.h +++ b/libcxx/include/__memory/allocation_guard.h @@ -49,24 +49,26 @@ struct __allocation_guard { using _Size _LIBCPP_NODEBUG = typename allocator_traits<_Alloc>::size_type; template // we perform the allocator conversion inside the constructor - _LIBCPP_HIDE_FROM_ABI explicit __allocation_guard(_AllocT __alloc, _Size __n) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __allocation_guard(_AllocT __alloc, _Size __n) : __alloc_(std::move(__alloc)), __n_(__n), __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important {} - _LIBCPP_HIDE_FROM_ABI ~__allocation_guard() _NOEXCEPT { __destroy(); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI ~__allocation_guard() _NOEXCEPT { __destroy(); } - _LIBCPP_HIDE_FROM_ABI __allocation_guard(const __allocation_guard&) = delete; - _LIBCPP_HIDE_FROM_ABI __allocation_guard(__allocation_guard&& __other) _NOEXCEPT + __allocation_guard(const __allocation_guard&) = delete; + __allocation_guard& operator=(const __allocation_guard& __other) = delete; + + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __allocation_guard(__allocation_guard&& __other) _NOEXCEPT : __alloc_(std::move(__other.__alloc_)), __n_(__other.__n_), __ptr_(__other.__ptr_) { __other.__ptr_ = nullptr; } - _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(const __allocation_guard& __other) = delete; - _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(__allocation_guard&& __other) _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __allocation_guard& + operator=(__allocation_guard&& __other) _NOEXCEPT { if (std::addressof(__other) != this) { __destroy(); @@ -79,17 +81,17 @@ struct __allocation_guard { return *this; } - _LIBCPP_HIDE_FROM_ABI _Pointer + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI _Pointer __release_ptr() _NOEXCEPT { // not called __release() because it's a keyword in objective-c++ _Pointer __tmp = __ptr_; __ptr_ = nullptr; return __tmp; } - _LIBCPP_HIDE_FROM_ABI _Pointer __get() const _NOEXCEPT { return __ptr_; } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI _Pointer __get() const _NOEXCEPT { return __ptr_; } private: - _LIBCPP_HIDE_FROM_ABI void __destroy() _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __destroy() _NOEXCEPT { if (__ptr_ != nullptr) { allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_); } diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h index 4ba50898fb37..8c7f8dff1b76 100644 --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -16,11 +16,13 @@ #include <__type_traits/conditional.h> #include <__type_traits/conjunction.h> #include <__type_traits/decay.h> +#include <__type_traits/detected_or.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_class.h> #include <__type_traits/is_function.h> #include <__type_traits/is_void.h> +#include <__type_traits/nat.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> #include <__utility/forward.h> @@ -34,67 +36,37 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -// clang-format off -#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \ - template \ - struct NAME : false_type {}; \ - template \ - struct NAME<_Tp, __void_t > : true_type {} -// clang-format on - -_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer); -_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type); - -template ::value> -struct __pointer_traits_element_type {}; - template -struct __pointer_traits_element_type<_Ptr, true> { - using type _LIBCPP_NODEBUG = typename _Ptr::element_type; -}; +struct __pointer_traits_element_type_impl {}; template