diff --git a/.ci/compute_projects.py b/.ci/compute_projects.py index e61b8dc5021f3..40dd0507a9eaf 100644 --- a/.ci/compute_projects.py +++ b/.ci/compute_projects.py @@ -49,7 +49,8 @@ }, "lld": {"bolt", "cross-project-tests"}, # TODO(issues/132795): LLDB should be enabled on clang changes. - "clang": {"clang-tools-extra", "cross-project-tests"}, + "clang": {"clang-tools-extra", "compiler-rt", "cross-project-tests"}, + "clang-tools-extra": {"libc"}, "mlir": {"flang"}, # Test everything if ci scripts are changed. # FIXME: Figure out what is missing and add here. @@ -63,15 +64,7 @@ # This mapping describes runtimes that should be tested when the key project is # touched. -DEPENDENT_RUNTIMES_TO_TEST = { - "clang": {"compiler-rt"}, - "clang-tools-extra": {"libc"}, -} -DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG = { - "llvm": {"libcxx", "libcxxabi", "libunwind"}, - "clang": {"libcxx", "libcxxabi", "libunwind"}, - ".ci": {"libcxx", "libcxxabi", "libunwind"}, -} +DEPENDENT_RUNTIMES_TO_TEST = {"clang": {"libcxx", "libcxxabi", "libunwind"}} EXCLUDE_LINUX = { "cross-project-tests", # TODO(issues/132796): Tests are failing. @@ -100,6 +93,9 @@ "cross-project-tests", "flang", "libc", + "libcxx", + "libcxxabi", + "libunwind", "lldb", "openmp", "polly", @@ -126,10 +122,10 @@ "polly": "check-polly", } -RUNTIMES = {"libcxx", "libcxxabi", "libunwind", "compiler-rt", "libc"} +RUNTIMES = {"libcxx", "libcxxabi", "libunwind"} -def _add_dependencies(projects: Set[str], runtimes: Set[str]) -> Set[str]: +def _add_dependencies(projects: Set[str]) -> Set[str]: projects_with_dependents = set(projects) current_projects_count = 0 while current_projects_count != len(projects_with_dependents): @@ -138,25 +134,9 @@ def _add_dependencies(projects: Set[str], runtimes: Set[str]) -> Set[str]: if project not in PROJECT_DEPENDENCIES: continue projects_with_dependents.update(PROJECT_DEPENDENCIES[project]) - for runtime in runtimes: - if runtime not in PROJECT_DEPENDENCIES: - continue - 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: @@ -174,14 +154,25 @@ def _compute_projects_to_test(modified_projects: Set[str], platform: str) -> Set ): continue projects_to_test.add(dependent_project) - projects_to_test = _exclude_projects(projects_to_test, platform) + 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.") return 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_projects_to_build(projects_to_test: Set[str]) -> Set[str]: + return _add_dependencies(projects_to_test) def _compute_project_check_targets(projects_to_test: Set[str]) -> Set[str]: @@ -193,36 +184,24 @@ def _compute_project_check_targets(projects_to_test: Set[str]) -> Set[str]: return check_targets -def _compute_runtimes_to_test(modified_projects: Set[str], platform: str) -> Set[str]: +def _compute_runtimes_to_test(projects_to_test: Set[str]) -> Set[str]: runtimes_to_test = set() - for modified_project in modified_projects: - if modified_project not in DEPENDENT_RUNTIMES_TO_TEST: - continue - runtimes_to_test.update(DEPENDENT_RUNTIMES_TO_TEST[modified_project]) - return _exclude_projects(runtimes_to_test, platform) + 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 -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 not in DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG: +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 - 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) + 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 _get_modified_projects(modified_files: list[str]) -> Set[str]: @@ -246,19 +225,10 @@ 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) - 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_to_build = _compute_projects_to_build(projects_to_test) projects_check_targets = _compute_project_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 - ) + runtimes_to_build = _compute_runtimes_to_test(projects_to_test) + runtimes_check_targets = _compute_runtime_check_targets(projects_to_test) # 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 @@ -268,9 +238,6 @@ 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 6bc2e34a1cbe1..ae376ea6a43cd 100644 --- a/.ci/compute_projects_test.py +++ b/.ci/compute_projects_test.py @@ -26,10 +26,6 @@ def test_llvm(self): ) self.assertEqual( env_variables["runtimes_check_targets"], - "", - ) - self.assertEqual( - env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -50,10 +46,6 @@ def test_llvm_windows(self): ) self.assertEqual( env_variables["runtimes_check_targets"], - "", - ) - self.assertEqual( - env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -74,10 +66,6 @@ def test_llvm_mac(self): ) self.assertEqual( env_variables["runtimes_check_targets"], - "", - ) - self.assertEqual( - env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -87,21 +75,17 @@ def test_clang(self): ) self.assertEqual( env_variables["projects_to_build"], - "clang;clang-tools-extra;lld;llvm", + "clang;clang-tools-extra;compiler-rt;lld;llvm", ) self.assertEqual( env_variables["project_check_targets"], - "check-clang check-clang-tools", + "check-clang check-clang-tools check-compiler-rt", ) self.assertEqual( - env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind" + env_variables["runtimes_to_build"], "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", ) @@ -120,10 +104,6 @@ def test_clang_windows(self): ) self.assertEqual( env_variables["runtimes_check_targets"], - "", - ) - self.assertEqual( - env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -135,7 +115,6 @@ def test_bolt(self): 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( @@ -145,7 +124,6 @@ def test_lldb(self): 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( @@ -157,7 +135,6 @@ def test_mlir(self): ) 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( @@ -167,7 +144,6 @@ def test_flang(self): 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( @@ -177,7 +153,6 @@ def test_invalid_subproject(self): 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") @@ -185,7 +160,6 @@ def test_top_level_file(self): 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( @@ -195,7 +169,6 @@ def test_exclude_runtiems_in_projects(self): 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( @@ -205,7 +178,6 @@ def test_exclude_docs(self): 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( @@ -215,7 +187,6 @@ def test_exclude_gn(self): 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( @@ -227,15 +198,10 @@ def test_ci(self): "check-clang check-lld check-lldb check-llvm", ) self.assertEqual( - env_variables["runtimes_to_build"], - "libcxx;libcxxabi;libunwind", + env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind" ) self.assertEqual( env_variables["runtimes_check_targets"], - "", - ) - self.assertEqual( - env_variables["runtimes_check_targets_needs_reconfig"], "check-cxx check-cxxabi check-unwind", ) @@ -249,19 +215,6 @@ def test_lldb(self): 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/monolithic-linux.sh b/.ci/monolithic-linux.sh index c350a58679140..7503ea4e6a992 100755 --- a/.ci/monolithic-linux.sh +++ b/.ci/monolithic-linux.sh @@ -57,7 +57,6 @@ 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" @@ -94,15 +93,9 @@ 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 [[ "${runtime_targets_needs_reconfig}" != "" ]]; then +if [[ "${runtimes_targets}" != "" ]]; then echo "--- cmake runtimes C++26" cmake \ @@ -112,7 +105,7 @@ if [[ "${runtime_targets_needs_reconfig}" != "" ]]; then echo "--- ninja runtimes C++26" - ninja -C "${BUILD_DIR}" ${runtime_targets_needs_reconfig} + ninja -C "${BUILD_DIR}" ${runtime_targets} echo "--- cmake runtimes clang modules" @@ -123,5 +116,5 @@ if [[ "${runtime_targets_needs_reconfig}" != "" ]]; then echo "--- ninja runtimes clang modules" - ninja -C "${BUILD_DIR}" ${runtime_targets_needs_reconfig} + ninja -C "${BUILD_DIR}" ${runtime_targets} fi diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 162161ff13fb0..2f8d5745668d9 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/email-check.yaml b/.github/workflows/email-check.yaml index f4481d5cf5583..904ad718f97dd 100644 --- a/.github/workflows/email-check.yaml +++ b/.github/workflows/email-check.yaml @@ -32,7 +32,8 @@ jobs: COMMENT: >- ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
- See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. + See [LLVM Developer Policy](https://llvm.org/docs/DeveloperPolicy.html#email-addresses) and + [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. run: | cat << EOF > comments [{"body" : "$COMMENT"}] diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index 80f2432b78dea..f0bdf6c0b5899 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/premerge.yaml b/.github/workflows/premerge.yaml index 4435a3e905768..709b6d03d94c3 100644 --- a/.github/workflows/premerge.yaml +++ b/.github/workflows/premerge.yaml @@ -56,12 +56,11 @@ 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}" "${runtimes_check_targets_needs_reconfig}" + ./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" - name: Upload Artifacts uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 14957cba50174..ca8b786f4ab69 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -388,6 +388,10 @@ class BinaryFunction { /// The profile data for the number of times the function was executed. uint64_t ExecutionCount{COUNT_NO_PROFILE}; + /// Profile data for the number of times this function was entered from + /// external code (DSO, JIT, etc). + uint64_t ExternEntryCount{0}; + /// Profile match ratio. float ProfileMatchRatio{0.0f}; @@ -1877,6 +1881,10 @@ class BinaryFunction { return *this; } + /// Set the profile data for the number of times the function was entered from + /// external code (DSO/JIT). + void setExternEntryCount(uint64_t Count) { ExternEntryCount = Count; } + /// Adjust execution count for the function by a given \p Count. The value /// \p Count will be subtracted from the current function count. /// @@ -1904,6 +1912,10 @@ class BinaryFunction { /// Return COUNT_NO_PROFILE if there's no profile info. uint64_t getExecutionCount() const { return ExecutionCount; } + /// Return the profile information about the number of times the function was + /// entered from external code (DSO/JIT). + uint64_t getExternEntryCount() const { return ExternEntryCount; } + /// Return the raw profile information about the number of branch /// executions corresponding to this function. uint64_t getRawSampleCount() const { return RawSampleCount; } diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index 3f07a6dc03a4f..96969cf53baca 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -99,24 +99,28 @@ class DataAggregator : public DataReader { uint64_t Addr; }; + /// Container for the unit of branch data. + /// Backwards compatible with legacy use for branches and fall-throughs: + /// - if \p Branch is FT_ONLY or FT_EXTERNAL_ORIGIN, the trace only + /// contains fall-through data, + /// - if \p To is BR_ONLY, the trace only contains branch data. 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; + + 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 +130,11 @@ class DataAggregator : public DataReader { /// 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 +207,8 @@ class DataAggregator : public DataReader { /// 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 +268,14 @@ class DataAggregator : public DataReader { 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 @@ -516,6 +525,21 @@ 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: + case DataAggregator::Trace::FT_EXTERNAL_ORIGIN: + 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/Profile/DataReader.h b/bolt/include/bolt/Profile/DataReader.h index 3c770fed2598f..6f527ba3931d4 100644 --- a/bolt/include/bolt/Profile/DataReader.h +++ b/bolt/include/bolt/Profile/DataReader.h @@ -97,6 +97,9 @@ struct FuncBranchData { /// Total execution count for the function. int64_t ExecutionCount{0}; + /// Total entry count from external code for the function. + uint64_t ExternEntryCount{0}; + /// Indicate if the data was used. bool Used{false}; diff --git a/bolt/include/bolt/Profile/ProfileYAMLMapping.h b/bolt/include/bolt/Profile/ProfileYAMLMapping.h index a8d9a15311d94..41e2bd1651efd 100644 --- a/bolt/include/bolt/Profile/ProfileYAMLMapping.h +++ b/bolt/include/bolt/Profile/ProfileYAMLMapping.h @@ -206,6 +206,7 @@ struct BinaryFunctionProfile { uint32_t Id{0}; llvm::yaml::Hex64 Hash{0}; uint64_t ExecCount{0}; + uint64_t ExternEntryCount{0}; std::vector Blocks; std::vector InlineTree; bool Used{false}; @@ -218,6 +219,7 @@ template <> struct MappingTraits { YamlIO.mapRequired("fid", BFP.Id); YamlIO.mapRequired("hash", BFP.Hash); YamlIO.mapRequired("exec", BFP.ExecCount); + YamlIO.mapOptional("extern", BFP.ExternEntryCount, 0); YamlIO.mapRequired("nblocks", BFP.NumBasicBlocks); YamlIO.mapOptional("blocks", BFP.Blocks, std::vector()); diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 6d1969f5c6c30..b998d7160aae7 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -471,6 +471,8 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation) { OS << "\n Sample Count: " << RawSampleCount; OS << "\n Profile Acc : " << format("%.1f%%", ProfileMatchRatio * 100.0f); } + if (ExternEntryCount) + OS << "\n Extern Entry Count: " << ExternEntryCount; if (opts::PrintDynoStats && !getLayout().block_empty()) { OS << '\n'; diff --git a/bolt/lib/Passes/ProfileQualityStats.cpp b/bolt/lib/Passes/ProfileQualityStats.cpp index dfd74d3dd5719..64cc662c3ab29 100644 --- a/bolt/lib/Passes/ProfileQualityStats.cpp +++ b/bolt/lib/Passes/ProfileQualityStats.cpp @@ -532,6 +532,9 @@ void computeFlowMappings(const BinaryContext &BC, FlowInfo &TotalFlowMap) { std::vector &MaxCountMap = TotalMaxCountMaps[FunctionNum]; std::vector &MinCountMap = TotalMinCountMaps[FunctionNum]; + // Record external entry count into CallGraphIncomingFlows + CallGraphIncomingFlows[FunctionNum] += Function->getExternEntryCount(); + // Update MaxCountMap, MinCountMap, and CallGraphIncomingFlows auto recordCall = [&](const BinaryBasicBlock *SourceBB, const MCSymbol *DestSymbol, uint64_t Count, diff --git a/bolt/lib/Passes/RetpolineInsertion.cpp b/bolt/lib/Passes/RetpolineInsertion.cpp index 98e5a8fba6454..bda26206e16c3 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/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 4022212bcf1b6..178c9d3a63730 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -61,6 +61,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"), @@ -181,6 +187,10 @@ void DataAggregator::start() { "script -F pid,event,ip", /*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 +201,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 +224,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 +514,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 +523,10 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) { deleteTempFiles(); heatmap: + // Sort parsed traces for faster processing. + if (!opts::BasicAggregation) + llvm::sort(Traces, llvm::less_first()); + if (!opts::HeatmapMode) return Error::success(); @@ -589,8 +602,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 +730,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 +787,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,28 +808,21 @@ 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"); + << FromFunc->getPrintName() << ":" << Trace << '\n'); for (auto [From, To] : *FTs) { if (BAT) { From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); @@ -843,17 +835,15 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, } 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 +870,13 @@ 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 (IsReturn) { + if (From) + FromBB = BF.getBasicBlockContainingOffset(From - 1); + else + LLVM_DEBUG(dbgs() << "return to the function start: " << Trace << '\n'); + } else if (Trace.Branch == Trace::EXTERNAL && From == FromBB->getOffset() && + !FromBB->isEntryPoint() && !FromBB->isLandingPad()) { const BinaryBasicBlock *PrevBB = BF.getLayout().getBlock(FromBB->getIndex() - 1); if (PrevBB->getSuccessor(FromBB->getLabel())) { @@ -889,10 +884,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 +905,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; } @@ -1218,14 +1210,15 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { FT_EXTERNAL_ORIGIN // f } 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()) { } @@ -1259,6 +1252,7 @@ std::error_code DataAggregator::parseAggregatedLBREntry() { 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 +1262,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 +1273,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 +1293,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 +1305,26 @@ 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; - - 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; + /// For legacy fall-through types, adjust locations to match Trace container. + if (Type == FT || Type == FT_EXTERNAL_ORIGIN) { + 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. + Addr[0] = Location(Type == FT ? Trace::FT_ONLY : Trace::FT_EXTERNAL_ORIGIN); } - // Add fallthrough trace - if (Type != BRANCH) { - FTInfo &Info = FallthroughLBRs[Trace]; - (Type == FT ? Info.InternCount : Info.ExternCount) += Count; - NumTraces += Count; + /// For legacy branch type, mark Trace To to differentite from a full trace. + if (Type == BRANCH) { + Addr[2] = Location(Trace::BR_ONLY); } + /// 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 +1335,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 +1371,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 +1419,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; } @@ -1554,10 +1533,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"; @@ -1582,23 +1565,14 @@ 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); + 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(); } @@ -2255,6 +2229,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, YamlBF.Id = BF->getFunctionNumber(); YamlBF.Hash = BAT->getBFHash(FuncAddress); YamlBF.ExecCount = BF->getKnownExecutionCount(); + YamlBF.ExternEntryCount = BF->getExternEntryCount(); YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress); const BoltAddressTranslation::BBHashMapTy &BlockMap = BAT->getBBHashMap(FuncAddress); diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index c512394f26a3b..afe24216d7f5d 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -85,6 +85,7 @@ void FuncBranchData::appendFrom(const FuncBranchData &FBD, uint64_t Offset) { } llvm::stable_sort(Data); ExecutionCount += FBD.ExecutionCount; + ExternEntryCount += FBD.ExternEntryCount; for (auto I = FBD.EntryData.begin(), E = FBD.EntryData.end(); I != E; ++I) { assert(I->To.Name == FBD.Name); auto NewElmt = EntryData.insert(EntryData.end(), *I); @@ -269,6 +270,7 @@ Error DataReader::preprocessProfile(BinaryContext &BC) { if (FuncBranchData *FuncData = getBranchDataForNames(Function.getNames())) { setBranchData(Function, FuncData); Function.ExecutionCount = FuncData->ExecutionCount; + Function.ExternEntryCount = FuncData->ExternEntryCount; FuncData->Used = true; } } @@ -419,6 +421,7 @@ void DataReader::matchProfileData(BinaryFunction &BF) { if (fetchProfileForOtherEntryPoints(BF)) { BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD); BF.ExecutionCount = FBD->ExecutionCount; + BF.ExternEntryCount = FBD->ExternEntryCount; BF.RawSampleCount = FBD->getNumExecutedBranches(); } return; @@ -449,6 +452,7 @@ void DataReader::matchProfileData(BinaryFunction &BF) { setBranchData(BF, NewBranchData); NewBranchData->Used = true; BF.ExecutionCount = NewBranchData->ExecutionCount; + BF.ExternEntryCount = NewBranchData->ExternEntryCount; BF.ProfileMatchRatio = 1.0f; break; } @@ -1190,6 +1194,8 @@ std::error_code DataReader::parse() { if (BI.To.IsSymbol && BI.To.Offset == 0) { I = GetOrCreateFuncEntry(BI.To.Name); I->second.ExecutionCount += BI.Branches; + if (!BI.From.IsSymbol) + I->second.ExternEntryCount += BI.Branches; } } diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp index 33ce40ac2eeec..086e47b661e10 100644 --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -176,6 +176,7 @@ bool YAMLProfileReader::parseFunctionProfile( uint64_t FunctionExecutionCount = 0; BF.setExecutionCount(YamlBF.ExecCount); + BF.setExternEntryCount(YamlBF.ExternEntryCount); uint64_t FuncRawBranchCount = 0; for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks) diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index 0ae67a4d35595..1632aa1c6bfe2 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -226,6 +226,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, YamlBF.Hash = BF.getHash(); YamlBF.NumBasicBlocks = BF.size(); YamlBF.ExecCount = BF.getKnownExecutionCount(); + YamlBF.ExternEntryCount = BF.getExternEntryCount(); DenseMap InlineTreeNodeId; if (PseudoProbeDecoder && BF.getGUID()) { std::tie(YamlBF.InlineTree, InlineTreeNodeId) = diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index 18be125d53aeb..c7d664ab09d46 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 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { 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 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { 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 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { } 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 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { 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 @@ class RISCVMCPlusBuilder : public MCPlusBuilder { 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 efba6d54449d3..94933644ef5ef 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/adr-relaxation.s b/bolt/test/AArch64/adr-relaxation.s index a643a62339ba3..864650c3287d8 100644 --- a/bolt/test/AArch64/adr-relaxation.s +++ b/bolt/test/AArch64/adr-relaxation.s @@ -34,7 +34,6 @@ foo: .cfi_startproc cmp x1, x11 b.hi .L2 - mov x0, #0x0 .L2: # CHECK-FOO: : # CHECK-FOO-NEXT: adrp diff --git a/bolt/test/X86/callcont-fallthru.s b/bolt/test/X86/callcont-fallthru.s index 4994cfb541eef..c2ef024db9475 100644 --- a/bolt/test/X86/callcont-fallthru.s +++ b/bolt/test/X86/callcont-fallthru.s @@ -4,29 +4,43 @@ # 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 +# 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 - -## 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 +## 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 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 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 +70,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 +85,18 @@ 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 + +# 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/shrinkwrapping.test b/bolt/test/X86/shrinkwrapping.test index 8581d7e0c0f7b..521b4561b3ba6 100644 --- a/bolt/test/X86/shrinkwrapping.test +++ b/bolt/test/X86/shrinkwrapping.test @@ -8,6 +8,7 @@ REQUIRES: shell RUN: %clangxx %cxxflags -no-pie %S/Inputs/exc4sw.S -o %t.exe -Wl,-q RUN: llvm-bolt %t.exe -o %t --relocs --frame-opt=all \ +RUN: --print-only=main --print-cfg \ RUN: --data=%p/Inputs/exc4sw.fdata --reorder-blocks=cache 2>&1 | \ RUN: FileCheck %s --check-prefix=CHECK-BOLT @@ -19,6 +20,7 @@ RUN: llvm-objdump --dwarf=frames %t | grep -A20 -e \ RUN: `llvm-nm --numeric-sort %t | grep main | tail -n 1 | cut -f1 -d' ' | \ RUN: tail -c9` 2>&1 | FileCheck %s --check-prefix=CHECK-OUTPUT +CHECK-BOLT: Extern Entry Count: 100 CHECK-BOLT: Shrink wrapping moved 2 spills inserting load/stores and 0 spills inserting push/pops CHECK-INPUT: DW_CFA_advance_loc: 2 diff --git a/bolt/test/lit.local.cfg b/bolt/test/lit.local.cfg index d5a6849b27a77..8a61d11f5825f 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/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index 57dd514b90a2b..35058abab0663 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, diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index 708ce09d9e5b2..f8a6859169b01 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -664,7 +664,7 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { case InfoType::IT_typedef: emitBlock(*static_cast(I)); break; - default: + case InfoType::IT_default: llvm::errs() << "Unexpected info, unable to write.\n"; return true; } diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 3ce930c6965db..71a926f1c73e0 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -143,10 +143,11 @@ mergeInfos(std::vector> &Values) { return reduce(Values); case InfoType::IT_typedef: return reduce(Values); - default: + case InfoType::IT_default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "unexpected info type"); } + llvm_unreachable("unhandled enumerator"); } bool CommentInfo::operator==(const CommentInfo &Other) const { diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 3cda38115ff7f..820e8bfd8e644 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -388,9 +388,11 @@ 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_typedef: + case InfoType::IT_default: return ""; } + llvm_unreachable("unhandled enumerator"); } static void parseFullComment(const FullComment *C, CommentInfo &CI) { @@ -525,9 +527,13 @@ 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: + break; } + llvm_unreachable("Invalid reference type for parent namespace"); } // There are two uses for this function. diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp index ea0207619fb2b..3b1cd18d80346 100644 --- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -86,6 +86,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()); diff --git a/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp index bedecb60569e8..203170d55f694 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/hicpp/ExceptionBaseclassCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp index 2b2acfdf5b08e..ed39568ea554a 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 faff1c17fc61e..37fbd8c0d725f 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 c8e6bf47bb82f..339462093a6d6 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 c02c5dfa8756d..eeba5cce80da5 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)))); - - // Match function calls or variable references not directly wrapped by an - // implicit cast - const auto CallIntExpr = CastBindName.empty() - ? callExpr(HasIntegerType) - : callExpr(HasIntegerType).bind(CastBindName); + const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr)); + const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr)); + const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr)); - 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 a877f9a7ee912..d89c3a69fc841 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 8bfd814d16357..b52043416e769 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h @@ -46,6 +46,7 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck { 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/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index f9fd1d903e231..20c73299915a9 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 29321f7cd3fa2..a703009e2b467 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 c9e8a175b5d76..2c858e28fa243 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 8a7809d6677ee..3a6bf155ee153 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 d9b73b83e902a..c56375b1a98d3 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 0000000000000..eea7a1a596e9a --- /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 69f6df46c87ce..775278ccf694b 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 1892f87c8e82a..b04d6431f89f9 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 882ee0015df17..3c1ca2f929044 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -237,10 +237,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,6 +265,8 @@ 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 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 f72b8c7eabc22..b7631139a0133 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 dc86530b95f13..cd25d7d94d99b 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/modularize/CoverageChecker.cpp b/clang-tools-extra/modularize/CoverageChecker.cpp index fe6711398ab7d..1345a6ef8f489 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 7f8a19280b111..2a90c5e3f6782 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 9ad1731915a8b..8a24f21d658df 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-reorder-fields/MacroExpansionField.cpp b/clang-tools-extra/test/clang-reorder-fields/MacroExpansionField.cpp new file mode 100644 index 0000000000000..a4c3cbc1e12f4 --- /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-tidy/checkers/modernize/use-integer-sign-comparison.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp index d93a05ac38050..e0a84ef5aed26 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 0000000000000..0a84dc4676470 --- /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/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp index bbe158ed50e28..659870d2a5c0d 100644 --- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp @@ -37,7 +37,7 @@ static std::string writeInfo(Info *I) { return writeInfo(*static_cast(I)); case InfoType::IT_typedef: return writeInfo(*static_cast(I)); - default: + case InfoType::IT_default: return ""; } } diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index ab2ac9bc6b9ad..94607a8e8473c 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/HIPSupport.rst b/clang/docs/HIPSupport.rst index 051a253969943..406e1c8e5a2fe 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/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index d6507071d4693..986aaabe1eed4 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -406,7 +406,8 @@ implementation. +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | Extensions to atomic construct | :none:`unclaimed` | :none:`unclaimed` | | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ -| Private reductions | :part:`partial` | :none:`unclaimed` | Parse/Sema:https://github.com/llvm/llvm-project/pull/129938 | +| Private reductions | :good:`mostly` | :none:`unclaimed` | Parse/Sema:https://github.com/llvm/llvm-project/pull/129938 | +| | | | Codegen: https://github.com/llvm/llvm-project/pull/134709 | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | Self maps | :part:`partial` | :none:`unclaimed` | parsing/sema done: https://github.com/llvm/llvm-project/pull/129888 | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f36c82bff2ef8..12816eed2e8b5 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 --------------------------- @@ -339,6 +341,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 +361,8 @@ 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). + Removed Compiler Flags ------------------------- @@ -622,6 +628,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 +694,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 @@ -693,6 +709,10 @@ Bug Fixes in This Version - Fixed type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed. (#GH141397) - 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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1100,6 +1120,10 @@ OpenMP Support open parenthesis. (#GH139665) - 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 61b6c55d8e6e4..2c50778d0f491 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 62844f7e6a2fa..284a404026dfe 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 8d24d393eab09..e01361e2466b5 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -488,8 +488,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; @@ -629,10 +629,48 @@ class ASTContext : public RefCountedBase { 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; @@ -1151,7 +1189,7 @@ class ASTContext : public RefCountedBase { /// /// 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(); @@ -3668,6 +3706,7 @@ OPT_LIST(V) /// 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/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 375e9e2592502..dd67ebc9873ff 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -646,6 +646,10 @@ class alignas(8) Decl { 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/Expr.h b/clang/include/clang/AST/Expr.h index 43c28c8bf649f..9fc23d30b733f 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -240,8 +240,7 @@ class Expr : public ValueStmt { 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); } @@ -6965,36 +6964,6 @@ class AtomicExpr : public Expr { } }; -/// 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]. diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index b0f8ae621cf6d..5cb2f57edffe4 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2956,7 +2956,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/Basic/AArch64ACLETypes.def b/clang/include/clang/Basic/AArch64ACLETypes.def index 9acfd693288cf..bbe0c85f9ffbe 100644 --- a/clang/include/clang/Basic/AArch64ACLETypes.def +++ b/clang/include/clang/Basic/AArch64ACLETypes.def @@ -123,31 +123,31 @@ //===- Neon Vector point types --------------------------------------------===// -NEON_VECTOR_TYPE(__Int8x8_t, CharTy, 8, 8, VectorKind::Neon) +NEON_VECTOR_TYPE(__Int8x8_t, SignedCharTy, 8, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Int16x4_t, ShortTy, 16, 4, VectorKind::Neon) NEON_VECTOR_TYPE(__Int32x2_t, IntTy, 32, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Uint8x8_t, CharTy, 8, 8, VectorKind::Neon) +NEON_VECTOR_TYPE(__Uint8x8_t, UnsignedCharTy, 8, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Uint16x4_t, UnsignedShortTy, 16, 4, VectorKind::Neon) NEON_VECTOR_TYPE(__Uint32x2_t, UnsignedIntTy, 32, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Float16x4_t, Float16Ty, 16, 4, VectorKind::Neon) +NEON_VECTOR_TYPE(__Float16x4_t, HalfTy, 16, 4, VectorKind::Neon) NEON_VECTOR_TYPE(__Float32x2_t, FloatTy, 32, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Poly8x8_t, CharTy, 8, 8, VectorKind::NeonPoly) +NEON_VECTOR_TYPE(__Poly8x8_t, UnsignedCharTy, 8, 8, VectorKind::NeonPoly) NEON_VECTOR_TYPE(__Poly16x4_t, UnsignedShortTy, 16, 4, VectorKind::NeonPoly) NEON_VECTOR_TYPE(__Bfloat16x4_t, BFloat16Ty, 16, 4, VectorKind::Neon) -NEON_VECTOR_TYPE(__Int8x16_t, CharTy, 8, 16, VectorKind::Neon) +NEON_VECTOR_TYPE(__Int8x16_t, SignedCharTy, 8, 16, VectorKind::Neon) NEON_VECTOR_TYPE(__Int16x8_t, ShortTy, 16, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Int32x4_t, IntTy, 32, 4, VectorKind::Neon) -NEON_VECTOR_TYPE(__Int64x2_t, LongLongTy, 64, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Uint8x16_t, CharTy, 8, 16, VectorKind::Neon) +NEON_VECTOR_TYPE(__Int64x2_t, LongTy, 64, 2, VectorKind::Neon) +NEON_VECTOR_TYPE(__Uint8x16_t, UnsignedCharTy, 8, 16, VectorKind::Neon) NEON_VECTOR_TYPE(__Uint16x8_t, UnsignedShortTy, 16, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Uint32x4_t, UnsignedIntTy, 32, 4, VectorKind::Neon) -NEON_VECTOR_TYPE(__Uint64x2_t, UnsignedLongLongTy, 64, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Float16x8_t, Float16Ty, 16, 8, VectorKind::Neon) +NEON_VECTOR_TYPE(__Uint64x2_t, UnsignedLongTy, 64, 2, VectorKind::Neon) +NEON_VECTOR_TYPE(__Float16x8_t, HalfTy, 16, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Float32x4_t, FloatTy, 32, 4, VectorKind::Neon) NEON_VECTOR_TYPE(__Float64x2_t, DoubleTy, 64, 2, VectorKind::Neon) -NEON_VECTOR_TYPE(__Poly8x16_t, CharTy, 8, 16, VectorKind::NeonPoly) +NEON_VECTOR_TYPE(__Poly8x16_t, UnsignedCharTy, 8, 16, VectorKind::NeonPoly) NEON_VECTOR_TYPE(__Poly16x8_t, UnsignedShortTy, 16, 8, VectorKind::NeonPoly) -NEON_VECTOR_TYPE(__Poly64x2_t, UnsignedLongLongTy, 64, 2, VectorKind::NeonPoly) +NEON_VECTOR_TYPE(__Poly64x2_t, UnsignedLongTy, 64, 2, VectorKind::NeonPoly) NEON_VECTOR_TYPE(__Bfloat16x8_t, BFloat16Ty, 16, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Mfloat8x8_t, MFloat8Ty, 8, 8, VectorKind::Neon) NEON_VECTOR_TYPE(__Mfloat8x16_t, MFloat8Ty, 8, 16, VectorKind::Neon) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b8e5806d3c5e9..f113cd2ba2fbf 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4630,6 +4630,7 @@ def OMPDeclareVariant : InheritableAttr { OMPTraitInfoArgument<"TraitInfos">, VariadicExprArgument<"AdjustArgsNothing">, VariadicExprArgument<"AdjustArgsNeedDevicePtr">, + VariadicExprArgument<"AdjustArgsNeedDeviceAddr">, VariadicOMPInteropInfoArgument<"AppendArgs">, ]; let AdditionalMembers = [{ @@ -4901,6 +4902,13 @@ def HLSLResourceBinding: InheritableAttr { }]; } +def HLSLSV_Position : HLSLAnnotationAttr { + let Spellings = [HLSLAnnotation<"sv_position">]; + let Subjects = SubjectList<[ParmVar, Field]>; + let LangOpts = [HLSL]; + let Documentation = [HLSLSV_PositionDocs]; +} + def HLSLPackOffset: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"packoffset">]; let LangOpts = [HLSL]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index ea3c43f38d9fe..6051e1fc45111 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 }]; } @@ -8529,6 +8529,20 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo }]; } +def HLSLSV_PositionDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``SV_Position`` semantic, when applied to an input parameter in a pixel +shader, contains the location of the pixel center (x, y) in screen space. +This semantic can be applied to the parameter, or a field in a struct used +as an input parameter. +This attribute is supported as an input in pixel, hull, domain and mesh shaders. +This attribute is supported as an output in vertex, geometry and domain shaders. + +The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics + }]; +} + def HLSLGroupSharedAddressSpaceDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index 34fc774362557..21a7a88a3fb98 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" @@ -61,6 +62,7 @@ class AttributeCommonInfo { /// implicitly. AS_Implicit }; + enum Kind { #define PARSED_ATTR(NAME) AT_##NAME, #include "clang/Basic/AttrParsedAttrList.inc" @@ -78,9 +80,9 @@ class AttributeCommonInfo { 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; @@ -146,11 +148,10 @@ class AttributeCommonInfo { }; 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()) { @@ -158,21 +159,20 @@ class AttributeCommonInfo { "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; @@ -190,17 +190,27 @@ class AttributeCommonInfo { 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 0000000000000..cca4df7c11b02 --- /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/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index fa9474d63ae42..e5566a540dc65 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 a77232c281f7f..7ba21fca6dd6b 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -80,16 +80,6 @@ class CodeGenOptions : public CodeGenOptionsBase { 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 @@ class CodeGenOptions : public CodeGenOptionsBase { /// 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 e9c54c3c487c9..7ae4ef7df138c 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 @@ class DiagStorageAllocator { 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 @@ class DiagnosticsEngine : public RefCountedBase { 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 @@ class DiagnosticsEngine : public RefCountedBase { /// /// 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 @@ class DiagnosticsEngine : public RefCountedBase { /// 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 @@ class DiagnosticsEngine : public RefCountedBase { /// 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 @@ class DiagnosticsEngine : public RefCountedBase { /// 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 20fb47237c56f..29f6480ba935c 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 beda73e675fc6..36fa3227fd6a6 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 80d52a0d01112..2b095f0fd6741 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -483,18 +483,6 @@ class DiagnosticIDs : public RefCountedBase { 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 3aa36ad59d0b9..6c30da376dafb 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 0f77083dac9df..979ff60b73b75 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1779,7 +1779,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}|" @@ -6263,14 +6263,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">, diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index b0de65df7e397..2b1dc1e0121b2 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/ProfileList.h b/clang/include/clang/Basic/ProfileList.h index b4217e49c18a3..5338ef3992ade 100644 --- a/clang/include/clang/Basic/ProfileList.h +++ b/clang/include/clang/Basic/ProfileList.h @@ -49,17 +49,16 @@ class ProfileList { ~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 9526fa5808aa5..c9c173f5c7469 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -202,7 +202,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 3e22bfb330af6..c6fd8a1a45fd1 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 c6753978274a0..e3d589699645b 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) { diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index d22d265e82425..b48f4ed461ccb 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -307,9 +307,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 565c0676773e6..8dd1f0ce361d7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2059,6 +2059,7 @@ def VecCreateOp : CIR_Op<"vec.create", [Pure]> { }]; let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -2154,6 +2155,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 +2280,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 +2355,36 @@ 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; +} + #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 fb96976075130..41d7d725a09e0 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/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 72d882beb2244..3dc28e6f2e5bf 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; } @@ -172,6 +172,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; } @@ -222,6 +227,16 @@ struct MissingFeatures { static bool instrumentation() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cxxRecordStaticMembers() { return false; } + 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; } // Missing types static bool dataMemberType() { return false; } @@ -237,7 +252,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/Driver/Options.td b/clang/include/clang/Driver/Options.td index 3582efd7721b0..0ffd8c40da7da 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1772,7 +1772,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]>, @@ -1789,7 +1789,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">, @@ -2167,11 +2167,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 " @@ -3348,6 +3351,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]>, @@ -3473,8 +3479,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", @@ -4927,8 +4934,10 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">, HelpText<"Set Fuchsia API level">, MarshallingInfoInt>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, + Visibility<[ClangOption, CC1Option, FlangOption]>, Group, HelpText<"Set macOS deployment target">; def : Joined<["-"], "mmacosx-version-min=">, + Visibility<[ClangOption, CC1Option, FC1Option, FlangOption]>, Group, Alias; def mms_bitfields : Flag<["-"], "mms-bitfields">, Group, Visibility<[ClangOption, CC1Option]>, @@ -5054,9 +5063,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)">; @@ -7759,7 +7775,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=">, @@ -8969,7 +8985,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/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0b2fab4a45c96..a47e23ffbd357 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -290,9 +290,7 @@ class Parser : public CodeCompletionHandler { 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) @@ -3600,7 +3598,7 @@ class Parser : public CodeCompletionHandler { /// keyword. bool isClassCompatibleKeyword(Token Tok) const; - void ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs); + void ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs); ///@} @@ -4171,8 +4169,7 @@ class Parser : public CodeCompletionHandler { 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/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 9e050ab9a620e..6b3c5a173417a 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -204,10 +204,9 @@ class ParsedAttr final /// 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 @@ class ParsedAttr final /// 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 @@ class ParsedAttr final /// 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 @@ class ParsedAttr final /// 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 @@ class ParsedAttr final /// 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 @@ class ParsedAttr final /// 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 @@ class AttributePool { 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 @@ class AttributePool { 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 @@ class ParsedAttributes : public ParsedAttributesView { /// 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 @@ class ParsedAttributes : public ParsedAttributesView { 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 @@ class ParsedAttributes : public ParsedAttributesView { /// 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 @@ class ParsedAttributes : public ParsedAttributesView { /// 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 ad12a3d73413b..07b9e1bc10f5a 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -427,6 +427,17 @@ class Scope { 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 0dad07e55a820..29452bb37260d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6713,10 +6713,6 @@ class Sema final : public SemaBase { /// 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 @@ -6813,7 +6809,7 @@ class Sema final : public SemaBase { Decl *ManglingContextDecl, ExpressionKind ExprContext) : Context(Context), ParentCleanup(ParentCleanup), - NumCleanupObjects(NumCleanupObjects), NumTypos(0), + NumCleanupObjects(NumCleanupObjects), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), InDiscardedStatement(false), InImmediateFunctionContext(false), InImmediateEscalatingFunctionContext(false) {} @@ -7146,8 +7142,7 @@ class Sema final : public SemaBase { 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. @@ -8748,40 +8743,6 @@ class Sema final : public SemaBase { 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); @@ -9283,12 +9244,6 @@ class Sema final : public SemaBase { /// 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*. @@ -9376,10 +9331,6 @@ class Sema final : public SemaBase { 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 @@ -9733,51 +9684,6 @@ class Sema final : public SemaBase { 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 { @@ -9796,20 +9702,6 @@ class Sema final : public SemaBase { 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); @@ -9832,23 +9724,15 @@ class Sema final : public SemaBase { /// 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; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 66d09f49680be..33c4b8d1568bf 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,12 +119,26 @@ class SemaHLSL : public SemaBase { 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); + void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); + void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL); void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); void handleShaderAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); @@ -146,6 +160,7 @@ class SemaHLSL : public SemaBase { // Diagnose whether the input ID is uint/unit2/uint3 type. bool diagnoseInputIDType(QualType T, const ParsedAttr &AL); + bool diagnosePositionType(QualType T, const ParsedAttr &AL); bool CanPerformScalarCast(QualType SrcTy, QualType DestTy); bool ContainsBitField(QualType BaseTy); diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 95874077050a9..4d0da1102bb59 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -314,20 +314,6 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { 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/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 6498390fe96f7..7b169f56b6807 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -283,7 +283,7 @@ class SemaOpenMP : public SemaBase { /// 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 @@ class SemaOpenMP : public SemaBase { 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/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index cf4ae610ea51f..0f49646f3f022 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -899,6 +899,10 @@ class ASTWriter : public ASTDeserializationListener, 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 2a96df80d1001..211ce585fbac8 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -326,39 +326,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.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullPassedToNonnullChecker + : Checker<"NullPassedToNonnull">, + HelpText<"Warns when a null pointer is passed to a pointer which has a " + "_Nonnull 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 NullReturnedFromNonnullChecker + : Checker<"NullReturnedFromNonnull">, + HelpText<"Warns when a null pointer is returned from a function that " + "has _Nonnull return type.">, + Documentation; -def NullableDereferencedChecker : Checker<"NullableDereferenced">, - HelpText<"Warns when a nullable pointer is dereferenced.">, - Dependencies<[NullabilityBase]>, - Documentation; + def NullableDereferencedChecker + : Checker<"NullableDereferenced">, + HelpText<"Warns when a nullable pointer is dereferenced.">, + 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 NullablePassedToNonnullChecker + : Checker<"NullablePassedToNonnull">, + HelpText<"Warns when a nullable pointer is passed to a pointer which " + "has a _Nonnull type.">, + 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 580b49a38dc72..70a7953918ace 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 @@ class SMTConv { // 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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b51f7622288df..189e67e4eed0d 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1175,7 +1175,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; @@ -1705,6 +1705,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"); @@ -7429,6 +7496,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)) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 003bad225e30c..5c44353d8b987 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9333,8 +9333,9 @@ class AttrImporter { 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 fefb8f55a9ee2..5875a925d3fb0 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/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index bf38b2e5d537d..9fe4803ce98ec 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6591,10 +6591,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(); diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index 9ef44cd29ff87..f60307870ffcc 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 b678f229d50bb..d01e3d042a8bf 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1321,7 +1321,7 @@ static bool interp__builtin_ia32_pdep(InterpState &S, CodePtr OpPC, if (Mask[I]) Result.setBitVal(I, Val[P++]); } - pushInteger(S, Result, Call->getType()); + pushInteger(S, std::move(Result), Call->getType()); return true; } @@ -1344,7 +1344,7 @@ static bool interp__builtin_ia32_pext(InterpState &S, CodePtr OpPC, if (Mask[I]) Result.setBitVal(P++, Val[I]); } - pushInteger(S, Result, Call->getType()); + pushInteger(S, std::move(Result), Call->getType()); return true; } @@ -1423,7 +1423,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 +1438,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/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index b183335dd5884..6b748d62b83bd 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/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index a1bb62bcb68fa..48c60aa4e449a 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1132,6 +1132,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/Expr.cpp b/clang/lib/AST/Expr.cpp index 17d2cb4a30f30..c3722c65abf6e 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3611,7 +3611,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. diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 3f37d06cc8f3a..ad66335138a42 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -129,7 +129,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/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fa4e10e84de05..f1580255a462a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6844,7 +6844,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // FIXME: In this case, the values of the other subobjects are // specified, since zero-initialization sets all padding bits to zero. if (!Value->hasValue() || - (Value->isUnion() && Value->getUnionField() != FD)) { + (Value->isUnion() && + !declaresSameEntity(Value->getUnionField(), FD))) { if (CD->isUnion()) *Value = APValue(FD); else @@ -17326,7 +17327,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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index ecf5be220439b..487933a748ab8 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4994,7 +4994,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, 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/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 13c3bc0387890..28317911d825b 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2914,11 +2914,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 f7d1655f67ed1..c666d966a6e58 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2361,10 +2361,6 @@ void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { VisitExpr(E); } -void StmtProfiler::VisitTypoExpr(const TypoExpr *E) { - VisitExpr(E); -} - void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { VisitExpr(E); } diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 8b1ca6b80971f..631a546b45ff4 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 905046685934b..004e5209a44a7 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 694224071347a..a30bfa28eca71 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 3e90b2d804773..dcf0c6cb54282 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -823,103 +823,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 7e696620993f9..912b890569cf5 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/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp index aaea5a00ab6ae..8481deffe2a7b 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 09e5c6547fb51..053e82683a4a6 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 7b577632fdf55..9429a316a9196 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -555,8 +555,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/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index e8abdf9aafd82..124b340b62d9f 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 a4c65361105e4..1951e0679d2ec 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 85ca4bc30c461..bbe7b01ca036d 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/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 0eaf82eee756b..b416a01f0f374 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -46,7 +46,7 @@ static const unsigned SPIRDefIsPrivMap[] = { 0, // ptr32_sptr 0, // ptr32_uptr 0, // ptr64 - 0, // hlsl_groupshared + 3, // hlsl_groupshared 12, // hlsl_constant 10, // hlsl_private 11, // hlsl_device @@ -82,7 +82,7 @@ static const unsigned SPIRDefIsGenMap[] = { 0, // ptr32_sptr 0, // ptr32_uptr 0, // ptr64 - 0, // hlsl_groupshared + 3, // hlsl_groupshared 0, // hlsl_constant 10, // hlsl_private 11, // hlsl_device diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 6f8a2365be256..ecb31ffa4750f 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -997,6 +997,10 @@ class LLVM_LIBRARY_VISIBILITY CygwinX86_64TargetInfo : public X86_64TargetInfo { if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } }; class LLVM_LIBRARY_VISIBILITY DarwinX86_64TargetInfo diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index 4c8c6ed289c3b..9cec17bcb2fd0 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 03077ee062a65..e38faba83b80c 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 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { } 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 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { 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 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { 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 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { 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 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { /// 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 0000000000000..19fac00ab8736 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// 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 "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)); + + 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); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp new file mode 100644 index 0000000000000..51751483d34e9 --- /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 107535ebc7275..2d967fd307e01 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -37,6 +37,10 @@ class CIRGenCXXABI { 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 @@ class CIRGenCXXABI { 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 b194a8670bfb9..af0e6ca822b8f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,30 @@ 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); +} + +/// Returns the canonical formal type of the given C++ method. +static CanQual getFormalType(const CXXMethodDecl *md) { + return md->getType() + ->getCanonicalTypeUnqualified() + .getAs(); +} + /// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size_attrs, then we'll add parameters for those, too. /// TODO(cir): this should be shared with LLVM codegen @@ -76,6 +100,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; + + if (auto *cd = dyn_cast(md)) { + // A base class inheriting constructor doesn't get forwarded arguments + // needed to construct a virtual base (or base class thereof) + if (cd->getInheritedConstructor()) + cgm.errorNYI(cd->getSourceRange(), + "arrangeCXXStructorDeclaration: inheriting constructor"); + } + + CanQual fpt = getFormalType(md); + + if (passParams) + appendParameterTypes(*this, argTypes, fpt); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + RequiredArgs required = + (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) + : RequiredArgs::All); + + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(gd) + ? astContext.VoidPtrTy + : astContext.VoidTy; + + assert(!theCXXABI.hasThisReturn(gd) && + "Please send PR with a test and remove this"); + + assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); + assert(!cir::MissingFeatures::opCallFnInfoOpts()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR /// qualification. Either or both of `rd` and `md` may be null. A null `rd` /// indicates that there is no meaningful 'this' type, and a null `md` can occur @@ -103,16 +169,56 @@ CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd, /// top of any implicit parameters already stored. static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, - CanQual ftp) { + CanQual fpt) { assert(!cir::MissingFeatures::opCallFnInfoOpts()); RequiredArgs required = - RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size()); + RequiredArgs::getFromProtoWithExtraSlots(fpt, prefix.size()); assert(!cir::MissingFeatures::opCallExtParameterInfo()); - appendParameterTypes(cgt, prefix, ftp); - CanQualType resultType = ftp->getReturnType().getUnqualifiedType(); + appendParameterTypes(cgt, prefix, fpt); + CanQualType resultType = fpt->getReturnType().getUnqualifiedType(); 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, @@ -141,6 +247,44 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, return cgt.arrangeCIRFunctionInfo(retType, argTypes, required); } +/// Arrange a call to a C++ method, passing the given arguments. +/// +/// passProtoArgs indicates whether `args` has args for the parameters in the +/// given CXXConstructorDecl. +const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( + const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind, + bool passProtoArgs) { + + // FIXME: Kill copy. + llvm::SmallVector argTypes; + for (const auto &arg : args) + argTypes.push_back(astContext.getCanonicalParamType(arg.ty)); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + // +1 for implicit this, which should always be args[0] + unsigned totalPrefixArgs = 1; + + CanQual fpt = getFormalType(d); + RequiredArgs required = + passProtoArgs + ? RequiredArgs::getFromProtoWithExtraSlots(fpt, totalPrefixArgs) + : RequiredArgs::All; + + GlobalDecl gd(d, ctorKind); + if (theCXXABI.hasThisReturn(gd)) + cgm.errorNYI(d->getSourceRange(), + "arrangeCXXConstructorCall: hasThisReturn"); + if (theCXXABI.hasMostDerivedReturn(gd)) + cgm.errorNYI(d->getSourceRange(), + "arrangeCXXConstructorCall: hasMostDerivedReturn"); + CanQualType resultType = astContext.VoidTy; + + assert(!cir::MissingFeatures::opCallFnInfoOpts()); + assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Arrange a call to a C++ method, passing the given arguments. /// /// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It @@ -198,7 +342,7 @@ CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) { /// constructor or destructor. const CIRGenFunctionInfo & CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd, - const FunctionProtoType *ftp, + const FunctionProtoType *fpt, const CXXMethodDecl *md) { llvm::SmallVector argTypes; @@ -208,7 +352,7 @@ CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd, assert(!cir::MissingFeatures::opCallFnInfoOpts()); return ::arrangeCIRFunctionInfo( *this, argTypes, - ftp->getCanonicalTypeUnqualified().getAs()); + fpt->getCanonicalTypeUnqualified().getAs()); } /// Arrange the argument and result information for the declaration or @@ -299,7 +443,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())) @@ -312,8 +456,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); } } @@ -352,6 +537,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, assert(!cir::MissingFeatures::opCallAttrs()); + mlir::Location callLoc = loc; cir::CIRCallOpInterface theCall = emitCallLikeOp( *this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs); @@ -365,6 +551,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"); @@ -381,7 +580,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); } @@ -400,10 +598,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); @@ -424,12 +633,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 605625705a75c..0353848f3ec0d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -44,16 +44,25 @@ class CIRGenCalleeInfo { 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 @@ class CIRGenCallee { 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); } @@ -105,8 +133,16 @@ struct CallArg { 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 +155,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 +174,15 @@ class CallArgList : public llvm::SmallVector { /// 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 4cdaa480121dd..e59a1fdb837cb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -10,14 +10,136 @@ // //===----------------------------------------------------------------------===// +#include "CIRGenCXXABI.h" #include "CIRGenFunction.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" #include "clang/CIR/MissingFeatures.h" 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, @@ -63,3 +185,74 @@ Address CIRGenFunction::getAddressOfBaseClass( return value; } + +void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, + clang::CXXCtorType type, + bool forVirtualBase, + bool delegating, + AggValueSlot thisAVS, + const clang::CXXConstructExpr *e) { + CallArgList args; + Address thisAddr = thisAVS.getAddress(); + QualType thisType = d->getThisType(); + mlir::Value thisPtr = thisAddr.getPointer(); + + assert(!cir::MissingFeatures::addressSpace()); + + args.add(RValue::get(thisPtr), thisType); + + // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. + // If this is a union copy constructor, we must emit a memcpy, because the AST + // does not model that copy. + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + const FunctionProtoType *fpt = d->getType()->castAs(); + + assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); + + emitCallArgs(args, fpt, e->arguments(), e->getConstructor(), + /*ParamsToSkip=*/0); + + assert(!cir::MissingFeatures::sanitizers()); + emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, + e->getExprLoc()); +} + +void CIRGenFunction::emitCXXConstructorCall( + const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, + bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { + + const CXXRecordDecl *crd = d->getParent(); + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + assert(!cir::MissingFeatures::isTrivialCtorOrDtor()); + + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + bool passPrototypeArgs = true; + + // Check whether we can actually emit the constructor before trying to do so. + if (d->getInheritedConstructor()) { + cgm.errorNYI(d->getSourceRange(), + "emitCXXConstructorCall: inherited constructor"); + return; + } + + // Insert any ABI-specific implicit constructor arguments. + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + // Emit the call. + auto calleePtr = cgm.getAddrOfCXXStructor(GlobalDecl(d, type)); + const CIRGenFunctionInfo &info = cgm.getTypes().arrangeCXXConstructorCall( + args, d, type, passPrototypeArgs); + CIRGenCallee callee = CIRGenCallee::forDirect(calleePtr, GlobalDecl(d, type)); + cir::CIRCallOpInterface c; + emitCall(info, callee, ReturnValueSlot(), args, &c, getLoc(loc)); + + if (cgm.getCodeGenOpts().OptimizationLevel != 0 && !crd->isDynamicClass() && + type != Ctor_Base && cgm.getCodeGenOpts().StrictVTablePointers) + cgm.errorNYI(d->getSourceRange(), "vtable assumption loads"); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 80b0172090aa3..afbe92aded804 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 8129fe0ad7db7..4f2046ad26d72 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) { @@ -1010,16 +1010,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 +1033,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 +1151,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 +1207,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 +1266,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, @@ -1393,6 +1454,61 @@ RValue CIRGenFunction::emitCXXMemberCallExpr(const CXXMemberCallExpr *ce, ce, md, returnValue, hasQualifier, qualifier, isArrow, base); } +void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, + AggValueSlot dest) { + assert(!dest.isIgnored() && "Must have a destination!"); + const CXXConstructorDecl *cd = e->getConstructor(); + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now, unless destination is + // already zeroed. + if (e->requiresZeroInitialization() && !dest.isZeroed()) { + cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: requires initialization"); + return; + } + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + + // Elide the constructor if we're constructing from a temporary + if (getLangOpts().ElideConstructors && e->isElidable()) { + cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: elidable constructor"); + return; + } + + if (getContext().getAsArrayType(e->getType())) { + cgm.errorNYI(e->getSourceRange(), "emitCXXConstructExpr: array type"); + return; + } + + clang::CXXCtorType type = Ctor_Complete; + bool forVirtualBase = false; + bool delegating = false; + + switch (e->getConstructionKind()) { + case CXXConstructionKind::Complete: + 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(), + "emitCXXConstructExpr: other construction kind"); + return; + } + + emitCXXConstructorCall(cd, type, forVirtualBase, delegating, dest, e); +} + RValue CIRGenFunction::emitReferenceBindingToExpr(const Expr *e) { // Emit the expression as an lvalue. LValue lv = emitLValue(e); @@ -1574,3 +1690,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 56d7ea3884ba7..ffe1b701b244e 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,17 +49,30 @@ class AggExprEmitter : public StmtVisitor { 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); void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef args, FieldDecl *initializedFieldInUnion, @@ -79,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) { @@ -181,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(); @@ -202,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()) @@ -213,6 +262,11 @@ void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) { } } +void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) { + AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType()); + cgf.emitCXXConstructExpr(e, slot); +} + void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc, LValue lv) { const QualType type = lv.getType(); @@ -240,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"); @@ -278,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 0000000000000..26070a6ca307a --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -0,0 +1,109 @@ +#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()) {} + + /// 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 VisitInitListExpr(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()); +} + +void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, + LValue lv, bool isInit) { + if (lv.getType()->isAtomicType() || + (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) { + cgf.cgm.errorNYI("StoreOfComplex with Atomic LV"); + return; + } + + const Address destAddr = lv.getAddress(); + builder.createStore(loc, val, destAddr); +} + +mlir::Value ComplexExprEmitter::VisitInitListExpr(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); +} + +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 c41ab54be09ca..8b817f3f3d8d2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -254,8 +254,8 @@ class ConstExprEmitter } 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 481eb492d1875..8d0db5cd0a1e5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -131,11 +131,11 @@ class ScalarExprEmitter : public StmtVisitor { 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 @@ class ScalarExprEmitter : public StmtVisitor { 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 @@ class ScalarExprEmitter : public StmtVisitor { 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 @@ class ScalarExprEmitter : public StmtVisitor { 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 e32a5c836be02..fd413fe86383a 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 d6002c3e4d4d9..de6ef2a69faf1 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { ~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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { /// 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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 @@ class CIRGenFunction : public CIRGenTypeCache { /// 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 @@ class CIRGenFunction : public CIRGenTypeCache { 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, @@ -742,8 +774,23 @@ class CIRGenFunction : public CIRGenTypeCache { LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e); + void emitConstructorBody(FunctionArgList &args); + mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s); + void emitCXXConstructExpr(const clang::CXXConstructExpr *e, + AggValueSlot dest); + + void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, + clang::CXXCtorType type, bool forVirtualBase, + bool delegating, AggValueSlot thisAVS, + const clang::CXXConstructExpr *e); + + void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, + clang::CXXCtorType type, bool forVirtualBase, + bool delegating, Address thisAddr, + CallArgList &args, clang::SourceLocation loc); + mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s, llvm::ArrayRef attrs); @@ -766,6 +813,16 @@ class CIRGenFunction : public CIRGenTypeCache { 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.) @@ -805,6 +862,10 @@ class CIRGenFunction : public CIRGenTypeCache { 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); + void emitCompoundStmt(const clang::CompoundStmt &s); void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); @@ -817,6 +878,17 @@ class CIRGenFunction : public CIRGenTypeCache { 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. @@ -893,6 +965,11 @@ class CIRGenFunction : public CIRGenTypeCache { 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); @@ -1064,6 +1141,12 @@ class CIRGenFunction : public CIRGenTypeCache { 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); @@ -1091,6 +1174,17 @@ class CIRGenFunction : public CIRGenTypeCache { 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 fdd8b63fb6da0..cd9096a0188a7 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 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { 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 3d46c44b4f1ec..434dd376208e1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -103,6 +103,25 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, CIRGenModule::~CIRGenModule() = default; +/// FIXME: this could likely be a common helper and not necessarily related +/// with codegen. +/// Return the best known alignment for an unknown pointer to a +/// particular class. +CharUnits CIRGenModule::getClassPointerAlignment(const CXXRecordDecl *rd) { + if (!rd->hasDefinition()) + return CharUnits::One(); // Hopefully won't be used anywhere. + + auto &layout = astContext.getASTRecordLayout(rd); + + // If the class is final, then we know that the pointer points to an + // object of that type and can use the full alignment. + if (rd->isEffectivelyFinal()) + return layout.getAlignment(); + + // Otherwise, we have to assume it could be a subclass. + return layout.getNonVirtualAlignment(); +} + CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t, LValueBaseInfo *baseInfo) { assert(!cir::MissingFeatures::opTBAA()); @@ -207,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 = @@ -392,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) { @@ -752,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 @@ -1154,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: @@ -1174,6 +1196,34 @@ void CIRGenModule::setInitializer(cir::GlobalOp &op, mlir::Attribute value) { assert(!cir::MissingFeatures::opGlobalVisibility()); } +std::pair CIRGenModule::getAddrAndTypeOfCXXStructor( + GlobalDecl gd, const CIRGenFunctionInfo *fnInfo, cir::FuncType fnType, + bool dontDefer, ForDefinition_t isForDefinition) { + auto *md = cast(gd.getDecl()); + + if (isa(md)) { + // Always alias equivalent complete destructors to base destructors in the + // MS ABI. + if (getTarget().getCXXABI().isMicrosoft() && + gd.getDtorType() == Dtor_Complete && + md->getParent()->getNumVBases() == 0) + errorNYI(md->getSourceRange(), + "getAddrAndTypeOfCXXStructor: MS ABI complete destructor"); + } + + if (!fnType) { + if (!fnInfo) + fnInfo = &getTypes().arrangeCXXStructorDeclaration(gd); + fnType = getTypes().getFunctionType(*fnInfo); + } + + auto fn = getOrCreateCIRFunction(getMangledName(gd), fnType, gd, + /*ForVtable=*/false, dontDefer, + /*IsThunk=*/false, isForDefinition); + + return {fnType, fn}; +} + cir::FuncOp CIRGenModule::getAddrOfFunction(clang::GlobalDecl gd, mlir::Type funcType, bool forVTable, bool dontDefer, @@ -1248,8 +1298,11 @@ StringRef CIRGenModule::getMangledName(GlobalDecl gd) { // Some ABIs don't have constructor variants. Make sure that base and complete // constructors get mangled the same. if (const auto *cd = dyn_cast(canonicalGd.getDecl())) { - errorNYI(cd->getSourceRange(), "getMangledName: C++ constructor"); - return cast(gd.getDecl())->getIdentifier()->getName(); + if (!getTarget().getCXXABI().hasConstructorVariants()) { + errorNYI(cd->getSourceRange(), + "getMangledName: C++ constructor without variants"); + return cast(gd.getDecl())->getIdentifier()->getName(); + } } // Keep the first result in the case of a mangling collision. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 24ec9ca6403bc..0ea2d9f9c8229 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -113,8 +113,21 @@ class CIRGenModule : public CIRGenTypeCache { 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, @@ -166,11 +179,30 @@ class CIRGenModule : public CIRGenTypeCache { mlir::Location getLoc(clang::SourceLocation cLoc); mlir::Location getLoc(clang::SourceRange cRange); + /// Return the best known alignment for an unknown pointer to a + /// particular class. + clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *rd); + /// FIXME: this could likely be a common helper and not necessarily related /// with codegen. clang::CharUnits getNaturalTypeAlignment(clang::QualType t, LValueBaseInfo *baseInfo); + cir::FuncOp + getAddrOfCXXStructor(clang::GlobalDecl gd, + const CIRGenFunctionInfo *fnInfo = nullptr, + cir::FuncType fnType = nullptr, bool dontDefer = false, + ForDefinition_t isForDefinition = NotForDefinition) { + return getAddrAndTypeOfCXXStructor(gd, fnInfo, fnType, dontDefer, + isForDefinition) + .second; + } + + std::pair getAddrAndTypeOfCXXStructor( + clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo = nullptr, + cir::FuncType fnType = nullptr, bool dontDefer = false, + ForDefinition_t isForDefinition = NotForDefinition); + /// This contains all the decls which have definitions but which are deferred /// for emission and therefore should only be output if they are actually /// used. If a decl is in this, then it is known to have not been referenced @@ -248,6 +280,11 @@ class CIRGenModule : public CIRGenTypeCache { // 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); @@ -264,6 +301,10 @@ class CIRGenModule : public CIRGenTypeCache { 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/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 019a44636ce3c..9193f6f1cd996 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 2aab9cecf93d8..1feefa55eb270 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 24cd1d399de65..71f3ccb8e040e 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 eaba3dfd1105e..bab47924dd719 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -419,6 +419,15 @@ mlir::Type CIRGenTypes::convertType(QualType type) { 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 +441,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/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 48d474beeddec..c2813d79bf63b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -19,6 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "clang/Basic/ABI.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "llvm/ADT/SmallPtrSet.h" @@ -165,6 +166,10 @@ class CIRGenTypes { bool isZeroInitializable(clang::QualType ty); bool isZeroInitializable(const RecordDecl *rd); + const CIRGenFunctionInfo &arrangeCXXConstructorCall( + const CallArgList &args, const clang::CXXConstructorDecl *d, + clang::CXXCtorType ctorKind, bool passProtoArgs = true); + const CIRGenFunctionInfo & arrangeCXXMethodCall(const CallArgList &args, const clang::FunctionProtoType *type, @@ -173,6 +178,7 @@ class CIRGenTypes { /// C++ methods have some special rules and also have implicit parameters. const CIRGenFunctionInfo & arrangeCXXMethodDeclaration(const clang::CXXMethodDecl *md); + const CIRGenFunctionInfo &arrangeCXXStructorDeclaration(clang::GlobalDecl gd); const CIRGenFunctionInfo & arrangeCXXMethodType(const clang::CXXRecordDecl *rd, diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 208247e16e531..84972fc7f9118 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 @@ class RValue { 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,22 +74,20 @@ class RValue { 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. @@ -267,23 +256,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 }; + + /// 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); + } - AggValueSlot(Address addr, clang::Qualifiers quals, bool zeroedFlag) - : addr(addr), quals(quals), zeroedFlag(zeroedFlag) {} + 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, isZeroed); + return AggValueSlot(addr, quals, isDestructed, isZeroed, isAliased, + mayOverlap); } - static AggValueSlot forLValue(const LValue &lv) { - return forAddr(lv.getAddress(), lv.getQuals()); + 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 +329,16 @@ class AggValueSlot { 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 8bfcd2773d07a..385bea066c61c 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/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index a6cf0a6b5d75e..3fcb0213b219a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1533,6 +1533,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 +1589,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 +1741,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 +1846,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 29f9942638964..f07e234e5e84c 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/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4fdf8f9ec2695..6a4e4e4a7df3b 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -901,7 +901,36 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( rewriter.eraseOp(op); return mlir::success(); } - } else { + } 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(); } @@ -1803,9 +1832,11 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMVecExtractOpLowering, CIRToLLVMVecInsertOpLowering, CIRToLLVMVecCmpOpLowering, + CIRToLLVMVecSplatOpLowering, CIRToLLVMVecShuffleOpLowering, CIRToLLVMVecShuffleDynamicOpLowering, - CIRToLLVMVecTernaryOpLowering + CIRToLLVMVecTernaryOpLowering, + CIRToLLVMComplexCreateOpLowering // clang-format on >(converter, patterns.getContext()); @@ -1956,6 +1987,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 +2122,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 22d8a1e7c22e0..a809818063547 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -367,6 +367,16 @@ class CIRToLLVMVecCmpOpLowering 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 +408,16 @@ class CIRToLLVMVecTernaryOpLowering 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 88b3a4943e0d8..7e0a3cf5591ce 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/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c0b02a104d95e..1f69274351676 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" diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 38f514304df5e..dd26be74e561b 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/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index abebc201808b0..ccf45c0c6ff1d 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -295,17 +295,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 +313,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: { diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 6d267e6164845..585411bc59e16 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; @@ -237,35 +236,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) { @@ -384,6 +354,30 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { return B.CreateCall(F, {B.getInt32(0)}); } +static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, + unsigned BuiltIn) { + LLVMContext &Ctx = GV->getContext(); + IRBuilder<> B(GV->getContext()); + MDNode *Operands = MDNode::get( + Ctx, + {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)), + ConstantAsMetadata::get(B.getInt32(BuiltIn))}); + MDNode *Decoration = MDNode::get(Ctx, {Operands}); + GV->addMetadata("spirv.Decorations", *Decoration); +} + +static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, + llvm::Type *Ty, const Twine &Name, + unsigned BuiltInID) { + auto *GV = new llvm::GlobalVariable( + M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 7, /* isExternallyInitialized= */ true); + addSPIRVBuiltinDecoration(GV, BuiltInID); + return B.CreateLoad(Ty, GV); +} + llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, const ParmVarDecl &D, llvm::Type *Ty) { @@ -407,6 +401,12 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); return buildVectorInput(B, GroupIDIntrinsic, Ty); } + if (D.hasAttr()) { + if (getArch() == llvm::Triple::spirv) + return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position", + /* BuiltIn::Position */ 0); + llvm_unreachable("SV_Position semantic not implemented for this target."); + } assert(false && "Unhandled parameter attribute"); return nullptr; } @@ -471,14 +471,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 = @@ -595,47 +587,35 @@ 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); } } void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *GV) { - if (auto Attr = VD->getAttr()) { - LLVMContext &Ctx = GV->getContext(); - IRBuilder<> B(GV->getContext()); - MDNode *Operands = MDNode::get( - Ctx, {ConstantAsMetadata::get( - B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)), - ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))}); - MDNode *Decoration = MDNode::get(Ctx, {Operands}); - GV->addMetadata("spirv.Decorations", *Decoration); - } + if (auto Attr = VD->getAttr()) + addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn()); } llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb2b82fa1f5aa..89d2aff85d913 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -118,6 +118,10 @@ class CGHLSLRuntime { 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 @@ class CGHLSLRuntime { // 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/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 09e3ccc380ae3..4173355491fd4 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4907,11 +4907,255 @@ void CGOpenMPRuntime::emitSingleReductionCombiner(CodeGenFunction &CGF, } } +static std::string generateUniqueName(CodeGenModule &CGM, + llvm::StringRef Prefix, const Expr *Ref); + +void CGOpenMPRuntime::emitPrivateReduction( + CodeGenFunction &CGF, SourceLocation Loc, const Expr *Privates, + const Expr *LHSExprs, const Expr *RHSExprs, const Expr *ReductionOps) { + + // Create a shared global variable (__shared_reduction_var) to accumulate the + // final result. + // + // Call __kmpc_barrier to synchronize threads before initialization. + // + // The master thread (thread_id == 0) initializes __shared_reduction_var + // with the identity value or initializer. + // + // Call __kmpc_barrier to synchronize before combining. + // For each i: + // - Thread enters critical section. + // - Reads its private value from LHSExprs[i]. + // - Updates __shared_reduction_var[i] = RedOp_i(__shared_reduction_var[i], + // Privates[i]). + // - Exits critical section. + // + // Call __kmpc_barrier after combining. + // + // Each thread copies __shared_reduction_var[i] back to RHSExprs[i]. + // + // Final __kmpc_barrier to synchronize after broadcasting + QualType PrivateType = Privates->getType(); + llvm::Type *LLVMType = CGF.ConvertTypeForMem(PrivateType); + + const OMPDeclareReductionDecl *UDR = getReductionInit(ReductionOps); + std::string ReductionVarNameStr; + if (const auto *DRE = dyn_cast(Privates->IgnoreParenCasts())) + ReductionVarNameStr = + generateUniqueName(CGM, DRE->getDecl()->getNameAsString(), Privates); + else + ReductionVarNameStr = "unnamed_priv_var"; + + // Create an internal shared variable + std::string SharedName = + CGM.getOpenMPRuntime().getName({"internal_pivate_", ReductionVarNameStr}); + llvm::GlobalVariable *SharedVar = OMPBuilder.getOrCreateInternalVariable( + LLVMType, ".omp.reduction." + SharedName); + + SharedVar->setAlignment( + llvm::MaybeAlign(CGF.getContext().getTypeAlign(PrivateType) / 8)); + + Address SharedResult = + CGF.MakeNaturalAlignRawAddrLValue(SharedVar, PrivateType).getAddress(); + + llvm::Value *ThreadId = getThreadID(CGF, Loc); + llvm::Value *BarrierLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE); + llvm::Value *BarrierArgs[] = {BarrierLoc, ThreadId}; + + llvm::BasicBlock *InitBB = CGF.createBasicBlock("init"); + llvm::BasicBlock *InitEndBB = CGF.createBasicBlock("init.end"); + + llvm::Value *IsWorker = CGF.Builder.CreateICmpEQ( + ThreadId, llvm::ConstantInt::get(ThreadId->getType(), 0)); + CGF.Builder.CreateCondBr(IsWorker, InitBB, InitEndBB); + + CGF.EmitBlock(InitBB); + + auto EmitSharedInit = [&]() { + if (UDR) { // Check if it's a User-Defined Reduction + if (const Expr *UDRInitExpr = UDR->getInitializer()) { + std::pair FnPair = + getUserDefinedReduction(UDR); + llvm::Function *InitializerFn = FnPair.second; + if (InitializerFn) { + if (const auto *CE = + dyn_cast(UDRInitExpr->IgnoreParenImpCasts())) { + const auto *OutDRE = cast( + cast(CE->getArg(0)->IgnoreParenImpCasts()) + ->getSubExpr()); + const VarDecl *OutVD = cast(OutDRE->getDecl()); + + CodeGenFunction::OMPPrivateScope LocalScope(CGF); + LocalScope.addPrivate(OutVD, SharedResult); + + (void)LocalScope.Privatize(); + if (const auto *OVE = dyn_cast( + CE->getCallee()->IgnoreParenImpCasts())) { + CodeGenFunction::OpaqueValueMapping OpaqueMap( + CGF, OVE, RValue::get(InitializerFn)); + CGF.EmitIgnoredExpr(CE); + } else { + CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult, + PrivateType.getQualifiers(), + /*IsInitializer=*/true); + } + } else { + CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult, + PrivateType.getQualifiers(), + /*IsInitializer=*/true); + } + } else { + CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult, + PrivateType.getQualifiers(), + /*IsInitializer=*/true); + } + } else { + // EmitNullInitialization handles default construction for C++ classes + // and zeroing for scalars, which is a reasonable default. + CGF.EmitNullInitialization(SharedResult, PrivateType); + } + return; // UDR initialization handled + } + if (const auto *DRE = dyn_cast(Privates)) { + if (const auto *VD = dyn_cast(DRE->getDecl())) { + if (const Expr *InitExpr = VD->getInit()) { + CGF.EmitAnyExprToMem(InitExpr, SharedResult, + PrivateType.getQualifiers(), true); + return; + } + } + } + CGF.EmitNullInitialization(SharedResult, PrivateType); + }; + EmitSharedInit(); + CGF.Builder.CreateBr(InitEndBB); + CGF.EmitBlock(InitEndBB); + + CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_barrier), + BarrierArgs); + + const Expr *ReductionOp = ReductionOps; + const OMPDeclareReductionDecl *CurrentUDR = getReductionInit(ReductionOp); + LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType); + LValue LHSLV = CGF.EmitLValue(Privates); + + auto EmitCriticalReduction = [&](auto ReductionGen) { + std::string CriticalName = getName({"reduction_critical"}); + emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc); + }; + + if (CurrentUDR) { + // Handle user-defined reduction. + auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) { + Action.Enter(CGF); + std::pair FnPair = + getUserDefinedReduction(CurrentUDR); + if (FnPair.first) { + if (const auto *CE = dyn_cast(ReductionOp)) { + const auto *OutDRE = cast( + cast(CE->getArg(0)->IgnoreParenImpCasts()) + ->getSubExpr()); + const auto *InDRE = cast( + cast(CE->getArg(1)->IgnoreParenImpCasts()) + ->getSubExpr()); + CodeGenFunction::OMPPrivateScope LocalScope(CGF); + LocalScope.addPrivate(cast(OutDRE->getDecl()), + SharedLV.getAddress()); + LocalScope.addPrivate(cast(InDRE->getDecl()), + LHSLV.getAddress()); + (void)LocalScope.Privatize(); + emitReductionCombiner(CGF, ReductionOp); + } + } + }; + EmitCriticalReduction(ReductionGen); + } else { + // Handle built-in reduction operations. +#ifndef NDEBUG + const Expr *ReductionClauseExpr = ReductionOp->IgnoreParenCasts(); + if (const auto *Cleanup = dyn_cast(ReductionClauseExpr)) + ReductionClauseExpr = Cleanup->getSubExpr()->IgnoreParenCasts(); + + const Expr *AssignRHS = nullptr; + if (const auto *BinOp = dyn_cast(ReductionClauseExpr)) { + if (BinOp->getOpcode() == BO_Assign) + AssignRHS = BinOp->getRHS(); + } else if (const auto *OpCall = + dyn_cast(ReductionClauseExpr)) { + if (OpCall->getOperator() == OO_Equal) + AssignRHS = OpCall->getArg(1); + } + + assert(AssignRHS && + "Private Variable Reduction : Invalid ReductionOp expression"); +#endif + + auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) { + Action.Enter(CGF); + const auto *OmpOutDRE = + dyn_cast(LHSExprs->IgnoreParenImpCasts()); + const auto *OmpInDRE = + dyn_cast(RHSExprs->IgnoreParenImpCasts()); + assert( + OmpOutDRE && OmpInDRE && + "Private Variable Reduction : LHSExpr/RHSExpr must be DeclRefExprs"); + const VarDecl *OmpOutVD = cast(OmpOutDRE->getDecl()); + const VarDecl *OmpInVD = cast(OmpInDRE->getDecl()); + CodeGenFunction::OMPPrivateScope LocalScope(CGF); + LocalScope.addPrivate(OmpOutVD, SharedLV.getAddress()); + LocalScope.addPrivate(OmpInVD, LHSLV.getAddress()); + (void)LocalScope.Privatize(); + // Emit the actual reduction operation + CGF.EmitIgnoredExpr(ReductionOp); + }; + EmitCriticalReduction(ReductionGen); + } + + CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_barrier), + BarrierArgs); + + // Broadcast final result + bool IsAggregate = PrivateType->isAggregateType(); + LValue SharedLV1 = CGF.MakeAddrLValue(SharedResult, PrivateType); + llvm::Value *FinalResultVal = nullptr; + Address FinalResultAddr = Address::invalid(); + + if (IsAggregate) + FinalResultAddr = SharedResult; + else + FinalResultVal = CGF.EmitLoadOfScalar(SharedLV1, Loc); + + LValue TargetLHSLV = CGF.EmitLValue(RHSExprs); + if (IsAggregate) { + CGF.EmitAggregateCopy(TargetLHSLV, + CGF.MakeAddrLValue(FinalResultAddr, PrivateType), + PrivateType, AggValueSlot::DoesNotOverlap, false); + } else { + CGF.EmitStoreOfScalar(FinalResultVal, TargetLHSLV); + } + // Final synchronization barrier + CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_barrier), + BarrierArgs); + + // Combiner with original list item + auto OriginalListCombiner = [&](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + emitSingleReductionCombiner(CGF, ReductionOps, Privates, + cast(LHSExprs), + cast(RHSExprs)); + }; + EmitCriticalReduction(OriginalListCombiner); +} + void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, - ArrayRef Privates, - ArrayRef LHSExprs, - ArrayRef RHSExprs, - ArrayRef ReductionOps, + ArrayRef OrgPrivates, + ArrayRef OrgLHSExprs, + ArrayRef OrgRHSExprs, + ArrayRef OrgReductionOps, ReductionOptionsTy Options) { if (!CGF.HaveInsertPoint()) return; @@ -4958,10 +5202,10 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, if (SimpleReduction) { CodeGenFunction::RunCleanupsScope Scope(CGF); - const auto *IPriv = Privates.begin(); - const auto *ILHS = LHSExprs.begin(); - const auto *IRHS = RHSExprs.begin(); - for (const Expr *E : ReductionOps) { + const auto *IPriv = OrgPrivates.begin(); + const auto *ILHS = OrgLHSExprs.begin(); + const auto *IRHS = OrgRHSExprs.begin(); + for (const Expr *E : OrgReductionOps) { emitSingleReductionCombiner(CGF, E, *IPriv, cast(*ILHS), cast(*IRHS)); ++IPriv; @@ -4971,6 +5215,26 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, return; } + // Filter out shared reduction variables based on IsPrivateVarReduction flag. + // Only keep entries where the corresponding variable is not private. + SmallVector FilteredPrivates, FilteredLHSExprs, + FilteredRHSExprs, FilteredReductionOps; + for (unsigned I : llvm::seq( + std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) { + if (!Options.IsPrivateVarReduction[I]) { + FilteredPrivates.emplace_back(OrgPrivates[I]); + FilteredLHSExprs.emplace_back(OrgLHSExprs[I]); + FilteredRHSExprs.emplace_back(OrgRHSExprs[I]); + FilteredReductionOps.emplace_back(OrgReductionOps[I]); + } + } + // Wrap filtered vectors in ArrayRef for downstream shared reduction + // processing. + ArrayRef Privates = FilteredPrivates; + ArrayRef LHSExprs = FilteredLHSExprs; + ArrayRef RHSExprs = FilteredRHSExprs; + ArrayRef ReductionOps = FilteredReductionOps; + // 1. Build a list of reduction variables. // void *RedList[] = {[0], ..., [-1]}; auto Size = RHSExprs.size(); @@ -5162,7 +5426,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, } else { // Emit as a critical region. auto &&CritRedGen = [E, Loc](CodeGenFunction &CGF, const Expr *, - const Expr *, const Expr *) { + const Expr *, const Expr *) { CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime(); std::string Name = RT.getName({"atomic_reduction"}); RT.emitCriticalRegion( @@ -5209,6 +5473,16 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, CGF.EmitBranch(DefaultBB); CGF.EmitBlock(DefaultBB, /*IsFinished=*/true); + assert(OrgLHSExprs.size() == OrgPrivates.size() && + "PrivateVarReduction: Privates size mismatch"); + assert(OrgLHSExprs.size() == OrgReductionOps.size() && + "PrivateVarReduction: ReductionOps size mismatch"); + for (unsigned I : llvm::seq( + std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) { + if (Options.IsPrivateVarReduction[I]) + emitPrivateReduction(CGF, Loc, OrgPrivates[I], OrgLHSExprs[I], + OrgRHSExprs[I], OrgReductionOps[I]); + } } /// Generates unique name for artificial threadprivate variables. diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 4321712e1521d..5be48b439f4fd 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -1201,8 +1201,20 @@ class CGOpenMPRuntime { struct ReductionOptionsTy { bool WithNowait; bool SimpleReduction; + llvm::SmallVector IsPrivateVarReduction; OpenMPDirectiveKind ReductionKind; }; + + /// Emits code for private variable reduction + /// \param Privates List of private copies for original reduction arguments. + /// \param LHSExprs List of LHS in \a ReductionOps reduction operations. + /// \param RHSExprs List of RHS in \a ReductionOps reduction operations. + /// \param ReductionOps List of reduction operations in form 'LHS binop RHS' + /// or 'operator binop(LHS, RHS)'. + void emitPrivateReduction(CodeGenFunction &CGF, SourceLocation Loc, + const Expr *Privates, const Expr *LHSExprs, + const Expr *RHSExprs, const Expr *ReductionOps); + /// Emit a code for reduction clause. Next code should be emitted for /// reduction: /// \code diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 7fa6bfa75c350..d9195d749e056 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1472,6 +1472,7 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( llvm::SmallVector LHSExprs; llvm::SmallVector RHSExprs; llvm::SmallVector ReductionOps; + llvm::SmallVector IsPrivateVarReduction; bool HasAtLeastOneReduction = false; bool IsReductionWithTaskMod = false; for (const auto *C : D.getClausesOfKind()) { @@ -1482,6 +1483,8 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( Privates.append(C->privates().begin(), C->privates().end()); LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end()); RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end()); + IsPrivateVarReduction.append(C->private_var_reduction_flags().begin(), + C->private_var_reduction_flags().end()); ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end()); IsReductionWithTaskMod = IsReductionWithTaskMod || C->getModifier() == OMPC_REDUCTION_task; @@ -1503,7 +1506,7 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( // parallel directive (it always has implicit barrier). CGM.getOpenMPRuntime().emitReduction( *this, D.getEndLoc(), Privates, LHSExprs, RHSExprs, ReductionOps, - {WithNowait, SimpleReduction, ReductionKind}); + {WithNowait, SimpleReduction, IsPrivateVarReduction, ReductionKind}); } } @@ -3944,7 +3947,8 @@ static void emitScanBasedDirective( PrivScope.Privatize(); CGF.CGM.getOpenMPRuntime().emitReduction( CGF, S.getEndLoc(), Privates, LHSs, RHSs, ReductionOps, - {/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_unknown}); + {/*WithNowait=*/true, /*SimpleReduction=*/true, + /*IsPrivateVarReduction*/ {}, OMPD_unknown}); } llvm::Value *NextIVal = CGF.Builder.CreateNUWSub(IVal, llvm::ConstantInt::get(CGF.SizeTy, 1)); @@ -5749,7 +5753,8 @@ void CodeGenFunction::EmitOMPScanDirective(const OMPScanDirective &S) { } CGM.getOpenMPRuntime().emitReduction( *this, ParentDir.getEndLoc(), Privates, LHSs, RHSs, ReductionOps, - {/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_simd}); + {/*WithNowait=*/true, /*SimpleReduction=*/true, + /*IsPrivateVarReduction*/ {}, OMPD_simd}); for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) { const Expr *PrivateExpr = Privates[I]; LValue DestLVal; diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index c7447273a42fa..2897ccdf88660 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -124,7 +124,7 @@ static void resolveTopLevelMetadata(llvm::Function *Fn, auto *DIS = Fn->getSubprogram(); if (!DIS) return; - auto *NewDIS = DIS->replaceWithDistinct(DIS->clone()); + auto *NewDIS = llvm::MDNode::replaceWithDistinct(DIS->clone()); VMap.MD()[DIS].reset(NewDIS); // Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 1f5eb427b566f..5493cc92bd8b0 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 56562002e7194..70a09795d02fe 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/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 16e49aab4fe61..c27168e4c4bfe 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; @@ -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/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 1788bb4f28697..4aafac349e3e9 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -2622,8 +2622,9 @@ void CoverageMappingModuleGen::emit() { CGM.addUsedGlobal(CovData); // Create the deferred function records array if (!FunctionNames.empty()) { - auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx), - FunctionNames.size()); + auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace(); + auto NamesArrTy = llvm::ArrayType::get( + llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size()); auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); // This variable will *NOT* be emitted to the object file. It is used // to pass the list of names referenced to codegen. diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index 3efe6ab4ea9c0..b82c46966cf0b 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/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 80728daca03c9..2f86b6633df1c 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1596,28 +1596,27 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { A->claim(); if (Args.hasArg(options::OPT_spirv)) { + const llvm::StringMap ValidTargets = { + {"vulkan1.2", llvm::Triple::SPIRVSubArch_v15}, + {"vulkan1.3", llvm::Triple::SPIRVSubArch_v16}}; llvm::Triple T(TargetTriple); - T.setArch(llvm::Triple::spirv); - T.setOS(llvm::Triple::Vulkan); - // Set specific Vulkan version if applicable. + // Set specific Vulkan version. Default to vulkan1.3. + auto TargetInfo = ValidTargets.find("vulkan1.3"); + assert(TargetInfo != ValidTargets.end()); if (const Arg *A = Args.getLastArg(options::OPT_fspv_target_env_EQ)) { - const llvm::StringMap ValidTargets = { - {"vulkan1.2", llvm::Triple::SPIRVSubArch_v15}, - {"vulkan1.3", llvm::Triple::SPIRVSubArch_v16}}; - - auto TargetInfo = ValidTargets.find(A->getValue()); - if (TargetInfo != ValidTargets.end()) { - T.setOSName(TargetInfo->getKey()); - T.setArch(llvm::Triple::spirv, TargetInfo->getValue()); - } else { + TargetInfo = ValidTargets.find(A->getValue()); + if (TargetInfo == ValidTargets.end()) { Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); } A->claim(); } - - TargetTriple = T.str(); + if (TargetInfo != ValidTargets.end()) { + T.setOSName(TargetInfo->getKey()); + T.setArch(llvm::Triple::spirv, TargetInfo->getValue()); + TargetTriple = T.str(); + } } } else { Diag(diag::err_drv_dxc_missing_target_profile); @@ -4331,6 +4330,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; @@ -4424,6 +4431,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 @@ -4557,7 +4568,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(), @@ -4868,10 +4879,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; @@ -4967,12 +4999,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); @@ -4996,12 +5028,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; }); @@ -5021,11 +5053,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(), @@ -5178,8 +5208,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) && diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index b0523a7f4e40e..731076d9754a9 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 3318e498a74f9..33a655870b01b 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 a74fa81f3cf5b..a78a1c8978183 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2831,8 +2831,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 @@ -2916,6 +2917,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: @@ -2929,6 +2931,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: @@ -2938,6 +2941,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: @@ -2950,6 +2954,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: { @@ -2984,6 +2989,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ComplexArithmeticStr(RangeVal)); } } + LastComplexRangeOption = + Args.MakeArgString(A->getSpelling() + A->getValue()); Range = RangeVal; break; } @@ -3037,6 +3044,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; } @@ -3222,6 +3230,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 @@ -3239,6 +3248,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()) @@ -5184,7 +5202,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"); @@ -5241,7 +5259,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) { @@ -5683,11 +5702,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 && @@ -6889,9 +6915,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)) { @@ -7334,8 +7368,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, @@ -7684,7 +7717,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()); @@ -8392,8 +8425,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(); @@ -9231,8 +9266,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/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index e987ef78920e8..e5075cbcaf660 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 @@ struct DarwinPlatform { 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 a20879dad94d4..47d0e345086b2 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 1c165bbfe84f5..146dc8bbd5313 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 9c68c5c6de2b2..9203bbc91b0bb 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -402,7 +402,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/Edit/EditedSource.cpp b/clang/lib/Edit/EditedSource.cpp index a3386b2489b07..398cce71d5e27 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 764c345a9db99..1087eb3001856 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 e881d56258e5e..139023f32e8d3 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; diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 424b6dbc0da79..b4745477b96ef 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; + + 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 (DisallowLineBreaksOnThisLine) + 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 116bbad320e1f..895d9f93dfce3 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 aed1672afac66..d2f8b2703a9a3 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 587b0d1af9c8d..09a66b652518f 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 2c02719121c73..5c52dc33ddf6c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1492,11 +1492,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( @@ -4475,6 +4475,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/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index c1c9d2e8c7b79..c96d209c1fc0c 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -341,6 +341,7 @@ set(cuda_wrapper_files ) set(cuda_wrapper_bits_files + cuda_wrappers/bits/c++config.h cuda_wrappers/bits/shared_ptr_base.h cuda_wrappers/bits/basic_string.h cuda_wrappers/bits/basic_string.tcc diff --git a/clang/lib/Headers/__clang_cuda_intrinsics.h b/clang/lib/Headers/__clang_cuda_intrinsics.h index 8b230af6f6647..5e13f3f78df70 100644 --- a/clang/lib/Headers/__clang_cuda_intrinsics.h +++ b/clang/lib/Headers/__clang_cuda_intrinsics.h @@ -479,6 +479,290 @@ inline __device__ unsigned __funnelshift_rc(unsigned low32, unsigned high32, return ret; } +#pragma push_macro("__INTRINSIC_LOAD") +#define __INTRINSIC_LOAD(__FnName, __AsmOp, __DeclType, __TmpType, __AsmType, \ + __Clobber) \ + inline __device__ __DeclType __FnName(const __DeclType *__ptr) { \ + __TmpType __ret; \ + asm(__AsmOp " %0, [%1];" : __AsmType(__ret) : "l"(__ptr)__Clobber); \ + return (__DeclType)__ret; \ + } + +#pragma push_macro("__INTRINSIC_LOAD2") +#define __INTRINSIC_LOAD2(__FnName, __AsmOp, __DeclType, __TmpType, __AsmType, \ + __Clobber) \ + inline __device__ __DeclType __FnName(const __DeclType *__ptr) { \ + __DeclType __ret; \ + __TmpType __tmp; \ + asm(__AsmOp " {%0,%1}, [%2];" \ + : __AsmType(__tmp.x), __AsmType(__tmp.y) \ + : "l"(__ptr)__Clobber); \ + using __ElementType = decltype(__ret.x); \ + __ret.x = (__ElementType)(__tmp.x); \ + __ret.y = (__ElementType)__tmp.y; \ + return __ret; \ + } + +#pragma push_macro("__INTRINSIC_LOAD4") +#define __INTRINSIC_LOAD4(__FnName, __AsmOp, __DeclType, __TmpType, __AsmType, \ + __Clobber) \ + inline __device__ __DeclType __FnName(const __DeclType *__ptr) { \ + __DeclType __ret; \ + __TmpType __tmp; \ + asm(__AsmOp " {%0,%1,%2,%3}, [%4];" \ + : __AsmType(__tmp.x), __AsmType(__tmp.y), __AsmType(__tmp.z), \ + __AsmType(__tmp.w) \ + : "l"(__ptr)__Clobber); \ + using __ElementType = decltype(__ret.x); \ + __ret.x = (__ElementType)__tmp.x; \ + __ret.y = (__ElementType)__tmp.y; \ + __ret.z = (__ElementType)__tmp.z; \ + __ret.w = (__ElementType)__tmp.w; \ + return __ret; \ + } + +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.s8", char, unsigned int, "=r", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.s8", signed char, unsigned int, "=r", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.s16", short, unsigned short, "=h", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.s32", int, unsigned int, "=r", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.s64", long long, unsigned long long, + "=l", ); + +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.s8", char2, int2, "=r", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.s8", char4, int4, "=r", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.s16", short2, short2, "=h", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.s16", short4, short4, "=h", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.s32", int2, int2, "=r", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.s32", int4, int4, "=r", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.s64 ", longlong2, longlong2, "=l", ); + +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.u8", unsigned char, unsigned int, + "=r", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.u16", unsigned short, unsigned short, + "=h", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.u32", unsigned int, unsigned int, + "=r", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.u64", unsigned long long, + unsigned long long, "=l", ); + +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.u8", uchar2, int2, "=r", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.u8", uchar4, int4, "=r", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.u16", ushort2, ushort2, "=h", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.u16", ushort4, ushort4, "=h", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.u32", uint2, uint2, "=r", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.u32", uint4, uint4, "=r", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.u64", ulonglong2, ulonglong2, + "=l", ); + +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.f32", float, float, "=f", ); +__INTRINSIC_LOAD(__ldcg, "ld.global.cg.f64", double, double, "=d", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.f32", float2, float2, "=f", ); +__INTRINSIC_LOAD4(__ldcg, "ld.global.cg.v4.f32", float4, float4, "=f", ); +__INTRINSIC_LOAD2(__ldcg, "ld.global.cg.v2.f64", double2, double2, "=d", ); + +inline __device__ long __ldcg(const long *__ptr) { + unsigned long __ret; + if (sizeof(long) == 8) { + asm("ld.global.cg.s64 %0, [%1];" : "=l"(__ret) : "l"(__ptr)); + } else { + asm("ld.global.cg.s32 %0, [%1];" : "=r"(__ret) : "l"(__ptr)); + } + return (long)__ret; +} + +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.u8", unsigned char, unsigned int, + "=r", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.u16", unsigned short, unsigned short, + "=h", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.u32", unsigned int, unsigned int, + "=r", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.u64", unsigned long long, + unsigned long long, "=l", : "memory"); + +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.s8", char, unsigned int, + "=r", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.s8", signed char, unsigned int, + "=r", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.s16", short, unsigned short, + "=h", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.s32", int, unsigned int, + "=r", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.s64", long long, unsigned long long, + "=l", : "memory"); + +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.u8", uchar2, uint2, + "=r", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.u8", uchar4, uint4, + "=r", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.u16", ushort2, ushort2, + "=h", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.u16", ushort4, ushort4, + "=h", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.u32", uint2, uint2, + "=r", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.u32", uint4, uint4, + "=r", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.u64", ulonglong2, ulonglong2, + "=l", : "memory"); + +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.s8", char2, int2, "=r", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.s8", char4, int4, "=r", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.s16", short2, short2, + "=h", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.s16", short4, short4, + "=h", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.s32", int2, int2, "=r", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.s32", int4, int4, "=r", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.s64", longlong2, longlong2, + "=l", : "memory"); + +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.f32", float, float, "=f", : "memory"); +__INTRINSIC_LOAD(__ldcv, "ld.global.cv.f64", double, double, "=d", : "memory"); + +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.f32", float2, float2, + "=f", : "memory"); +__INTRINSIC_LOAD4(__ldcv, "ld.global.cv.v4.f32", float4, float4, + "=f", : "memory"); +__INTRINSIC_LOAD2(__ldcv, "ld.global.cv.v2.f64", double2, double2, + "=d", : "memory"); + +inline __device__ long __ldcv(const long *__ptr) { + unsigned long __ret; + if (sizeof(long) == 8) { + asm("ld.global.cv.s64 %0, [%1];" : "=l"(__ret) : "l"(__ptr)); + } else { + asm("ld.global.cv.s32 %0, [%1];" : "=r"(__ret) : "l"(__ptr)); + } + return (long)__ret; +} + +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.s8", char, unsigned int, "=r", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.s8", signed char, signed int, "=r", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.s16", short, unsigned short, "=h", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.s32", int, unsigned int, "=r", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.s64", long long, unsigned long long, + "=l", ); + +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.s8", char2, int2, "=r", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.s8", char4, int4, "=r", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.s16", short2, short2, "=h", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.s16", short4, short4, "=h", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.s32", int2, int2, "=r", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.s32", int4, int4, "=r", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.s64", longlong2, longlong2, "=l", ); + +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.u8", unsigned char, unsigned int, + "=r", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.u16", unsigned short, unsigned short, + "=h", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.u32", unsigned int, unsigned int, + "=r", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.u64", unsigned long long, + unsigned long long, "=l", ); + +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.u8", uchar2, uint2, "=r", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.u8", uchar4, uint4, "=r", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.u16", ushort2, ushort2, "=h", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.u16", ushort4, ushort4, "=h", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.u32", uint2, uint2, "=r", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.u32", uint4, uint4, "=r", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.u64", ulonglong2, ulonglong2, + "=l", ); + +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.f32", float, float, "=f", ); +__INTRINSIC_LOAD(__ldcs, "ld.global.cs.f64", double, double, "=d", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.f32", float2, float2, "=f", ); +__INTRINSIC_LOAD4(__ldcs, "ld.global.cs.v4.f32", float4, float4, "=f", ); +__INTRINSIC_LOAD2(__ldcs, "ld.global.cs.v2.f64", double2, double2, "=d", ); + +#pragma pop_macro("__INTRINSIC_LOAD") +#pragma pop_macro("__INTRINSIC_LOAD2") +#pragma pop_macro("__INTRINSIC_LOAD4") + +inline __device__ long __ldcs(const long *__ptr) { + unsigned long __ret; + if (sizeof(long) == 8) { + asm("ld.global.cs.s64 %0, [%1];" : "=l"(__ret) : "l"(__ptr)); + } else { + asm("ld.global.cs.s32 %0, [%1];" : "=r"(__ret) : "l"(__ptr)); + } + return (long)__ret; +} + +#pragma push_macro("__INTRINSIC_STORE") +#define __INTRINSIC_STORE(__FnName, __AsmOp, __DeclType, __TmpType, __AsmType) \ + inline __device__ void __FnName(__DeclType *__ptr, __DeclType __value) { \ + __TmpType __tmp = (__TmpType)__value; \ + asm(__AsmOp " [%0], %1;" ::"l"(__ptr), __AsmType(__tmp) : "memory"); \ + } + +#pragma push_macro("__INTRINSIC_STORE2") +#define __INTRINSIC_STORE2(__FnName, __AsmOp, __DeclType, __TmpType, \ + __AsmType) \ + inline __device__ void __FnName(__DeclType *__ptr, __DeclType __value) { \ + __TmpType __tmp; \ + using __ElementType = decltype(__tmp.x); \ + __tmp.x = (__ElementType)(__value.x); \ + __tmp.y = (__ElementType)(__value.y); \ + asm(__AsmOp " [%0], {%1,%2};" ::"l"(__ptr), __AsmType(__tmp.x), \ + __AsmType(__tmp.y) \ + : "memory"); \ + } + +#pragma push_macro("__INTRINSIC_STORE4") +#define __INTRINSIC_STORE4(__FnName, __AsmOp, __DeclType, __TmpType, \ + __AsmType) \ + inline __device__ void __FnName(__DeclType *__ptr, __DeclType __value) { \ + __TmpType __tmp; \ + using __ElementType = decltype(__tmp.x); \ + __tmp.x = (__ElementType)(__value.x); \ + __tmp.y = (__ElementType)(__value.y); \ + __tmp.z = (__ElementType)(__value.z); \ + __tmp.w = (__ElementType)(__value.w); \ + asm(__AsmOp " [%0], {%1,%2,%3,%4};" ::"l"(__ptr), __AsmType(__tmp.x), \ + __AsmType(__tmp.y), __AsmType(__tmp.z), __AsmType(__tmp.w) \ + : "memory"); \ + } + +__INTRINSIC_STORE(__stwt, "st.global.wt.s8", char, int, "r"); +__INTRINSIC_STORE(__stwt, "st.global.wt.s8", signed char, int, "r"); +__INTRINSIC_STORE(__stwt, "st.global.wt.s16", short, short, "h"); +__INTRINSIC_STORE(__stwt, "st.global.wt.s32", int, int, "r"); +__INTRINSIC_STORE(__stwt, "st.global.wt.s64", long long, long long, "l"); + +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.s8", char2, int2, "r"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.s8", char4, int4, "r"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.s16", short2, short2, "h"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.s16", short4, short4, "h"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.s32", int2, int2, "r"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.s32", int4, int4, "r"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.s64", longlong2, longlong2, "l"); + +__INTRINSIC_STORE(__stwt, "st.global.wt.u8", unsigned char, int, "r"); +__INTRINSIC_STORE(__stwt, "st.global.wt.u16", unsigned short, unsigned short, + "h"); +__INTRINSIC_STORE(__stwt, "st.global.wt.u32", unsigned int, unsigned int, "r"); +__INTRINSIC_STORE(__stwt, "st.global.wt.u64", unsigned long long, + unsigned long long, "l"); + +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.u8", uchar2, uchar2, "r"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.u8", uchar4, uint4, "r"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.u16", ushort2, ushort2, "h"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.u16", ushort4, ushort4, "h"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.u32", uint2, uint2, "r"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.u32", uint4, uint4, "r"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.u64", ulonglong2, ulonglong2, "l"); + +__INTRINSIC_STORE(__stwt, "st.global.wt.f32", float, float, "f"); +__INTRINSIC_STORE(__stwt, "st.global.wt.f64", double, double, "d"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.f32", float2, float2, "f"); +__INTRINSIC_STORE4(__stwt, "st.global.wt.v4.f32", float4, float4, "f"); +__INTRINSIC_STORE2(__stwt, "st.global.wt.v2.f64", double2, double2, "d"); + +#pragma pop_macro("__INTRINSIC_STORE") +#pragma pop_macro("__INTRINSIC_STORE2") +#pragma pop_macro("__INTRINSIC_STORE4") + #endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 320 #if CUDA_VERSION >= 11000 diff --git a/clang/lib/Headers/cuda_wrappers/bits/c++config.h b/clang/lib/Headers/cuda_wrappers/bits/c++config.h new file mode 100644 index 0000000000000..eafa13a9cc640 --- /dev/null +++ b/clang/lib/Headers/cuda_wrappers/bits/c++config.h @@ -0,0 +1,51 @@ +// libstdc++ uses the non-constexpr function std::__glibcxx_assert_fail() +// to trigger compilation errors when the __glibcxx_assert(cond) macro +// is used in a constexpr context. +// Compilation fails when using code from the libstdc++ (such as std::array) on +// device code, since these assertions invoke a non-constexpr host function from +// device code. +// +// To work around this issue, we declare our own device version of the function + +#ifndef __CLANG_CUDA_WRAPPERS_BITS_CPP_CONFIG +#define __CLANG_CUDA_WRAPPERS_BITS_CPP_CONFIG + +#include_next + +#ifdef _LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_BEGIN_NAMESPACE_STD +#else +namespace std { +#ifdef _GLIBCXX_BEGIN_NAMESPACE_VERSION +_GLIBCXX_BEGIN_NAMESPACE_VERSION +#endif + +#ifdef _GLIBCXX_VERBOSE_ASSERT +__attribute__((device, noreturn)) inline void +__glibcxx_assert_fail(const char *file, int line, const char *function, + const char *condition) noexcept { + if (file && function && condition) + __builtin_printf("%s:%d: %s: Assertion '%s' failed.\n", file, line, + function, condition); + else if (function) + __builtin_printf("%s: Undefined behavior detected.\n", function); + __builtin_abort(); +} +#endif + +#endif +__attribute__((device, noreturn, __always_inline__, + __visibility__("default"))) inline void +__glibcxx_assert_fail(...) noexcept { + __builtin_abort(); +} +#ifdef _LIBCPP_END_NAMESPACE_STD +_LIBCPP_END_NAMESPACE_STD +#else +#ifdef _GLIBCXX_BEGIN_NAMESPACE_VERSION +_GLIBCXX_END_NAMESPACE_VERSION +#endif +} // namespace std +#endif + +#endif diff --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp index 2ed20df22bda0..98ce6f73ec849 100644 --- a/clang/lib/Index/IndexBody.cpp +++ b/clang/lib/Index/IndexBody.cpp @@ -435,6 +435,13 @@ class BodyIndexer : public RecursiveASTVisitor { 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 fd9db8113a41e..37b428216c91e 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 be43a96f3d97d..f8f708fda4ca4 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 65610903840af..8f8ed6e8a5db6 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 9e8c60fbda3d0..cce0b19b50619 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 a73ea0b0d124c..487be2c300887 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 05625ddedb72f..9a25a264b2d5c 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 3e3fbfd172caa..3e7e32b2e8557 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 eb2ce9c9fd330..afdf406b37253 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 4606b85d42fe7..1b6b16c561141 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 588b32ee9ca8e..a7b670f00ac6e 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/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt index 00fde537bb9c6..e6cbf3b868b7d 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 e215c64cccd11..9a010fb5f3427 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 f469e466e4634..02f33511dbd61 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -151,7 +151,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; } @@ -396,12 +396,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 @@ -436,7 +436,6 @@ bool Parser::ParseAttributeArgumentList( } else { Expr = ParseAssignmentExpression(); } - Expr = Actions.CorrectDelayedTyposInExpr(Expr); if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); @@ -472,15 +471,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; } @@ -565,9 +555,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; @@ -621,10 +609,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); } } @@ -866,7 +856,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(); @@ -952,7 +942,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(); @@ -980,7 +970,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; } @@ -1001,9 +991,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() { @@ -1047,7 +1036,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); } } @@ -1057,7 +1046,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); } } @@ -1066,7 +1055,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__); } } @@ -1074,7 +1063,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()); } @@ -1086,7 +1075,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) { @@ -1103,7 +1092,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; } @@ -1447,10 +1436,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( @@ -1568,7 +1558,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( @@ -1636,8 +1627,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( @@ -1678,7 +1669,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( @@ -1731,9 +1723,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) @@ -1840,9 +1832,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(); @@ -3129,12 +3122,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); } } @@ -3180,9 +3173,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)); } @@ -3212,9 +3204,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; @@ -3230,7 +3220,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() { @@ -4009,7 +3999,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; } @@ -4067,8 +4057,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; @@ -6252,8 +6243,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; @@ -6890,8 +6882,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. @@ -7538,8 +7530,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. @@ -7653,7 +7644,6 @@ void Parser::ParseParameterDeclarationClause( } DefArgResult = ParseAssignmentExpression(); } - DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param, EqualLoc, /*DefaultArg=*/nullptr); @@ -7799,8 +7789,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { } else { EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - NumElements = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + NumElements = ParseAssignmentExpression(); } } else { if (StaticLoc.isValid()) { @@ -7937,8 +7926,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 0b5f56fea0b14..c1493a5bfd3b3 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -29,6 +29,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 @@ -760,6 +761,10 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( Decl *AD = ParseAliasDeclarationAfterDeclarator( TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec); + + if (!AD) + return nullptr; + return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec); } @@ -1071,10 +1076,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)) { @@ -1433,7 +1435,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); } } @@ -1442,7 +1444,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); } } @@ -4465,8 +4467,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); @@ -4497,8 +4498,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; @@ -4578,7 +4579,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; } @@ -4633,7 +4634,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; } @@ -4728,12 +4729,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; } @@ -4894,13 +4898,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(); @@ -4942,18 +4946,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; @@ -4963,12 +4963,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 @@ -4979,8 +4976,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()); } @@ -5011,7 +5008,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(); @@ -5030,7 +5027,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 951a157305ddc..3cf3d4ea7d705 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -183,7 +183,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; @@ -244,7 +243,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; @@ -256,14 +254,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; @@ -281,14 +276,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; @@ -408,7 +400,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } if (TernaryMiddle.isInvalid()) { - Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); TernaryMiddle = nullptr; } @@ -466,11 +457,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(); } @@ -503,11 +489,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(); } @@ -532,7 +513,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()) { @@ -571,17 +551,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); } } } @@ -1711,7 +1680,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); @@ -1737,8 +1705,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 { @@ -1746,7 +1712,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } else if (Tok.isNot(tok::r_square)) { if (ParseExpressionList(ArgExprs)) { - LHS = Actions.CorrectDelayedTyposInExpr(LHS); HasError = true; } } @@ -1762,7 +1727,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); @@ -1773,7 +1738,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 && @@ -1789,8 +1753,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()) { @@ -1838,7 +1800,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation OpenLoc = ConsumeToken(); if (ParseSimpleExpressionList(ExecConfigExprs)) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } @@ -1889,16 +1850,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); } } } @@ -1913,16 +1870,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(); @@ -2050,7 +2007,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*AllowConstructorName=*/ getLangOpts().MicrosoftExt && SS.isNotEmpty(), /*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) { - (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } @@ -2921,8 +2877,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, @@ -2936,7 +2891,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()) { @@ -2948,12 +2903,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; @@ -3057,8 +3006,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(); @@ -3104,8 +3052,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(); @@ -3199,8 +3146,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) @@ -3213,9 +3159,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)) { @@ -3244,14 +3187,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 d95260829e4a0..1ea0cf52933f6 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -421,8 +421,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. } @@ -972,8 +972,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. @@ -1065,8 +1063,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 @@ -1238,8 +1234,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); @@ -3202,8 +3198,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); @@ -3306,8 +3301,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); @@ -3373,8 +3367,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 5569605c287b1..e6caa81b309ca 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -289,12 +289,13 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, case ParsedAttr::AT_HLSLSV_GroupID: case ParsedAttr::AT_HLSLSV_GroupIndex: case ParsedAttr::AT_HLSLSV_DispatchThreadID: + case ParsedAttr::AT_HLSLSV_Position: break; default: llvm_unreachable("invalid HLSL Annotation"); 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 df8372b995e55..a3be3744a9327 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()); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 6afb7809d3cd2..291c70e7bad4b 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 ca4f878464c4f..f2849c4eac7cc 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 e41e5ba8596b9..78d3503d8eb68 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 6341e565b5042..98933811265e8 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 c788723023c8b..bc40b726bf41b 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -602,7 +602,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { { ParseScopeFlags FilterScope(this, getCurScope()->getFlags() | Scope::SEHFilterScope); - FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + FilterExpr = ParseExpression(); } if (getLangOpts().Borland) { @@ -832,10 +832,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; } @@ -1829,11 +1831,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( @@ -2015,7 +2013,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { } } else { ProhibitAttributes(attrs); - Value = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + Value = ParseExpression(); ForEach = isTokIdentifier_in(); @@ -2174,12 +2172,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRangeInfo.ParsedForRangeDecl()) { - ExprResult CorrectedRange = - Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get()); ForRangeStmt = Actions.ActOnCXXForRangeStmt( getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(), - ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(), - T.getCloseLocation(), Sema::BFRK_Build, + ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, + 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 @@ -2349,8 +2345,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 f2417479a0e78..182907df56070 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 d3c9ca029c9aa..a16dbe95b788d 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -296,8 +296,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 db65c05cc114a..788ed79e0c1fa 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1873,6 +1873,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) diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index 1829a4ff3504a..109cdf990543a 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/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9826abc0c3b40..42ebf2a508a26 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 def909fc2478d..f21cbbbdb44ee 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/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8f8e1ceb7197e..69276ce418fa6 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/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 425b32e53a7b7..a1389c6c034b1 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 bbd63372c168b..1bf72e5bb7b9d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -62,6 +62,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 @@ -13518,8 +13519,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())) @@ -13550,19 +13571,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 @@ -13575,7 +13593,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(); } } } @@ -13584,7 +13602,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; } @@ -13607,12 +13624,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; @@ -13627,23 +13640,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; @@ -13789,23 +13791,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); @@ -13978,31 +13963,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 @@ -14730,6 +14694,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) { @@ -14765,6 +14740,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 6360827f415b8..1c2fa80e782d4 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; } @@ -3233,8 +3231,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; @@ -3242,8 +3239,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) @@ -7588,6 +7584,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLWaveSize: S.HLSL().handleWaveSizeAttr(D, AL); break; + case ParsedAttr::AT_HLSLSV_Position: + S.HLSL().handleSV_PositionAttr(D, AL); + break; case ParsedAttr::AT_HLSLVkExtBuiltinInput: S.HLSL().handleVkExtBuiltinInputAttr(D, AL); break; @@ -7953,8 +7952,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(); @@ -7972,15 +7970,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 39d4d49a0fe79..16645ecf411e5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2865,8 +2865,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(); @@ -4154,10 +4153,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(); @@ -4207,23 +4202,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 @@ -4393,13 +4385,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); @@ -7172,7 +7158,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()) @@ -7181,16 +7170,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 c692f824da422..0a6cea8869c14 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1368,7 +1368,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 c7abbbd6993de..ebc43157d4c2b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2446,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 @@ -2544,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(); @@ -2604,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; @@ -2880,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; @@ -2896,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"); @@ -7009,40 +6938,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); @@ -7281,6 +7176,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. @@ -7933,12 +7829,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); @@ -8984,30 +8874,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; @@ -15021,18 +14887,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. @@ -15068,28 +14922,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, @@ -15146,7 +14978,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(); @@ -15662,12 +15493,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 @@ -18194,8 +18021,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 && @@ -18263,9 +18088,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() { @@ -20023,8 +19845,6 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { } ExprResult Sema::ActOnConstantExpression(ExprResult Res) { - Res = CorrectDelayedTyposInExpr(Res); - if (!Res.isUsable()) return Res; @@ -21350,15 +21170,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; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 2546ab5c0a342..4a86cbd0633b6 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -40,7 +40,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" @@ -1500,13 +1499,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; @@ -2888,7 +2881,7 @@ static bool resolveAllocationOverload( // type-identity-less argument list. IAP.PassTypeIdentity = TypeAwareAllocationMode::No; IAP.PassAlignment = InitialAlignmentMode; - Args = UntypedParameters; + Args = std::move(UntypedParameters); } assert(!S.isStdTypeIdentity(Args[0]->getType(), nullptr)); return resolveAllocationOverloadInterior( @@ -7653,417 +7646,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) { @@ -8095,8 +7677,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 39c162c3b835d..5dca509d46fdb 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -650,64 +650,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) && @@ -724,56 +671,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; } @@ -793,15 +690,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 { @@ -1396,16 +1289,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/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 9065cc5a1d4a5..b55f4fd786b58 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -764,6 +764,13 @@ void SemaHLSL::CheckSemanticAnnotation( return; DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute}); break; + case attr::HLSLSV_Position: + // TODO(#143523): allow use on other shader types & output once the overall + // semantic logic is implemented. + if (ST == llvm::Triple::Pixel) + return; + DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel}); + break; default: llvm_unreachable("Unknown HLSLAnnotationAttr"); } @@ -971,6 +978,31 @@ 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); + + SignatureDecl->setImplicit(); + SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); +} + void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() != 1) { Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -1147,6 +1179,26 @@ void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); } +bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) { + const auto *VT = T->getAs(); + + if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "float/float1/float2/float3/float4"; + return false; + } + + return true; +} + +void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) { + auto *VD = cast(D); + if (!diagnosePositionType(VD->getType(), AL)) + return; + + D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL)); +} + void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) { auto *VD = cast(D); if (!diagnoseInputIDType(VD->getType(), AL)) @@ -2179,8 +2231,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); } @@ -2493,8 +2546,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()) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index eef134b158438..5ad9dd8ed0d3e 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1978,6 +1978,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 @@ -1996,17 +1998,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; } @@ -5431,40 +5444,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; @@ -5789,32 +5768,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 6c4df0aa35af5..9fcaad48d3058 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -712,7 +712,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 +726,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 56815cd2731a1..0f39a9817ce7f 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 4ac3a60ae455f..d928b7ae2b4c2 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); } @@ -19047,34 +19052,14 @@ static bool actOnOMPReductionKindClause( reportOriginalDsa(S, Stack, D, DVar); continue; } - // OpenMP 6.0 [ 7.6.10 ] - // Support Reduction over private variables with reduction clause. - // A list item in a reduction clause can now be private in the enclosing - // context. For orphaned constructs it is assumed to be shared unless the - // original(private) modifier appears in the clause. - DVar = Stack->getImplicitDSA(D, true); - bool IsOrphaned = false; - OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective(); - OpenMPDirectiveKind ParentDir = Stack->getParentDirective(); - // Check if the construct is orphaned (has no enclosing OpenMP context) - IsOrphaned = ParentDir == OMPD_unknown; - // OpenMP 6.0: Private DSA check - IsPrivate = - (S.getLangOpts().OpenMP > 52) && - ((isOpenMPPrivate(DVar.CKind) && DVar.CKind != OMPC_reduction && - isOpenMPWorksharingDirective(CurrDir) && - !isOpenMPParallelDirective(CurrDir) && - !isOpenMPTeamsDirective(CurrDir) && - !isOpenMPSimdDirective(ParentDir)) || - (IsOrphaned && DVar.CKind == OMPC_unknown) || - RD.OrigSharingModifier != OMPC_ORIGINAL_SHARING_shared); // OpenMP [2.14.3.6, Restrictions, p.1] // A list item that appears in a reduction clause of a worksharing // construct must be shared in the parallel regions to which any of the // worksharing regions arising from the worksharing construct bind. - if (!IsPrivate && isOpenMPWorksharingDirective(CurrDir) && + if (S.getLangOpts().OpenMP <= 52 && + isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir) && !isOpenMPTeamsDirective(CurrDir)) { DVar = Stack->getImplicitDSA(D, true); @@ -19085,6 +19070,23 @@ static bool actOnOMPReductionKindClause( reportOriginalDsa(S, Stack, D, DVar); continue; } + } else if (isOpenMPWorksharingDirective(CurrDir) && + !isOpenMPParallelDirective(CurrDir) && + !isOpenMPTeamsDirective(CurrDir)) { + // OpenMP 6.0 [ 7.6.10 ] + // Support Reduction over private variables with reduction clause. + // A list item in a reduction clause can now be private in the enclosing + // context. For orphaned constructs it is assumed to be shared unless + // the original(private) modifier appears in the clause. + DVar = Stack->getImplicitDSA(D, true); + // Determine if the variable should be considered private + IsPrivate = DVar.CKind != OMPC_shared; + bool IsOrphaned = false; + OpenMPDirectiveKind ParentDir = Stack->getParentDirective(); + IsOrphaned = ParentDir == OMPD_unknown; + if ((IsOrphaned && + RD.OrigSharingModifier == OMPC_ORIGINAL_SHARING_private)) + IsPrivate = true; } } else { // Threadprivates cannot be shared between threads, so dignose if the base @@ -22060,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 cf455f4588de3..8c5f81f126c7a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -9272,11 +9272,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(); @@ -11322,9 +11321,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; @@ -14055,8 +14054,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 9f70be746eb3f..9eab0c2a0df6a 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/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 50f5757dff5bc..923a9e81fbd6a 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,10 +3840,7 @@ 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); + ExprResult RetVal = RetValExp; if (RetVal.isInvalid()) return StmtError(); diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 17da5fd8325be..857d46af9ada9 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 57271415f838c..a25bfd1c48dee 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 5f0e968ff18c4..572dbf2e7393f 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -741,7 +741,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(); } @@ -1201,11 +1200,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 = @@ -1403,11 +1400,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 @@ -1415,7 +1407,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 @@ -1430,7 +1421,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 a0cd2d1615243..785d7b89e778e 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4552,7 +4552,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); @@ -5735,10 +5735,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 d663e5581093e..4dbb2450857e0 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -105,7 +105,7 @@ static CXXMethodDecl *LookupSpecialMemberFromXValue(Sema &SemaRef, switch (OCS.BestViableFunction(SemaRef, LookupLoc, Best)) { case OR_Success: case OR_Deleted: - return cast(Best->Function); + return cast(Best->Function)->getCanonicalDecl(); default: return nullptr; } @@ -164,6 +164,8 @@ static bool IsDefaultMovable(Sema &SemaRef, const CXXRecordDecl *D) { if (!Dtr) return true; + Dtr = Dtr->getCanonicalDecl(); + if (Dtr->isUserProvided() && (!Dtr->isDefaulted() || Dtr->isDeleted())) return false; @@ -186,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; @@ -195,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(); } @@ -311,7 +320,6 @@ bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) { } bool Sema::IsCXXTriviallyRelocatableType(QualType Type) { - QualType BaseElementType = getASTContext().getBaseElementType(Type); if (Type->isVariableArrayType()) @@ -320,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()) @@ -668,7 +676,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(); @@ -2044,11 +2055,13 @@ static void DiagnoseNonDefaultMovable(Sema &SemaRef, SourceLocation Loc, << diag::TraitNotSatisfiedReason::UserProvidedAssign << Decl->isMoveAssignmentOperator() << Decl->getSourceRange(); } - CXXDestructorDecl *Dtr = D->getDestructor(); - if (Dtr && Dtr->isUserProvided() && !Dtr->isDefaulted()) - SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) - << diag::TraitNotSatisfiedReason::DeletedDtr << /*User Provided*/ 1 - << Dtr->getSourceRange(); + if (CXXDestructorDecl *Dtr = D->getDestructor()) { + Dtr = Dtr->getCanonicalDecl(); + if (Dtr->isUserProvided() && !Dtr->isDefaulted()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::DeletedDtr << /*User Provided*/ 1 + << Dtr->getSourceRange(); + } } static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c8d29f0a625f8..3e33fb73e01b4 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13121,12 +13121,6 @@ TreeTransform::TransformOpaqueValueExpr(OpaqueValueExpr *E) { return E; } -template -ExprResult -TreeTransform::TransformTypoExpr(TypoExpr *E) { - return E; -} - template ExprResult TreeTransform::TransformRecoveryExpr(RecoveryExpr *E) { llvm::SmallVector Children; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8dafefb9696bf..a1368a48351c6 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -3198,8 +3198,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}); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 01c838b955755..65102b64030c6 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2310,10 +2310,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(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ab1b5b333e06a..be22ee5221911 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5167,8 +5167,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 diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 8f82324a27535..052cb5a253bf7 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -221,6 +221,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 @@ -235,6 +277,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); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 767e7405752c2..a6e320c7f3eb0 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2314,12 +2314,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 15d73fb9ca39a..ab90615f63182 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/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index fef33509c0b6e..35e98a5e2719a 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 461d01b452fd0..9744d1abf7790 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 @@ class NullabilityChecker 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 - }; - - 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]; - } + StringRef getDebugTag() const override { return "NullabilityChecker"; } + + // 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 @@ class NullabilityChecker /// /// 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) - return; + 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, - CK_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, + 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(); -} - -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); \ +// 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"; + +#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 a00a09f60fd5d..62bc3218d9ced 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 b28deee41d1c5..c77ef26da568d 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1732,7 +1732,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 836fc375809ad..f965bfb590d80 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 daf09ac66f214..5a4e805d4a9d1 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 d01c57ee69c00..999fa790124cb 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/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 44a270d5f7b35..b1495163ccc24 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/cxx17.cpp b/clang/test/AST/ByteCode/cxx17.cpp index 08a40e0a92862..0cf3a4f666d63 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/literals.cpp b/clang/test/AST/ByteCode/literals.cpp index 2fa7b69b93470..699746c0b2c4a 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 1ee41a98e13bb..9c293e5d15fc8 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/ast-dump-aarch64-neon-types.c b/clang/test/AST/ast-dump-aarch64-neon-types.c index 16255cd51c9d8..f509bd880c14b 100644 --- a/clang/test/AST/ast-dump-aarch64-neon-types.c +++ b/clang/test/AST/ast-dump-aarch64-neon-types.c @@ -9,7 +9,7 @@ // RUN: %clang_cc1 -verify -verify-ignore-unexpected=note -triple arm-linux-gnu %s -x c++ __Int8x8_t Int8x8; -// CHECK: Int8x8 '__Int8x8_t':'__attribute__((neon_vector_type(8))) char' +// CHECK: Int8x8 '__Int8x8_t':'__attribute__((neon_vector_type(8))) signed char' // expected-error@-2{{unknown type name '__Int8x8_t'}} __Int16x4_t Int16x4; @@ -21,7 +21,7 @@ __Int32x2_t Int32x2; // expected-error@-2{{unknown type name '__Int32x2_t'}} __Uint8x8_t Uint8x8; -// CHECK: Uint8x8 '__Uint8x8_t':'__attribute__((neon_vector_type(8))) char' +// CHECK: Uint8x8 '__Uint8x8_t':'__attribute__((neon_vector_type(8))) unsigned char' // expected-error@-2{{unknown type name '__Uint8x8_t'}} __Uint16x4_t Uint16x4; @@ -33,7 +33,7 @@ __Uint32x2_t Uint32x2; // expected-error@-2{{unknown type name '__Uint32x2_t'}} __Float16x4_t Float16x4; -// CHECK: Float16x4 '__Float16x4_t':'__attribute__((neon_vector_type(4))) _Float16' +// CHECK: Float16x4 '__Float16x4_t':'__attribute__((neon_vector_type(4))) __fp16' // expected-error@-2{{unknown type name '__Float16x4_t'}} __Float32x2_t Float32x2; @@ -41,7 +41,7 @@ __Float32x2_t Float32x2; // expected-error@-2{{unknown type name '__Float32x2_t'}} __Poly8x8_t Poly8x8; -// CHECK: Poly8x8 '__Poly8x8_t':'__attribute__((neon_polyvector_type(8))) char' +// CHECK: Poly8x8 '__Poly8x8_t':'__attribute__((neon_polyvector_type(8))) unsigned char' // expected-error@-2{{unknown type name '__Poly8x8_t'}} __Poly16x4_t Poly16x4; @@ -53,7 +53,7 @@ __Bfloat16x4_t Bfloat16x4; // expected-error@-2{{unknown type name '__Bfloat16x4_t'}} __Int8x16_t Int8x16; -// CHECK: Int8x16 '__Int8x16_t':'__attribute__((neon_vector_type(16))) char' +// CHECK: Int8x16 '__Int8x16_t':'__attribute__((neon_vector_type(16))) signed char' // expected-error@-2{{unknown type name '__Int8x16_t'}} __Int16x8_t Int16x8; @@ -65,11 +65,11 @@ __Int32x4_t Int32x4; // expected-error@-2{{unknown type name '__Int32x4_t'}} __Int64x2_t Int64x2; -// CHECK: Int64x2 '__Int64x2_t':'__attribute__((neon_vector_type(2))) long long' +// CHECK: Int64x2 '__Int64x2_t':'__attribute__((neon_vector_type(2))) long' // expected-error@-2{{unknown type name '__Int64x2_t'}} __Uint8x16_t Uint8x16; -// CHECK: Uint8x16 '__Uint8x16_t':'__attribute__((neon_vector_type(16))) char' +// CHECK: Uint8x16 '__Uint8x16_t':'__attribute__((neon_vector_type(16))) unsigned char' // expected-error@-2{{unknown type name '__Uint8x16_t'}} __Uint16x8_t Uint16x8; @@ -81,11 +81,11 @@ __Uint32x4_t Uint32x4; // expected-error@-2{{unknown type name '__Uint32x4_t'}} __Uint64x2_t Uint64x2; -// CHECK: Uint64x2 '__Uint64x2_t':'__attribute__((neon_vector_type(2))) unsigned long long' +// CHECK: Uint64x2 '__Uint64x2_t':'__attribute__((neon_vector_type(2))) unsigned long' // expected-error@-2{{unknown type name '__Uint64x2_t'}} __Float16x8_t Float16x8; -// CHECK: Float16x8 '__Float16x8_t':'__attribute__((neon_vector_type(8))) _Float16' +// CHECK: Float16x8 '__Float16x8_t':'__attribute__((neon_vector_type(8))) __fp16' // expected-error@-2{{unknown type name '__Float16x8_t'}} __Float32x4_t Float32x4; @@ -97,7 +97,7 @@ __Float64x2_t Float64x2; // expected-error@-2{{unknown type name '__Float64x2_t'}} __Poly8x16_t Poly8x16; -// CHECK: Poly8x16 '__Poly8x16_t':'__attribute__((neon_polyvector_type(16))) char' +// CHECK: Poly8x16 '__Poly8x16_t':'__attribute__((neon_polyvector_type(16))) unsigned char' // expected-error@-2{{unknown type name '__Poly8x16_t'}} __Poly16x8_t Poly16x8; @@ -105,7 +105,7 @@ __Poly16x8_t Poly16x8; // expected-error@-2{{unknown type name '__Poly16x8_t'}} __Poly64x2_t Poly64x2; -// CHECK: Poly64x2 '__Poly64x2_t':'__attribute__((neon_polyvector_type(2))) unsigned long long' +// CHECK: Poly64x2 '__Poly64x2_t':'__attribute__((neon_polyvector_type(2))) unsigned long' // expected-error@-2{{unknown type name '__Poly64x2_t'}} __Bfloat16x8_t Bfloat16x8; diff --git a/clang/test/AST/ast-dump-recovery.c b/clang/test/AST/ast-dump-recovery.c index 68d3f182dd9f6..09a03fb9d6fdf 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 b8195950f2fa1..a8e30f1759e9f 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,52 +178,12 @@ 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 // CHECK-NEXT: `-InitListExpr @@ -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 37fa8045c0b94..0000000000000 --- 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 06754f669b1e6..da0eef7c52bd8 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 66b9be9795f12..78ee00deea18d 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 0000000000000..4cb97f9de8299 --- /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 80820f4c93444..8bb0196b2f9b8 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 8c6078a49c231..7f9c9ff4c9fd7 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 3c520612c5d9b..9d6d2942df4a9 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 7b90c1682ec45..26e172a006451 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 abc1a45fd433f..7ff73ee95f799 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/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp new file mode 100644 index 0000000000000..322c13c8f081a --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin_call.cpp @@ -0,0 +1,96 @@ +// 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() diff --git a/clang/test/CIR/CodeGen/builtin_printf.cpp b/clang/test/CIR/CodeGen/builtin_printf.cpp new file mode 100644 index 0000000000000..366e474c2b09a --- /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 0000000000000..13f3c5a21ceb0 --- /dev/null +++ b/clang/test/CIR/CodeGen/call.c @@ -0,0 +1,111 @@ +// 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]]) diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp index 741cadeb5c764..cc25afce1e5a4 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 a7c11b1939ba5..84f55242a6118 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 6fa7bca3749cf..db0b9111ab4fb 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -27,3 +27,181 @@ 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 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 diff --git a/clang/test/CIR/CodeGen/ctor.cpp b/clang/test/CIR/CodeGen/ctor.cpp new file mode 100644 index 0000000000000..1a36eb0d9d3a6 --- /dev/null +++ b/clang/test/CIR/CodeGen/ctor.cpp @@ -0,0 +1,115 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +struct Struk { + int a; + Struk() {} +}; + +void baz() { + Struk s; +} + +// CHECK: !rec_Struk = !cir.record + +// 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 6b6ccc79e59dd..45e146e9091d0 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 0000000000000..f65fe92cd36a0 --- /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 0000000000000..f45a41d9a00fc --- /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 0000000000000..9b892c69a6fed --- /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 00f59b09400c8..90ea21906f363 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 0000000000000..c56eb74387329 --- /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/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp index e1814f216f6b9..fe4919ec0478d 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 4f116faa7a1ac..d0c5b83cd5b04 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 1f3c9f1a8d3fa..5b83a9cb91898 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 db94e2819b301..c0bf11e353951 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/invalid-vector-shuffle-wrong-index.cir b/clang/test/CIR/IR/invalid-vector-shuffle-wrong-index.cir new file mode 100644 index 0000000000000..375b2d3dc563e --- /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 a455acf92ab6f..f23f5de9692de 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 0000000000000..5d9d22112c8b7 --- /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 0000000000000..b207fc08748e2 --- /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 0000000000000..fb8f66dc4debc --- /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/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp index 8b84de0ab5a9a..c9dce77b772dc 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 ab4d3695b6e22..60d896443ecd1 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.link/p2.cppm b/clang/test/CXX/module/basic/basic.link/p2.cppm index d7d2b5992a235..6a2c67526c9a1 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/dcl.dcl/dcl.module/dcl.module.import/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm index 873e4c0edeac2..3670f9430ed4b 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 @@ -45,7 +45,7 @@ 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 {{unknown attribute 'blarg::noreturn' ignored}} import x.y; import x.; // expected-error {{expected a module name after 'import'}} diff --git a/clang/test/CodeGen/AArch64/mixed-neon-types.c b/clang/test/CodeGen/AArch64/mixed-neon-types.c index 47681a507d715..34fbe499f4052 100644 --- a/clang/test/CodeGen/AArch64/mixed-neon-types.c +++ b/clang/test/CodeGen/AArch64/mixed-neon-types.c @@ -3,23 +3,23 @@ // RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -x c++ %s -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-CPP // REQUIRES: aarch64-registered-target -typedef __Uint32x4_t X; +typedef __Uint8x16_t X; -// CHECK-C-LABEL: define dso_local <4 x i32> @test( -// CHECK-C-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-C-LABEL: define dso_local <16 x i8> @test( +// CHECK-C-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-C-NEXT: [[ENTRY:.*:]] -// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 -// CHECK-C-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 -// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-C-NEXT: ret <4 x i32> [[TMP0]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP0]] // -// CHECK-CPP-LABEL: define dso_local noundef <4 x i32> @_Z4test12__Uint32x4_t( -// CHECK-CPP-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z4test12__Uint8x16_t( +// CHECK-CPP-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-CPP-NEXT: [[ENTRY:.*:]] -// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 -// CHECK-CPP-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 -// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-CPP-NEXT: ret <4 x i32> [[TMP0]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP0]] // X test(X x) { return x; @@ -28,47 +28,520 @@ X test(X x) { #include // CHECK-C-LABEL: define dso_local <16 x i8> @testboth( -// CHECK-C-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { // CHECK-C-NEXT: [[ENTRY:.*:]] // CHECK-C-NEXT: [[__P0_ADDR_I:%.*]] = alloca <16 x i8>, align 16 // CHECK-C-NEXT: [[__P1_ADDR_I:%.*]] = alloca <16 x i8>, align 16 // CHECK-C-NEXT: [[__RET_I:%.*]] = alloca <16 x i8>, align 16 -// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 -// CHECK-C-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 -// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-C-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8> -// CHECK-C-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-C-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[TMP2]] to <16 x i8> -// CHECK-C-NEXT: store <16 x i8> [[TMP1]], ptr [[__P0_ADDR_I]], align 16 -// CHECK-C-NEXT: store <16 x i8> [[TMP3]], ptr [[__P1_ADDR_I]], align 16 -// CHECK-C-NEXT: [[TMP4:%.*]] = load <16 x i8>, ptr [[__P0_ADDR_I]], align 16 -// CHECK-C-NEXT: [[TMP5:%.*]] = load <16 x i8>, ptr [[__P1_ADDR_I]], align 16 -// CHECK-C-NEXT: [[ADD_I:%.*]] = add <16 x i8> [[TMP4]], [[TMP5]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP1:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: store <16 x i8> [[TMP0]], ptr [[__P0_ADDR_I]], align 16 +// CHECK-C-NEXT: store <16 x i8> [[TMP1]], ptr [[__P1_ADDR_I]], align 16 +// CHECK-C-NEXT: [[TMP2:%.*]] = load <16 x i8>, ptr [[__P0_ADDR_I]], align 16 +// CHECK-C-NEXT: [[TMP3:%.*]] = load <16 x i8>, ptr [[__P1_ADDR_I]], align 16 +// CHECK-C-NEXT: [[ADD_I:%.*]] = add <16 x i8> [[TMP2]], [[TMP3]] // CHECK-C-NEXT: store <16 x i8> [[ADD_I]], ptr [[__RET_I]], align 16 -// CHECK-C-NEXT: [[TMP6:%.*]] = load <16 x i8>, ptr [[__RET_I]], align 16 -// CHECK-C-NEXT: ret <16 x i8> [[TMP6]] +// CHECK-C-NEXT: [[TMP4:%.*]] = load <16 x i8>, ptr [[__RET_I]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP4]] // -// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z8testboth12__Uint32x4_t( -// CHECK-CPP-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z8testboth12__Uint8x16_t( +// CHECK-CPP-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { // CHECK-CPP-NEXT: [[ENTRY:.*:]] // CHECK-CPP-NEXT: [[__P0_ADDR_I:%.*]] = alloca <16 x i8>, align 16 // CHECK-CPP-NEXT: [[__P1_ADDR_I:%.*]] = alloca <16 x i8>, align 16 // CHECK-CPP-NEXT: [[__RET_I:%.*]] = alloca <16 x i8>, align 16 -// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 -// CHECK-CPP-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 -// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-CPP-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8> -// CHECK-CPP-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 -// CHECK-CPP-NEXT: [[TMP3:%.*]] = bitcast <4 x i32> [[TMP2]] to <16 x i8> -// CHECK-CPP-NEXT: store <16 x i8> [[TMP1]], ptr [[__P0_ADDR_I]], align 16 -// CHECK-CPP-NEXT: store <16 x i8> [[TMP3]], ptr [[__P1_ADDR_I]], align 16 -// CHECK-CPP-NEXT: [[TMP4:%.*]] = load <16 x i8>, ptr [[__P0_ADDR_I]], align 16 -// CHECK-CPP-NEXT: [[TMP5:%.*]] = load <16 x i8>, ptr [[__P1_ADDR_I]], align 16 -// CHECK-CPP-NEXT: [[ADD_I:%.*]] = add <16 x i8> [[TMP4]], [[TMP5]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP1:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[TMP0]], ptr [[__P0_ADDR_I]], align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[TMP1]], ptr [[__P1_ADDR_I]], align 16 +// CHECK-CPP-NEXT: [[TMP2:%.*]] = load <16 x i8>, ptr [[__P0_ADDR_I]], align 16 +// CHECK-CPP-NEXT: [[TMP3:%.*]] = load <16 x i8>, ptr [[__P1_ADDR_I]], align 16 +// CHECK-CPP-NEXT: [[ADD_I:%.*]] = add <16 x i8> [[TMP2]], [[TMP3]] // CHECK-CPP-NEXT: store <16 x i8> [[ADD_I]], ptr [[__RET_I]], align 16 -// CHECK-CPP-NEXT: [[TMP6:%.*]] = load <16 x i8>, ptr [[__RET_I]], align 16 -// CHECK-CPP-NEXT: ret <16 x i8> [[TMP6]] +// CHECK-CPP-NEXT: [[TMP4:%.*]] = load <16 x i8>, ptr [[__RET_I]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP4]] // -int8x16_t testboth(X x) { +uint8x16_t testboth(X x) { return vaddq_u8(x, x); } + +// CHECK-C-LABEL: define dso_local <8 x i8> @test__Int8x8_t( +// CHECK-C-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-C-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <8 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i8> @_Z14test__Int8x8_t10__Int8x8_t( +// CHECK-CPP-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-CPP-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <8 x i8> [[TMP0]] +// +int8x8_t test__Int8x8_t(__Int8x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x i16> @test__Int16x4_t( +// CHECK-C-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-C-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <4 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x i16> @_Z15test__Int16x4_t11__Int16x4_t( +// CHECK-CPP-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-CPP-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <4 x i16> [[TMP0]] +// +int16x4_t test__Int16x4_t(__Int16x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x i32> @test__Int32x2_t( +// CHECK-C-SAME: <2 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x i32>, align 8 +// CHECK-C-NEXT: store <2 x i32> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <2 x i32> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x i32> @_Z15test__Int32x2_t11__Int32x2_t( +// CHECK-CPP-SAME: <2 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x i32>, align 8 +// CHECK-CPP-NEXT: store <2 x i32> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <2 x i32> [[TMP0]] +// +int32x2_t test__Int32x2_t(__Int32x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i8> @test__Uint8x8_t( +// CHECK-C-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-C-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <8 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i8> @_Z15test__Uint8x8_t11__Uint8x8_t( +// CHECK-CPP-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-CPP-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <8 x i8> [[TMP0]] +// +uint8x8_t test__Uint8x8_t(__Uint8x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x i16> @test__Uint16x4_t( +// CHECK-C-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-C-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <4 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x i16> @_Z16test__Uint16x4_t12__Uint16x4_t( +// CHECK-CPP-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-CPP-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <4 x i16> [[TMP0]] +// +uint16x4_t test__Uint16x4_t(__Uint16x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x i32> @test__Uint32x2_t( +// CHECK-C-SAME: <2 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x i32>, align 8 +// CHECK-C-NEXT: store <2 x i32> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <2 x i32> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x i32> @_Z16test__Uint32x2_t12__Uint32x2_t( +// CHECK-CPP-SAME: <2 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x i32>, align 8 +// CHECK-CPP-NEXT: store <2 x i32> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <2 x i32> [[TMP0]] +// +uint32x2_t test__Uint32x2_t(__Uint32x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x half> @test__Float16x4_t( +// CHECK-C-SAME: <4 x half> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x half>, align 8 +// CHECK-C-NEXT: store <4 x half> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x half>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <4 x half> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x half> @_Z17test__Float16x4_t13__Float16x4_t( +// CHECK-CPP-SAME: <4 x half> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x half>, align 8 +// CHECK-CPP-NEXT: store <4 x half> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x half>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <4 x half> [[TMP0]] +// +float16x4_t test__Float16x4_t(__Float16x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x float> @test__Float32x2_t( +// CHECK-C-SAME: <2 x float> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x float>, align 8 +// CHECK-C-NEXT: store <2 x float> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <2 x float> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x float> @_Z17test__Float32x2_t13__Float32x2_t( +// CHECK-CPP-SAME: <2 x float> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x float>, align 8 +// CHECK-CPP-NEXT: store <2 x float> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <2 x float> [[TMP0]] +// +float32x2_t test__Float32x2_t(__Float32x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i8> @test__Poly8x8_t( +// CHECK-C-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-C-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <8 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i8> @_Z15test__Poly8x8_t11__Poly8x8_t( +// CHECK-CPP-SAME: <8 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-CPP-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <8 x i8> [[TMP0]] +// +poly8x8_t test__Poly8x8_t(__Poly8x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x i16> @test__Poly16x4_t( +// CHECK-C-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-C-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <4 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x i16> @_Z16test__Poly16x4_t12__Poly16x4_t( +// CHECK-CPP-SAME: <4 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i16>, align 8 +// CHECK-CPP-NEXT: store <4 x i16> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <4 x i16> [[TMP0]] +// +poly16x4_t test__Poly16x4_t(__Poly16x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x bfloat> @test__Bfloat16x4_t( +// CHECK-C-SAME: <4 x bfloat> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x bfloat>, align 8 +// CHECK-C-NEXT: store <4 x bfloat> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x bfloat>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <4 x bfloat> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x bfloat> @_Z18test__Bfloat16x4_t14__Bfloat16x4_t( +// CHECK-CPP-SAME: <4 x bfloat> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x bfloat>, align 8 +// CHECK-CPP-NEXT: store <4 x bfloat> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x bfloat>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <4 x bfloat> [[TMP0]] +// +bfloat16x4_t test__Bfloat16x4_t(__Bfloat16x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <16 x i8> @test__Int8x16_t( +// CHECK-C-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z15test__Int8x16_t11__Int8x16_t( +// CHECK-CPP-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test__Int8x16_t(__Int8x16_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i16> @test__Int16x8_t( +// CHECK-C-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-C-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <8 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i16> @_Z15test__Int16x8_t11__Int16x8_t( +// CHECK-CPP-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-CPP-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <8 x i16> [[TMP0]] +// +int16x8_t test__Int16x8_t(__Int16x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x i32> @test__Int32x4_t( +// CHECK-C-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-C-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <4 x i32> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x i32> @_Z15test__Int32x4_t11__Int32x4_t( +// CHECK-CPP-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-CPP-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <4 x i32> [[TMP0]] +// +int32x4_t test__Int32x4_t(__Int32x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x i64> @test__Int64x2_t( +// CHECK-C-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-C-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <2 x i64> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x i64> @_Z15test__Int64x2_t11__Int64x2_t( +// CHECK-CPP-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-CPP-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <2 x i64> [[TMP0]] +// +int64x2_t test__Int64x2_t(__Int64x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <16 x i8> @test__Uint8x16_t( +// CHECK-C-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z16test__Uint8x16_t12__Uint8x16_t( +// CHECK-CPP-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test__Uint8x16_t(__Uint8x16_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i16> @test__Uint16x8_t( +// CHECK-C-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-C-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <8 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i16> @_Z16test__Uint16x8_t12__Uint16x8_t( +// CHECK-CPP-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-CPP-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <8 x i16> [[TMP0]] +// +uint16x8_t test__Uint16x8_t(__Uint16x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x i32> @test__Uint32x4_t( +// CHECK-C-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-C-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <4 x i32> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x i32> @_Z16test__Uint32x4_t12__Uint32x4_t( +// CHECK-CPP-SAME: <4 x i32> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-CPP-NEXT: store <4 x i32> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <4 x i32> [[TMP0]] +// +uint32x4_t test__Uint32x4_t(__Uint32x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x i64> @test__Uint64x2_t( +// CHECK-C-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-C-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <2 x i64> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x i64> @_Z16test__Uint64x2_t12__Uint64x2_t( +// CHECK-CPP-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-CPP-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <2 x i64> [[TMP0]] +// +uint64x2_t test__Uint64x2_t(__Uint64x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x half> @test__Float16x8_t( +// CHECK-C-SAME: <8 x half> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x half>, align 16 +// CHECK-C-NEXT: store <8 x half> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x half>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <8 x half> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x half> @_Z17test__Float16x8_t13__Float16x8_t( +// CHECK-CPP-SAME: <8 x half> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x half>, align 16 +// CHECK-CPP-NEXT: store <8 x half> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x half>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <8 x half> [[TMP0]] +// +float16x8_t test__Float16x8_t(__Float16x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <4 x float> @test__Float32x4_t( +// CHECK-C-SAME: <4 x float> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-C-NEXT: store <4 x float> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <4 x float> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <4 x float> @_Z17test__Float32x4_t13__Float32x4_t( +// CHECK-CPP-SAME: <4 x float> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-CPP-NEXT: store <4 x float> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <4 x float> [[TMP0]] +// +float32x4_t test__Float32x4_t(__Float32x4_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x double> @test__Float64x2_t( +// CHECK-C-SAME: <2 x double> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-C-NEXT: store <2 x double> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <2 x double> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x double> @_Z17test__Float64x2_t13__Float64x2_t( +// CHECK-CPP-SAME: <2 x double> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-CPP-NEXT: store <2 x double> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <2 x double> [[TMP0]] +// +float64x2_t test__Float64x2_t(__Float64x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <16 x i8> @test__Poly8x16_t( +// CHECK-C-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <16 x i8> @_Z16test__Poly8x16_t12__Poly8x16_t( +// CHECK-CPP-SAME: <16 x i8> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP0]] +// +poly8x16_t test__Poly8x16_t(__Poly8x16_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i16> @test__Poly16x8_t( +// CHECK-C-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-C-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <8 x i16> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x i16> @_Z16test__Poly16x8_t12__Poly16x8_t( +// CHECK-CPP-SAME: <8 x i16> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-CPP-NEXT: store <8 x i16> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i16>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <8 x i16> [[TMP0]] +// +poly16x8_t test__Poly16x8_t(__Poly16x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <2 x i64> @test__Poly64x2_t( +// CHECK-C-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-C-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <2 x i64> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <2 x i64> @_Z16test__Poly64x2_t12__Poly64x2_t( +// CHECK-CPP-SAME: <2 x i64> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-CPP-NEXT: store <2 x i64> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <2 x i64> [[TMP0]] +// +poly64x2_t test__Poly64x2_t(__Poly64x2_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x bfloat> @test__Bfloat16x8_t( +// CHECK-C-SAME: <8 x bfloat> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x bfloat>, align 16 +// CHECK-C-NEXT: store <8 x bfloat> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <8 x bfloat> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local noundef <8 x bfloat> @_Z18test__Bfloat16x8_t14__Bfloat16x8_t( +// CHECK-CPP-SAME: <8 x bfloat> noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x bfloat>, align 16 +// CHECK-CPP-NEXT: store <8 x bfloat> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <8 x bfloat> [[TMP0]] +// +bfloat16x8_t test__Bfloat16x8_t(__Bfloat16x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <8 x i8> @test__Mfloat8x8_t( +// CHECK-C-SAME: <8 x i8> [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-C-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-C-NEXT: ret <8 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local <8 x i8> @_Z17test__Mfloat8x8_t13__Mfloat8x8_t( +// CHECK-CPP-SAME: <8 x i8> [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <8 x i8>, align 8 +// CHECK-CPP-NEXT: store <8 x i8> [[X]], ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[X_ADDR]], align 8 +// CHECK-CPP-NEXT: ret <8 x i8> [[TMP0]] +// +mfloat8x8_t test__Mfloat8x8_t(__Mfloat8x8_t x) { return x; } +// CHECK-C-LABEL: define dso_local <16 x i8> @test__Mfloat8x16_t( +// CHECK-C-SAME: <16 x i8> [[X:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-C-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-C-NEXT: ret <16 x i8> [[TMP0]] +// +// CHECK-CPP-LABEL: define dso_local <16 x i8> @_Z18test__Mfloat8x16_t14__Mfloat8x16_t( +// CHECK-CPP-SAME: <16 x i8> [[X:%.*]]) #[[ATTR0]] { +// CHECK-CPP-NEXT: [[ENTRY:.*:]] +// CHECK-CPP-NEXT: [[X_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-CPP-NEXT: store <16 x i8> [[X]], ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[X_ADDR]], align 16 +// CHECK-CPP-NEXT: ret <16 x i8> [[TMP0]] +// +mfloat8x16_t test__Mfloat8x16_t(__Mfloat8x16_t x) { return x; } diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp index a41f315340b57..b1232921df363 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/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 32469731d1140..41214f7cdce23 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 c4e7d86e7d536..8b97ce8f760cb 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 0ab387525f6a4..c302b2940bc67 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 f69613c4777f6..a63f0a59a34e7 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 14b3a99a6f0f5..fb99a750a6707 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 1b3c3f6c0f858..77e8122890ab7 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 e22da32dbfa84..cf98549c41af2 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 205866db3566c..4f1c00bef0760 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 b32264fd88e75..c9fa994e51b3a 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 3d53e46b48859..c50f1f731ffb2 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 c275ee9bb2f6f..476b9b59dc192 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 9bd602fa5d762..1e0228e17caf9 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 bcd9c361fda90..6ce6815a521a1 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/X86/cygwin-varargs.c b/clang/test/CodeGen/X86/cygwin-varargs.c new file mode 100644 index 0000000000000..4eea7d64bcb35 --- /dev/null +++ b/clang/test/CodeGen/X86/cygwin-varargs.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm < %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-cygwin -emit-llvm < %s | FileCheck %s + +struct foo { + int x; + float y; + char z; +}; +// CHECK: %[[STRUCT_FOO:.*]] = type { i32, float, i8 } + +void f(int a, ...) { + // CHECK-LABEL: define dso_local void @f + __builtin_va_list ap; + __builtin_va_start(ap, a); + // CHECK: %[[AP:.*]] = alloca ptr + // CHECK: call void @llvm.va_start + int b = __builtin_va_arg(ap, int); + // CHECK: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]] + // CHECK-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8 + // CHECK-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]] + double _Complex c = __builtin_va_arg(ap, double _Complex); + // CHECK: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]] + // CHECK-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8 + // CHECK-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]] + // CHECK-NEXT: load ptr, ptr %[[AP_CUR2]] + struct foo d = __builtin_va_arg(ap, struct foo); + // CHECK: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]] + // CHECK-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8 + // CHECK-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]] + __builtin_va_list ap2; + __builtin_va_copy(ap2, ap); + // CHECK: call void @llvm.va_copy + __builtin_va_end(ap); + // CHECK: call void @llvm.va_end +} 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 0000000000000..27c3983c66d2b --- /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 bc4167adf53f6..9403c55beae0b 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/attr-arm-sve-vector-bits-cast.c b/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c index e1e2220f94d6d..fcd4314249ff8 100644 --- a/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c +++ b/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c @@ -62,10 +62,7 @@ fixed_bool_t from_svbool_t(svbool_t type) { // CHECK-LABEL: @lax_cast( // CHECK-NEXT: entry: -// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <16 x i32>, align 64 -// CHECK-NEXT: [[TYPE:%.*]] = tail call <16 x i32> @llvm.vector.extract.v16i32.nxv4i32( [[TYPE_COERCE:%.*]], i64 0) -// CHECK-NEXT: store <16 x i32> [[TYPE]], ptr [[SAVED_VALUE]], align 64, !tbaa [[TBAA6:![0-9]+]] -// CHECK-NEXT: [[TMP0:%.*]] = load , ptr [[SAVED_VALUE]], align 64, !tbaa [[TBAA6]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[TYPE_COERCE:%.*]] to // CHECK-NEXT: ret [[TMP0]] // svint64_t lax_cast(fixed_int32_t type) { @@ -74,9 +71,9 @@ svint64_t lax_cast(fixed_int32_t type) { // CHECK-LABEL: @to_svint32_t__from_gnu_int32_t( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TYPE:%.*]] = load <16 x i32>, ptr [[TMP0:%.*]], align 16, !tbaa [[TBAA6]] -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TYPE]], i64 0) -// CHECK-NEXT: ret [[CASTSCALABLESVE]] +// CHECK-NEXT: [[TYPE:%.*]] = load <16 x i32>, ptr [[TMP0:%.*]], align 16, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TYPE]], i64 0) +// CHECK-NEXT: ret [[CAST_SCALABLE]] // svint32_t to_svint32_t__from_gnu_int32_t(gnu_int32_t type) { return type; @@ -84,8 +81,8 @@ svint32_t to_svint32_t__from_gnu_int32_t(gnu_int32_t type) { // CHECK-LABEL: @from_svint32_t__to_gnu_int32_t( // CHECK-NEXT: entry: -// CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = tail call <16 x i32> @llvm.vector.extract.v16i32.nxv4i32( [[TYPE:%.*]], i64 0) -// CHECK-NEXT: store <16 x i32> [[CASTFIXEDSVE]], ptr [[AGG_RESULT:%.*]], align 16, !tbaa [[TBAA6]] +// CHECK-NEXT: [[CAST_FIXED:%.*]] = tail call <16 x i32> @llvm.vector.extract.v16i32.nxv4i32( [[TYPE:%.*]], i64 0) +// CHECK-NEXT: store <16 x i32> [[CAST_FIXED]], ptr [[AGG_RESULT:%.*]], align 16, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // gnu_int32_t from_svint32_t__to_gnu_int32_t(svint32_t type) { @@ -94,9 +91,9 @@ gnu_int32_t from_svint32_t__to_gnu_int32_t(svint32_t type) { // CHECK-LABEL: @to_fixed_int32_t__from_gnu_int32_t( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TYPE:%.*]] = load <16 x i32>, ptr [[TMP0:%.*]], align 16, !tbaa [[TBAA6]] -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TYPE]], i64 0) -// CHECK-NEXT: ret [[CASTSCALABLESVE]] +// CHECK-NEXT: [[TYPE:%.*]] = load <16 x i32>, ptr [[TMP0:%.*]], align 16, !tbaa [[TBAA2]] +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TYPE]], i64 0) +// CHECK-NEXT: ret [[CAST_SCALABLE]] // fixed_int32_t to_fixed_int32_t__from_gnu_int32_t(gnu_int32_t type) { return type; @@ -105,7 +102,7 @@ fixed_int32_t to_fixed_int32_t__from_gnu_int32_t(gnu_int32_t type) { // CHECK-LABEL: @from_fixed_int32_t__to_gnu_int32_t( // CHECK-NEXT: entry: // CHECK-NEXT: [[TYPE:%.*]] = tail call <16 x i32> @llvm.vector.extract.v16i32.nxv4i32( [[TYPE_COERCE:%.*]], i64 0) -// CHECK-NEXT: store <16 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 16, !tbaa [[TBAA6]] +// CHECK-NEXT: store <16 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 16, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // gnu_int32_t from_fixed_int32_t__to_gnu_int32_t(fixed_int32_t type) { 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 0000000000000..6497a58292362 --- /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 fa7e20e7f5279..c7c2bb95017a2 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 991ff09fb37cf..b2f7497b455b6 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/debug-info-coff.cpp b/clang/test/CodeGenCXX/debug-info-coff.cpp new file mode 100644 index 0000000000000..2535c5cc7511f --- /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 10fb1750f2c55..ff2dfc19961c0 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 48a61f7fb1977..e31c762b08872 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/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl index c3204570d6ef3..aaa486eff10b7 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 29ea896045bb1..42a469ae87957 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 eb7d755bca61d..bccfaf597f0ed 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 371f31c9e4afc..c30c640519cda 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 1f45a7f9b46d3..d0ba8f447b732 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 fb0f32b11241d..21328c1f9d4df 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 35d8b9dac801d..d5054a5a92b5d 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 9090e9e85ed98..afda714106fac 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/basic_types.hlsl b/clang/test/CodeGenHLSL/basic_types.hlsl index 362042654ea8c..37fb5195e9768 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 e1832bdbbf33f..8457ad6da293f 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 403d473ce9680..3a8d2c03e173c 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 9d95d54852c0b..114230d38ba54 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 e74a7ed270b01..114468914e2ea 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 8a3958ad8fd04..7804239edccae 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 fc7b6be5c9000..28841732df99e 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/abs.hlsl b/clang/test/CodeGenHLSL/builtins/abs.hlsl index e8a6ee0449571..6abe2f816c844 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 39f364c5953d6..391fad0ef33f5 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 b77889cd9ae70..d2ca7cf4163ed 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 3d9d8e9e689ed..e4837876e2693 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 b313c99e89a53..bdefe46b802e7 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 fe0b8f8983838..1a9c630b60e57 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 c0e1e914831aa..eaedfb419c195 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 d01c2a45c43c8..58db4423799be 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 c864f93af472b..aaeb2f026449b 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 5a1753766a8a1..e067828c38bf6 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 b7b11b1c3bd6d..70926cc8ba743 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 5f993d50498bf..79f9e1e6fbec2 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 b2a1d6316787d..89ac383e2517f 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 bafd2368c9961..a1abf435ea10c 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 64531dd2785eb..f0fb12855e5f6 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 ac38cf1853799..0c24fbb9f1859 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 858a1210169d2..df34beeba7a8c 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 6ed40ed8f433c..5a8f60528a84c 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 ef522afc244a8..20482777a18de 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 b067427e46368..a9bbcb0d9bff9 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 debf6b6d3e3f5..a71b1878f8b55 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 5d490fabc5bc8..007db0c9c2ad5 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 26d83443ea489..1e413e53f333e 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 f610baeeefd48..b3ff58317981a 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 7ecc5854b3988..cc91c0b67f6cc 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 b0e844bd8a8d8..7a3f7b0069480 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 7b105ce84359f..d8397407cd013 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 6d2ae6535ecb3..24114b11c7602 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 ace209003ce43..f39cba9ace6e3 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 df44fc4a91dfd..4d53daaafb692 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 ea0d1348c6e4e..f8fa06c39f2a1 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 0b17d03d7097d..9297c35abfd16 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 3cb14f8555cab..3b13e43873c77 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 5c63d630c3f3c..d7aacdc486ac6 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 e489939594a53..0136c1a052ed4 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 1a0539c3517d5..e408f4a5d45ce 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 37c8e837c45a3..6a75444143b18 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 c35b50d8e490a..f88d5ab849212 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 5159d5bb0fa4e..84d73c1810890 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 d952398a6a592..cd7013ba75825 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 0b767335556ee..fab53a160c856 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 5c200f488c246..f81fa128ce9c7 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 508d8b68ea452..b3e8fedff9b1b 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 e9baa25fc6409..52ff7da94c4f7 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 830fc26b7acf0..cc2378756a50a 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 69c57c5455f7d..66cc5572a75b5 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 39003aef7b7b5..0d1f3d3546a33 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 fd21f1b94c57e..fcde755e15fcc 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 d0cfc7b60265b..4b12f590edcd6 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 efdeb9f6e142a..f281747fbf298 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 8f07f3a031531..cdfaa3c5f1ee3 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 c082e63ac1da6..65fefd801ffed 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 fe137b9cae4e9..91375c8f4eb8f 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 109633a64d34e..3b07fcec064d8 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 a945a9677abbb..755f2e86fb116 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 09f21f366b9d2..262f306b92572 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 6c9b1f643713b..9c398fd6f06cb 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 8cc910933f462..cbdb929388934 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 a5522e4f28b7f..e471cb3d42c5c 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 69c657239ef95..9bbe97997aa33 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 d3e5c1059029c..bef64ce77d470 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 a883c9d5cc355..aeb2b79e90291 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 48b74c9db5c64..d4de244f38b3e 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 94d966f0bef8a..31839f6bc177d 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 d3b979254391c..f55a8f8aff92d 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 49d09e5c6fe6f..be0ffbd794646 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 d913aabfb4066..51eb20c58e405 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 26de5bf94c3cc..c1c6ee4119f0d 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 3ab8048146ad3..0df3598a3cc3e 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 8e1f2d69e7432..9034cae254036 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 12b120d0c067d..a71b988417f09 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 eebf0f682d3de..b58a49b41eb98 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 4a7e2597dc0ff..33f480bf445e5 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 0d092f0c36c29..16d22a5b1fdd4 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 a6034386ac450..cda231d8d2ebb 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 934fe3ea9eb7a..9aabbfd54e539 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 363c6a48839b5..b7b11e9959ea8 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 570b4b1336717..32579e8631001 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 557913042e884..ad4d92f8afc02 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 40e3196649a50..1b2cb0e99aa83 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 770618ff2e070..e72dbde5188a9 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 4b2e2beba4f12..6498c53752d4e 100644 --- a/clang/test/CodeGenHLSL/group_shared.hlsl +++ b/clang/test/CodeGenHLSL/group_shared.hlsl @@ -3,8 +3,12 @@ // RUN: dxil-pc-shadermodel6.3-library %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan1.3-compute %s \ +// 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 12d3eeedb590f..60238cbf8eff5 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 4748eeee7475f..0c7467e2f972e 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/inline-spirv/SpirvType.hlsl b/clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl index 5b58e436bbedb..7149be0122f4d 100644 --- a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl +++ b/clang/test/CodeGenHLSL/inline-spirv/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/no_int_promotion.hlsl b/clang/test/CodeGenHLSL/no_int_promotion.hlsl index 78bff3b13810d..b4ffcb477f1ba 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 8127a6c2ec1e4..57f6c123e50e5 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 new file mode 100644 index 0000000000000..58b91fc9264dd --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -0,0 +1,10 @@ +// 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: define void @main() {{.*}} { +float4 main(float4 p : SV_Position) { + // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @sv_position, align 16 + // CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]]) + return p; +} diff --git a/clang/test/CodeGenHLSL/shift-mask.hlsl b/clang/test/CodeGenHLSL/shift-mask.hlsl index 7b3890ae560d2..41e05330ed1a5 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 a87eb0b38f603..a2df307038774 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/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl index 1cc7963c0e289..157a1818c82ff 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/Driver/android-link.cpp b/clang/test/Driver/android-link.cpp index ab7dae5405587..b103263cdd3f0 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 0535285862b9f..eb079895a0a88 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 0000000000000..84603aec1d2f5 --- /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/dxc_spirv.hlsl b/clang/test/Driver/dxc_spirv.hlsl index e6624e5f1b3f6..65c9018dc54c5 100644 --- a/clang/test/Driver/dxc_spirv.hlsl +++ b/clang/test/Driver/dxc_spirv.hlsl @@ -3,7 +3,7 @@ // RUN: %clang_dxc -T cs_6_0 -spirv -fspv-target-env=vulkan1.3 -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-VULKAN13 // RUN: not %clang_dxc -T cs_6_0 -spirv -fspv-target-env=vulkan1.0 -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR -// CHECK: "-triple" "spirv-unknown-vulkan-compute" +// CHECK: "-triple" "spirv1.6-unknown-vulkan1.3-compute" // CHECK-SAME: "-x" "hlsl" // CHECK-VULKAN12: "-triple" "spirv1.5-unknown-vulkan1.2-compute" diff --git a/clang/test/Driver/fveclib.c b/clang/test/Driver/fveclib.c index 5420555c36a2a..c57e9aa7a3cc2 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 57e57194ec87b..d8b3f1e242018 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-phases.hip b/clang/test/Driver/hip-phases.hip index 5fd2c0216ccc3..d8a58b78d6d5c 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]]) - -// 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: [[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]]) + +// 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-toolchain-no-rdc.hip b/clang/test/Driver/hip-toolchain-no-rdc.hip index 6c69d1d51a260..ddd251b67cc57 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 0000000000000..a3597dc0fe0d4 --- /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 a7e98e7351d98..80b1a5745a123 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/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index 95464f06378e2..5008c2b7f789d 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 da5748d7c723c..30140f3c208e0 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/stack-alignment.c b/clang/test/Driver/stack-alignment.c new file mode 100644 index 0000000000000..e1e62c05c32ab --- /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/FixIt/fixit-punctuator-spelling.cpp b/clang/test/FixIt/fixit-punctuator-spelling.cpp new file mode 100644 index 0000000000000..3cba0e7b64594 --- /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 0000000000000..7dff510f5ddf0 --- /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 e489fbbcaa1df..0000000000000 --- 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 1aa9c9f3e2fad..7cb835d39f23e 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 66b984e037b3c..f42492e43f84b 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 new file mode 100644 index 0000000000000..d761e12e8392e --- /dev/null +++ b/clang/test/Frontend/aarch64-print-enabled-extensions-cc1.c @@ -0,0 +1,139 @@ +// Test how -cc1 -target-feature interacts with -print-enabled-extensions. +// The current behaviour does not look correct, since dependent features are +// removed from the printed list when one of their dependencies are disabled, +// but they are actually still enabled during compilation, and then actually +// disabled for parsing assembly. + +// REQUIRES: aarch64-registered-target + +// Behaviour with two positive features. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon -target-feature +sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=POS_ONLY + +// Negative -target-feature disables the extension but keeps any dependencies of it (FEAT_FP16). +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon -target-feature +sve -target-feature -sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=POS_NEG + +// Disabling then re-enabling a feature is the same as never disabling it. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon -target-feature -sve -target-feature +sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=POS_ONLY + +// Disabling then re-enabling a feature is the same as never disabling it. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon -target-feature +sve -target-feature -sve -target-feature +sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=POS_ONLY + +// Only disabling it is the same as never having enabled it. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=NEG_ONLY + +// Only disabling it is the same as never having enabled it. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +neon -target-feature -sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=NEG_ONLY + +// Disabling a dependency (after enabling the dependent) appears to disable the dependent feature. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +sve2 -target-feature -sve \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=DISABLE_DEP + +// Disabling a dependency before enabling the dependent appears to have no effect. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature -sve -target-feature +sve2 \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=DISABLE_DEP2 + +// Disabling a dependency before enabling the dependent appears to have no effect. +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -print-enabled-extensions \ +// RUN: -target-feature +sve2 \ +// RUN: | FileCheck --strict-whitespace --implicit-check-not=FEAT_ %s --check-prefix=DISABLE_DEP2 + +// Driver --print-enabled-extensions indicates that negative -target-features disable dependent features. +// RUN: %clang --target=aarch64 -march=armv8-a+sve2 --print-enabled-extensions \ +// RUN: -Xclang -target-feature -Xclang -sve \ +// 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 -o %t \ +// RUN: -Xclang -target-feature -Xclang -sve \ +// RUN: -Xclang -verify -Xclang -verify-ignore-unexpected=note + + +// POS_ONLY: Extensions enabled for the given AArch64 target +// POS_ONLY-EMPTY: +// POS_ONLY-NEXT: Architecture Feature(s) Description +// POS_ONLY-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// POS_ONLY-NEXT: FEAT_ETE Enable Embedded Trace Extension +// POS_ONLY-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// POS_ONLY-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// POS_ONLY-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions +// POS_ONLY-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// POS_NEG: Extensions enabled for the given AArch64 target +// POS_NEG-EMPTY: +// POS_NEG-NEXT: Architecture Feature(s) Description +// POS_NEG-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// POS_NEG-NEXT: FEAT_ETE Enable Embedded Trace Extension +// POS_NEG-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// POS_NEG-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// POS_NEG-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// NEG_POS: Extensions enabled for the given AArch64 target +// NEG_POS-EMPTY: +// NEG_POS-NEXT: Architecture Feature(s) Description +// NEG_POS-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// NEG_POS-NEXT: FEAT_ETE Enable Embedded Trace Extension +// NEG_POS-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// NEG_POS-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// NEG_POS-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions +// NEG_POS-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// NEG_ONLY: Extensions enabled for the given AArch64 target +// NEG_ONLY-EMPTY: +// NEG_ONLY-NEXT: Architecture Feature(s) Description +// NEG_ONLY-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// NEG_ONLY-NEXT: FEAT_ETE Enable Embedded Trace Extension +// NEG_ONLY-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// NEG_ONLY-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// DISABLE_DEP: Extensions enabled for the given AArch64 target +// DISABLE_DEP-EMPTY: +// DISABLE_DEP-NEXT: Architecture Feature(s) Description +// DISABLE_DEP-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// DISABLE_DEP-NEXT: FEAT_ETE Enable Embedded Trace Extension +// DISABLE_DEP-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// DISABLE_DEP-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// DISABLE_DEP-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// DISABLE_DEP2: Extensions enabled for the given AArch64 target +// DISABLE_DEP2-EMPTY: +// DISABLE_DEP2-NEXT: Architecture Feature(s) Description +// DISABLE_DEP2-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// DISABLE_DEP2-NEXT: FEAT_ETE Enable Embedded Trace Extension +// DISABLE_DEP2-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// DISABLE_DEP2-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// DISABLE_DEP2-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions +// DISABLE_DEP2-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions +// DISABLE_DEP2-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +// DISABLE_VIA_XCLANG: Extensions enabled for the given AArch64 target +// DISABLE_VIA_XCLANG-EMPTY: +// DISABLE_VIA_XCLANG-NEXT: Architecture Feature(s) Description +// DISABLE_VIA_XCLANG-NEXT: FEAT_AdvSIMD Enable Advanced SIMD instructions +// DISABLE_VIA_XCLANG-NEXT: FEAT_ETE Enable Embedded Trace Extension +// DISABLE_VIA_XCLANG-NEXT: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// DISABLE_VIA_XCLANG-NEXT: FEAT_FP16 Enable half-precision floating-point data processing +// DISABLE_VIA_XCLANG-NEXT: FEAT_TRBE Enable Trace Buffer Extension + +#if __ARM_FEATURE_SVE2 +#warning "SVE2 is enabled" +// expected-warning@-1 {{SVE2 is enabled}} +#endif + +void fn_that_requires_sve2() { + __asm__("ldnt1sh z0.s, p0/z, [z1.s]"); + // expected-error@-1 {{instruction requires: sve2}} +} diff --git a/clang/test/Frontend/ast-main.c b/clang/test/Frontend/ast-main.c index cdc74219f73ac..6a64497f4109c 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 fe47ce435f068..fc09e6437f93f 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 4a78854595543..0000000000000 --- 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 1e710c28afcca..8378fd9da9b43 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 de318b616df70..8ed96e5c19f0d 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/target-invalid-cpu-note/avr.c b/clang/test/Misc/target-invalid-cpu-note/avr.c index 86ffbb6838582..49d68bcc2edf8 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/Modules/constexpr-initialization-failure.cpp b/clang/test/Modules/constexpr-initialization-failure.cpp new file mode 100644 index 0000000000000..8ff20f2fc8ac6 --- /dev/null +++ b/clang/test/Modules/constexpr-initialization-failure.cpp @@ -0,0 +1,44 @@ +// 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 + +template struct A { + union { + struct { + T x, y, z; + }; + }; + constexpr A(T, T, T) : x(), y(), z() {} +}; +typedef A packed_vec3; + +//--- h1.h +// expected-no-diagnostics +#pragma once + +#include "h0.h" + +constexpr packed_vec3 kMessThingsUp = packed_vec3(5.0f, 5.0f, 5.0f); + +//--- main.cpp +// expected-no-diagnostics +#include "h0.h" + +static_assert(sizeof(packed_vec3) == sizeof(float) * 3); +static_assert(alignof(packed_vec3) == sizeof(float)); + +import "h1.h"; + +constexpr packed_vec3 kDefaultHalfExtents = packed_vec3(5.0f, 5.0f, 5.0f); diff --git a/clang/test/Modules/diagnose-missing-import.m b/clang/test/Modules/diagnose-missing-import.m index 8fb8e6b25f68a..b34bc1a62b6bc 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/module-local-declarations-02.cppm b/clang/test/Modules/module-local-declarations-02.cppm new file mode 100644 index 0000000000000..0670c4295abc7 --- /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 0000000000000..4fbcf09e4d792 --- /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/pr119947.cppm b/clang/test/Modules/pr119947.cppm new file mode 100644 index 0000000000000..40de2cad3c0d7 --- /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/pr143788.cppm b/clang/test/Modules/pr143788.cppm new file mode 100644 index 0000000000000..5ae36d8d0e85a --- /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/pr61360.cppm b/clang/test/Modules/pr61360.cppm new file mode 100644 index 0000000000000..a16f65d4be2fe --- /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 0000000000000..b1f1e3579f31e --- /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/OpenMP/begin_declare_variant_messages.c b/clang/test/OpenMP/begin_declare_variant_messages.c index d8d8f4211678f..8878188e7ceb2 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 3c554a106fe49..bb83f23a0c18a 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 422fa9981672e..9ca3412e3e3d9 100644 --- a/clang/test/OpenMP/declare_mapper_ast_print.cpp +++ b/clang/test/OpenMP/declare_mapper_ast_print.cpp @@ -34,6 +34,28 @@ class vecchild : public vec { // 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 752cc4fb05a12..f91d952dfa14f 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 172dd1670421d..c14e19cc8b7ec 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 284e49bbd21b4..aadded7699ea1 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 32e365cc415bd..d1e36e5d1e7e9 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 8eb37bc64cbc1..06da8a8e5b058 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/distribute_simd_misc_messages.c b/clang/test/OpenMP/distribute_simd_misc_messages.c index 8cbf96cd7a014..270e17dcb89bb 100644 --- a/clang/test/OpenMP/distribute_simd_misc_messages.c +++ b/clang/test/OpenMP/distribute_simd_misc_messages.c @@ -508,6 +508,7 @@ void test_collapse(void) { #pragma omp distribute simd collapse(5 - 5) for (i = 0; i < 16; ++i) ; +#if defined(_OPENMP) && (_OPENMP <= 202111) // expected-note@+3 2 {{defined as reduction}} #pragma omp target #pragma omp teams @@ -520,7 +521,7 @@ void test_collapse(void) { #pragma omp for reduction(+ : i, j) for (int k = 0; k < 16; ++k) i += j; - +#endif #pragma omp target #pragma omp teams for (i = 0; i < 16; ++i) diff --git a/clang/test/OpenMP/for_private_reduction_codegen.cpp b/clang/test/OpenMP/for_private_reduction_codegen.cpp new file mode 100644 index 0000000000000..c8a6863299fb3 --- /dev/null +++ b/clang/test/OpenMP/for_private_reduction_codegen.cpp @@ -0,0 +1,710 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs --replace-value-regex "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ --global-value-regex ".omp.reduction..internal[a-zA-Z_0-9.]+" +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -fopenmp-version=60 -x c++ -std=c++17 -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics +#define N 10 +class Sum { + int val; + +public: + Sum(int v = 0) : val(v) {} + Sum operator+(const Sum &rhs) const { return Sum(val + rhs.val); } + Sum &operator+=(const Sum &rhs) { + val += rhs.val; + return *this; + } +}; +#pragma omp declare reduction(sum_reduction:Sum : omp_out += omp_in) \ + initializer(omp_priv = Sum(0)) + +void func_red() { + Sum result(0); + Sum array[N]; + + for (int i = 0; i < N; i++) { + array[i] = Sum(i); + } + +#pragma omp parallel private(result) num_threads(4) + { +#pragma omp for reduction(sum_reduction : result) + for (int i = 0; i < N; i++) { + result = result + array[i]; + } + } +} + +void do_red(int n, int *v, int &sum_v) { + sum_v = 0; +#pragma omp for reduction(original(private), + : sum_v) + for (int i = 0; i < n; i++) { + sum_v += v[i]; + } +} +void do_red_extended(int n, int *v, int &sum_v, int &prod_v) { + sum_v = 0; + prod_v = 1; + +#pragma omp for reduction(original(private), + : sum_v) \ + reduction(original(private), * : prod_v) + for (int i = 0; i < n; i++) { + sum_v += v[i]; + prod_v *= v[i]; + } +} +int main(void) { + int v[N]; + for (int i = 0; i < N; i++) + v[i] = i; +#pragma omp parallel num_threads(4) + { + int s_v; + do_red(N, v, s_v); + } + + int sum_v_ext = 0, prod_v_ext = 1; +#pragma omp parallel num_threads(4) + { + do_red_extended(N, v, sum_v_ext, prod_v_ext); + } + return 0; +} + +//. +// CHECK: @.omp.reduction..internal_pivate_.result.result_996 = common global %class.Sum zeroinitializer, align 4 +// CHECK: @.omp.reduction..internal_pivate_.sum_v.sum_v_1188 = common global i32 0, align 4 +// CHECK: @.omp.reduction..internal_pivate_.sum_v.sum_v_1392 = common global i32 0, align 4 +// CHECK: @.omp.reduction..internal_pivate_.prod_v.prod_v_1461 = common global i32 0, align 4 +//. +// CHECK-LABEL: define {{[^@]+}}@_Z8func_redv +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RESULT:%.*]] = alloca [[CLASS_SUM:%.*]], align 4 +// CHECK-NEXT: [[ARRAY:%.*]] = alloca [10 x %class.Sum], align 16 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_SUM]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3:[0-9]+]]) +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[RESULT]], i32 noundef 0) +// CHECK-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x %class.Sum], ptr [[ARRAY]], i32 0, i32 0 +// CHECK-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[CLASS_SUM]], ptr [[ARRAY_BEGIN]], i64 10 +// CHECK-NEXT: br label [[ARRAYCTOR_LOOP:%.*]] +// CHECK: arrayctor.loop: +// CHECK-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ] +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]], i32 noundef 0) +// CHECK-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[CLASS_SUM]], ptr [[ARRAYCTOR_CUR]], i64 1 +// CHECK-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]] +// CHECK-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]] +// CHECK: arrayctor.cont: +// CHECK-NEXT: store i32 0, ptr [[I]], align 4 +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP1]], 10 +// CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[REF_TMP]], i32 noundef [[TMP2]]) +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP3]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x %class.Sum], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX]], ptr align 4 [[REF_TMP]], i64 4, i1 false) +// CHECK-NEXT: br label [[FOR_INC:%.*]] +// CHECK: for.inc: +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP4]], 1 +// CHECK-NEXT: store i32 [[INC]], ptr [[I]], align 4 +// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK: for.end: +// CHECK-NEXT: call void @__kmpc_push_num_threads(ptr @[[GLOB3]], i32 [[TMP0]], i32 4) +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 1, ptr @_Z8func_redv.omp_outlined, ptr [[ARRAY]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_ZN3SumC1Ei +// CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[V:%.*]]) unnamed_addr #[[ATTR0]] comdat align 2 { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[V_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store i32 [[V]], ptr [[V_ADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[V_ADDR]], align 4 +// CHECK-NEXT: call void @_ZN3SumC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z8func_redv.omp_outlined +// CHECK-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[ARRAY:%.*]]) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ARRAY_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[RESULT:%.*]] = alloca [[CLASS_SUM:%.*]], align 4 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[RESULT1:%.*]] = alloca [[CLASS_SUM]], align 4 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_SUM]], align 4 +// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [0 x ptr], align 8 +// CHECK-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK-NEXT: store ptr [[ARRAY]], ptr [[ARRAY_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAY_ADDR]], align 8 +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[RESULT]], i32 noundef 0) +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: store i32 9, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 +// CHECK-NEXT: call void @.omp_initializer.(ptr noundef [[RESULT1]], ptr noundef [[RESULT]]) +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4 +// CHECK-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP2]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP3]], 9 +// CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i32 [ 9, [[COND_TRUE]] ], [ [[TMP4]], [[COND_FALSE]] ] +// CHECK-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]] +// CHECK-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]] +// CHECK: omp.inner.for.body: +// CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] +// CHECK-NEXT: store i32 [[ADD]], ptr [[I]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x %class.Sum], ptr [[TMP0]], i64 0, i64 [[IDXPROM]] +// CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZNK3SumplERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[RESULT1]], ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYIDX]]) +// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[CLASS_SUM]], ptr [[REF_TMP]], i32 0, i32 0 +// CHECK-NEXT: store i32 [[CALL]], ptr [[COERCE_DIVE]], align 4 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RESULT1]], ptr align 4 [[REF_TMP]], i64 4, i1 false) +// CHECK-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] +// CHECK: omp.body.continue: +// CHECK-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] +// CHECK: omp.inner.for.inc: +// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1 +// CHECK-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND]] +// CHECK: omp.inner.for.end: +// CHECK-NEXT: br label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]]) +// CHECK-NEXT: [[TMP11:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 0, i64 0, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z8func_redv.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: switch i32 [[TMP11]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [ +// CHECK-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]] +// CHECK-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]] +// CHECK-NEXT: ] +// CHECK: .omp.reduction.case1: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.case2: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.default: +// CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP2]], 0 +// CHECK-NEXT: br i1 [[TMP12]], label [[INIT:%.*]], label [[INIT_END:%.*]] +// CHECK: init: +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @.omp.reduction..internal_pivate_.result.result_996, i32 noundef 0) +// CHECK-NEXT: br label [[INIT_END]] +// CHECK: init.end: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @.omp_combiner.(ptr noundef @.omp.reduction..internal_pivate_.result.result_996, ptr noundef [[RESULT1]]) +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) +// CHECK-NEXT: [[TMP13:%.*]] = load [[CLASS_SUM]], ptr @.omp.reduction..internal_pivate_.result.result_996, align 4 +// CHECK-NEXT: store [[CLASS_SUM]] [[TMP13]], ptr [[RESULT1]], align 4 +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @.omp_combiner.(ptr noundef [[RESULT]], ptr noundef [[RESULT1]]) +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4:[0-9]+]], i32 [[TMP2]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@.omp_combiner. +// CHECK-SAME: (ptr noalias noundef [[TMP0:%.*]], ptr noalias noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-NEXT: [[CALL:%.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_ZN3SumpLERKS_(ptr noundef nonnull align 4 dereferenceable(4) [[TMP3]], ptr noundef nonnull align 4 dereferenceable(4) [[TMP2]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_ZN3SumpLERKS_ +// CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[RHS:%.*]]) #[[ATTR0]] comdat align 2 { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[RHS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store ptr [[RHS]], ptr [[RHS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[RHS_ADDR]], align 8 +// CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw [[CLASS_SUM:%.*]], ptr [[TMP0]], i32 0, i32 0 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[VAL]], align 4 +// CHECK-NEXT: [[VAL2:%.*]] = getelementptr inbounds nuw [[CLASS_SUM]], ptr [[THIS1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VAL2]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[ADD]], ptr [[VAL2]], align 4 +// CHECK-NEXT: ret ptr [[THIS1]] +// +// +// CHECK-LABEL: define {{[^@]+}}@.omp_initializer. +// CHECK-SAME: (ptr noalias noundef [[TMP0:%.*]], ptr noalias noundef [[TMP1:%.*]]) #[[ATTR3]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[TMP3]], i32 noundef 0) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_ZNK3SumplERKS_ +// CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[RHS:%.*]]) #[[ATTR0]] comdat align 2 { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[CLASS_SUM:%.*]], align 4 +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[RHS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store ptr [[RHS]], ptr [[RHS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw [[CLASS_SUM]], ptr [[THIS1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[VAL]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[RHS_ADDR]], align 8 +// CHECK-NEXT: [[VAL2:%.*]] = getelementptr inbounds nuw [[CLASS_SUM]], ptr [[TMP1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VAL2]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP2]] +// CHECK-NEXT: call void @_ZN3SumC1Ei(ptr noundef nonnull align 4 dereferenceable(4) [[RETVAL]], i32 noundef [[ADD]]) +// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[CLASS_SUM]], ptr [[RETVAL]], i32 0, i32 0 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[COERCE_DIVE]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z8func_redv.omp_outlined.omp.reduction.reduction_func +// CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_ZN3SumC2Ei +// CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[V:%.*]]) unnamed_addr #[[ATTR0]] comdat align 2 { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[V_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store i32 [[V]], ptr [[V_ADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw [[CLASS_SUM:%.*]], ptr [[THIS1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[V_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[VAL]], align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z6do_rediPiRi +// CHECK-SAME: (i32 noundef [[N:%.*]], ptr noundef [[V:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[SUM_V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[V_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[SUM_V_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TMP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[_TMP1:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTCAPTURE_EXPR_2:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SUM_V4:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[_TMP5:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[I6:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [0 x ptr], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]]) +// CHECK-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4 +// CHECK-NEXT: store ptr [[V]], ptr [[V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[SUM_V]], ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: store i32 0, ptr [[TMP1]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP2]], ptr [[TMP]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[N_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP4]], 0 +// CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1 +// CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[DIV]], 1 +// CHECK-NEXT: store i32 [[SUB3]], ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK-NEXT: store i32 0, ptr [[I]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP5]] +// CHECK-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]] +// CHECK: omp.precond.then: +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP]], align 8 +// CHECK-NEXT: store i32 0, ptr [[SUM_V4]], align 4 +// CHECK-NEXT: store ptr [[SUM_V4]], ptr [[_TMP5]], align 8 +// CHECK-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1]], i32 [[TMP0]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK-NEXT: [[CMP7:%.*]] = icmp sgt i32 [[TMP8]], [[TMP9]] +// CHECK-NEXT: br i1 [[CMP7]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[TMP10]], [[COND_TRUE]] ], [ [[TMP11]], [[COND_FALSE]] ] +// CHECK-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: store i32 [[TMP12]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[CMP8:%.*]] = icmp sle i32 [[TMP13]], [[TMP14]] +// CHECK-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]] +// CHECK: omp.inner.for.body: +// CHECK-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] +// CHECK-NEXT: store i32 [[ADD]], ptr [[I6]], align 4 +// CHECK-NEXT: [[TMP16:%.*]] = load ptr, ptr [[V_ADDR]], align 8 +// CHECK-NEXT: [[TMP17:%.*]] = load i32, ptr [[I6]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP17]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP16]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP18:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP19:%.*]] = load ptr, ptr [[_TMP5]], align 8 +// CHECK-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4 +// CHECK-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP20]], [[TMP18]] +// CHECK-NEXT: store i32 [[ADD9]], ptr [[TMP19]], align 4 +// CHECK-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] +// CHECK: omp.body.continue: +// CHECK-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] +// CHECK: omp.inner.for.inc: +// CHECK-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP21]], 1 +// CHECK-NEXT: store i32 [[ADD10]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND]] +// CHECK: omp.inner.for.end: +// CHECK-NEXT: br label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP0]]) +// CHECK-NEXT: [[TMP22:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB2]], i32 [[TMP0]], i32 0, i64 0, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z6do_rediPiRi.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: switch i32 [[TMP22]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [ +// CHECK-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]] +// CHECK-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]] +// CHECK-NEXT: ] +// CHECK: .omp.reduction.case1: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.case2: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.default: +// CHECK-NEXT: [[TMP23:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NEXT: br i1 [[TMP23]], label [[INIT:%.*]], label [[INIT_END:%.*]] +// CHECK: init: +// CHECK-NEXT: store i32 0, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1188, align 4 +// CHECK-NEXT: br label [[INIT_END]] +// CHECK: init.end: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP24:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1188, align 4 +// CHECK-NEXT: [[TMP25:%.*]] = load i32, ptr [[SUM_V4]], align 4 +// CHECK-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP24]], [[TMP25]] +// CHECK-NEXT: store i32 [[ADD11]], ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1188, align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: [[TMP26:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1188, align 4 +// CHECK-NEXT: store i32 [[TMP26]], ptr [[SUM_V4]], align 4 +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP27:%.*]] = load i32, ptr [[TMP7]], align 4 +// CHECK-NEXT: [[TMP28:%.*]] = load i32, ptr [[SUM_V4]], align 4 +// CHECK-NEXT: [[ADD12:%.*]] = add nsw i32 [[TMP27]], [[TMP28]] +// CHECK-NEXT: store i32 [[ADD12]], ptr [[TMP7]], align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: br label [[OMP_PRECOND_END]] +// CHECK: omp.precond.end: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4]], i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z6do_rediPiRi.omp.reduction.reduction_func +// CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR5]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z15do_red_extendediPiRiS0_ +// CHECK-SAME: (i32 noundef [[N:%.*]], ptr noundef [[V:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[SUM_V:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[PROD_V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[V_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[SUM_V_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PROD_V_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[TMP:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[_TMP2:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SUM_V5:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[_TMP6:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[PROD_V7:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[_TMP8:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[I9:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [0 x ptr], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]]) +// CHECK-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4 +// CHECK-NEXT: store ptr [[V]], ptr [[V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[SUM_V]], ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[PROD_V]], ptr [[PROD_V_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: store i32 0, ptr [[TMP1]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PROD_V_ADDR]], align 8 +// CHECK-NEXT: store i32 1, ptr [[TMP2]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[SUM_V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP3]], ptr [[TMP]], align 8 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[PROD_V_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP4]], ptr [[_TMP1]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0 +// CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1 +// CHECK-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1 +// CHECK-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4 +// CHECK-NEXT: store i32 0, ptr [[I]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP7]] +// CHECK-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]] +// CHECK: omp.precond.then: +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4 +// CHECK-NEXT: store i32 [[TMP8]], ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 +// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[TMP]], align 8 +// CHECK-NEXT: store i32 0, ptr [[SUM_V5]], align 4 +// CHECK-NEXT: store ptr [[SUM_V5]], ptr [[_TMP6]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP1]], align 8 +// CHECK-NEXT: store i32 1, ptr [[PROD_V7]], align 4 +// CHECK-NEXT: store ptr [[PROD_V7]], ptr [[_TMP8]], align 8 +// CHECK-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1]], i32 [[TMP0]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4 +// CHECK-NEXT: [[CMP10:%.*]] = icmp sgt i32 [[TMP11]], [[TMP12]] +// CHECK-NEXT: br i1 [[CMP10]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +// CHECK: cond.true: +// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4 +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK: cond.false: +// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: br label [[COND_END]] +// CHECK: cond.end: +// CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[TMP13]], [[COND_TRUE]] ], [ [[TMP14]], [[COND_FALSE]] ] +// CHECK-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK-NEXT: store i32 [[TMP15]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: [[CMP11:%.*]] = icmp sle i32 [[TMP16]], [[TMP17]] +// CHECK-NEXT: br i1 [[CMP11]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]] +// CHECK: omp.inner.for.body: +// CHECK-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP18]], 1 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] +// CHECK-NEXT: store i32 [[ADD]], ptr [[I9]], align 4 +// CHECK-NEXT: [[TMP19:%.*]] = load ptr, ptr [[V_ADDR]], align 8 +// CHECK-NEXT: [[TMP20:%.*]] = load i32, ptr [[I9]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP19]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP22:%.*]] = load ptr, ptr [[_TMP6]], align 8 +// CHECK-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4 +// CHECK-NEXT: [[ADD12:%.*]] = add nsw i32 [[TMP23]], [[TMP21]] +// CHECK-NEXT: store i32 [[ADD12]], ptr [[TMP22]], align 4 +// CHECK-NEXT: [[TMP24:%.*]] = load ptr, ptr [[V_ADDR]], align 8 +// CHECK-NEXT: [[TMP25:%.*]] = load i32, ptr [[I9]], align 4 +// CHECK-NEXT: [[IDXPROM13:%.*]] = sext i32 [[TMP25]] to i64 +// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds i32, ptr [[TMP24]], i64 [[IDXPROM13]] +// CHECK-NEXT: [[TMP26:%.*]] = load i32, ptr [[ARRAYIDX14]], align 4 +// CHECK-NEXT: [[TMP27:%.*]] = load ptr, ptr [[_TMP8]], align 8 +// CHECK-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4 +// CHECK-NEXT: [[MUL15:%.*]] = mul nsw i32 [[TMP28]], [[TMP26]] +// CHECK-NEXT: store i32 [[MUL15]], ptr [[TMP27]], align 4 +// CHECK-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] +// CHECK: omp.body.continue: +// CHECK-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] +// CHECK: omp.inner.for.inc: +// CHECK-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP29]], 1 +// CHECK-NEXT: store i32 [[ADD16]], ptr [[DOTOMP_IV]], align 4 +// CHECK-NEXT: br label [[OMP_INNER_FOR_COND]] +// CHECK: omp.inner.for.end: +// CHECK-NEXT: br label [[OMP_LOOP_EXIT:%.*]] +// CHECK: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP0]]) +// CHECK-NEXT: [[TMP30:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB2]], i32 [[TMP0]], i32 0, i64 0, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z15do_red_extendediPiRiS0_.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: switch i32 [[TMP30]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [ +// CHECK-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]] +// CHECK-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]] +// CHECK-NEXT: ] +// CHECK: .omp.reduction.case1: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.case2: +// CHECK-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB2]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction.var) +// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]] +// CHECK: .omp.reduction.default: +// CHECK-NEXT: [[TMP31:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NEXT: br i1 [[TMP31]], label [[INIT:%.*]], label [[INIT_END:%.*]] +// CHECK: init: +// CHECK-NEXT: store i32 0, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1392, align 4 +// CHECK-NEXT: br label [[INIT_END]] +// CHECK: init.end: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP32:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1392, align 4 +// CHECK-NEXT: [[TMP33:%.*]] = load i32, ptr [[SUM_V5]], align 4 +// CHECK-NEXT: [[ADD17:%.*]] = add nsw i32 [[TMP32]], [[TMP33]] +// CHECK-NEXT: store i32 [[ADD17]], ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1392, align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: [[TMP34:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.sum_v.sum_v_1392, align 4 +// CHECK-NEXT: store i32 [[TMP34]], ptr [[SUM_V5]], align 4 +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP9]], align 4 +// CHECK-NEXT: [[TMP36:%.*]] = load i32, ptr [[SUM_V5]], align 4 +// CHECK-NEXT: [[ADD18:%.*]] = add nsw i32 [[TMP35]], [[TMP36]] +// CHECK-NEXT: store i32 [[ADD18]], ptr [[TMP9]], align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP37:%.*]] = icmp eq i32 [[TMP0]], 0 +// CHECK-NEXT: br i1 [[TMP37]], label [[INIT19:%.*]], label [[INIT_END20:%.*]] +// CHECK: init19: +// CHECK-NEXT: store i32 1, ptr @.omp.reduction..internal_pivate_.prod_v.prod_v_1461, align 4 +// CHECK-NEXT: br label [[INIT_END20]] +// CHECK: init.end20: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP38:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.prod_v.prod_v_1461, align 4 +// CHECK-NEXT: [[TMP39:%.*]] = load i32, ptr [[PROD_V7]], align 4 +// CHECK-NEXT: [[MUL21:%.*]] = mul nsw i32 [[TMP38]], [[TMP39]] +// CHECK-NEXT: store i32 [[MUL21]], ptr @.omp.reduction..internal_pivate_.prod_v.prod_v_1461, align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: [[TMP40:%.*]] = load i32, ptr @.omp.reduction..internal_pivate_.prod_v.prod_v_1461, align 4 +// CHECK-NEXT: store i32 [[TMP40]], ptr [[PROD_V7]], align 4 +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP0]]) +// CHECK-NEXT: call void @__kmpc_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: [[TMP41:%.*]] = load i32, ptr [[TMP10]], align 4 +// CHECK-NEXT: [[TMP42:%.*]] = load i32, ptr [[PROD_V7]], align 4 +// CHECK-NEXT: [[MUL22:%.*]] = mul nsw i32 [[TMP41]], [[TMP42]] +// CHECK-NEXT: store i32 [[MUL22]], ptr [[TMP10]], align 4 +// CHECK-NEXT: call void @__kmpc_end_critical(ptr @[[GLOB3]], i32 [[TMP0]], ptr @.gomp_critical_user_.reduction_critical.var) +// CHECK-NEXT: br label [[OMP_PRECOND_END]] +// CHECK: omp.precond.end: +// CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4]], i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@_Z15do_red_extendediPiRiS0_.omp.reduction.reduction_func +// CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR5]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@main +// CHECK-SAME: () #[[ATTR7:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[V:%.*]] = alloca [10 x i32], align 16 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SUM_V_EXT:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[PROD_V_EXT:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]]) +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: store i32 0, ptr [[I]], align 4 +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP1]], 10 +// CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP3]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], ptr [[V]], i64 0, i64 [[IDXPROM]] +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: br label [[FOR_INC:%.*]] +// CHECK: for.inc: +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP4]], 1 +// CHECK-NEXT: store i32 [[INC]], ptr [[I]], align 4 +// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP7:![0-9]+]] +// CHECK: for.end: +// CHECK-NEXT: call void @__kmpc_push_num_threads(ptr @[[GLOB3]], i32 [[TMP0]], i32 4) +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 1, ptr @main.omp_outlined, ptr [[V]]) +// CHECK-NEXT: store i32 0, ptr [[SUM_V_EXT]], align 4 +// CHECK-NEXT: store i32 1, ptr [[PROD_V_EXT]], align 4 +// CHECK-NEXT: call void @__kmpc_push_num_threads(ptr @[[GLOB3]], i32 [[TMP0]], i32 4) +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @main.omp_outlined.1, ptr [[V]], ptr [[SUM_V_EXT]], ptr [[PROD_V_EXT]]) +// CHECK-NEXT: ret i32 0 + diff --git a/clang/test/OpenMP/for_reduction_messages.cpp b/clang/test/OpenMP/for_reduction_messages.cpp index de28ba2c3be02..2fdac3048c9cd 100644 --- a/clang/test/OpenMP/for_reduction_messages.cpp +++ b/clang/test/OpenMP/for_reduction_messages.cpp @@ -417,10 +417,12 @@ int main(int argc, char **argv) { #pragma omp for reduction(+ : qa[1], qa[0]) for (int i = 0; i < 10; ++i) foo(); +#if defined(_OPENMP) && (_OPENMP <= 202111) #pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}} #pragma omp for reduction(+ : fl) // expected-error {{reduction variable must be shared}} for (int i = 0; i < 10; ++i) foo(); +#endif static int m=0; #pragma omp for reduction(+:m) for (int i = 0; i < 10; ++i) diff --git a/clang/test/OpenMP/for_simd_reduction_messages.cpp b/clang/test/OpenMP/for_simd_reduction_messages.cpp index 96b3805b10a86..a9ef6c39cb5d2 100644 --- a/clang/test/OpenMP/for_simd_reduction_messages.cpp +++ b/clang/test/OpenMP/for_simd_reduction_messages.cpp @@ -396,11 +396,11 @@ int main(int argc, char **argv) { #pragma omp for simd reduction(+ : fl) // expected-error {{reduction variable must be shared}} for (int i = 0; i < 10; ++i) foo(); -#endif #pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}} #pragma omp for simd reduction(+ : fl) // expected-error {{reduction variable must be shared}} for (int i = 0; i < 10; ++i) foo(); +#endif static int m; #pragma omp for simd reduction(+ : m) for (int i = 0; i < 10; ++i) diff --git a/clang/test/OpenMP/sections_reduction_messages.cpp b/clang/test/OpenMP/sections_reduction_messages.cpp index 42ec3ed6d58e8..8cde6489f325f 100644 --- a/clang/test/OpenMP/sections_reduction_messages.cpp +++ b/clang/test/OpenMP/sections_reduction_messages.cpp @@ -461,12 +461,12 @@ int main(int argc, char **argv) { { foo(); } -#endif #pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}} #pragma omp sections reduction(+ : fl) // expected-error {{reduction variable must be shared}} { foo(); } +#endif static int m; #pragma omp sections reduction(+ : m) // OK { 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 0000000000000..a5847709d3e76 --- /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 0000000000000..5df1e958ad55a --- /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 83191059202ca..000cc80e513e6 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 aad8836db1062..f37d00503fe57 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 0000000000000..56047037c331f --- /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 0000000000000..5b64582cba618 --- /dev/null +++ b/clang/test/PCH/ignored-pch.c @@ -0,0 +1,113 @@ +// 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 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH-ERROR %s +// RUN: ls %t.ll 2>&1 | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-OBJ-ERROR %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH-ERROR %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH-ERROR %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH-ERROR %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH-ERROR %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + +// 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 2>&1 | FileCheck --check-prefix=CHECK-PCH %s +// RUN: ls %t.ll | FileCheck --check-prefix=CHECK-OBJ %s + + +// 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-PCH: ignored-pch.c.{{.*}}.pch +// CHECK-OBJ: ignored-pch.c.{{.*}}.ll +// CHECK-PCH-ERROR: ignored-pch.c.{{.*}}.pch{{'?}}: No such file or directory +// CHECK-OBJ-ERROR: ignored-pch.c.{{.*}}.ll{{'?}}: No such file or directory +// 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 0000000000000..94fa8c8c820a5 --- /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 7338c5116c16c..6f2f54ead62bc 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 3e2526979be8b..b7a8d30bd16c5 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 4a329646b799f..d798a9cbb99b7 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 72e286322fa97..79069a86ea706 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 0000000000000..6826cc04e4df5 --- /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 2158d8062f6cd..1ff84f393b9f4 100644 --- a/clang/test/Parser/objc-foreach-syntax.m +++ b/clang/test/Parser/objc-foreach-syntax.m @@ -21,6 +21,5 @@ - (void)compilerTestAgainst { 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 d7ba609ebd74b..88fa3103593ef 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 2648142f28e7c..2cd2c6ca133e1 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 6fdbedffd236a..0d86bd0608bf1 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 baf703cd03aed..40712799933c2 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 ebf1c18f2b86a..95d610b9cdd25 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 a5a1e58028c33..948f2e30f149c 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 6d771e858d243..a9ad7ab176cbc 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 814f6a1fd09f2..69b04bcbad9e3 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 16e31a67c094f..5c006b4379a27 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 491c3bee4ac5a..27a3a02dc2637 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 4cb9b6ce53b0d..fd83e4b689a2a 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 ac461b371162f..71a266b8a9157 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/riscv-target-features-andes.c b/clang/test/Preprocessor/riscv-target-features-andes.c index 3cd9b04354132..c66d4427b5cf2 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 8d0a4ad33562a..7e9d5cc91038d 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 fb8e341156a59..9bfcb30b9eba3 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 0000000000000..6afd3fd32c366 --- /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 0000000000000..81c966789ccb5 --- /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 0000000000000..0568c734424ca --- /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 57ee187ccf4d5..0e3fec1b18eec 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/typo-correction-ambiguity.cpp b/clang/test/Sema/typo-correction-ambiguity.cpp index 9dcff3d68c823..b2dae1d7696c3 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 e6041704ff324..da234a2c7373c 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 3c591645be25c..34b8486bed902 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 @@ class A { 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 b39beb5493f65..a7d7127564b75 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 @@ class Y 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 4157207a9ac42..510a67e725f9c 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 a701650c9e056..4711c9fa667ba 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 295dea3c1756c..a789c4e36e4c9 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 00fa5bd7336b6..acd9846bb20fb 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 c775fe71069df..66981acf87a8a 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 2f59544e7f36c..f1e02d5158aac 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 @@ class C { 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 @@ class C { #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 eeeb58f1a771a..ab4e50072f654 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 b653a3bf1a1d2..717c73c4786eb 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 068fdab4bfe38..c9cefeb30c15a 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 0000000000000..f3aa051532815 --- /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 a612a5c07e6ed..4b54221cceff2 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 @@ class C { 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 95c64bc3b8bff..6ee1249a66c3f 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 0000000000000..a16a7f8255f7c --- /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 5c0d89d9125f2..1bc7f2cce3c92 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 d9932e4dd8241..1474c48cda3c1 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 aff172e0bc70a..7152a5937d9b7 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)); @@ -388,3 +389,24 @@ void do_test__builtin_trivially_relocate() { // expected-note@-1 {{'test__builtin_trivially_relocate' requested here}} // expected-error@#reloc1 {{first argument to '__builtin_trivially_relocate' must be relocatable}} } + + +namespace GH143599 { +struct A { ~A (); }; +A::~A () = default; + +static_assert (!__builtin_is_cpp_trivially_relocatable(A)); +static_assert (!__builtin_is_replaceable(A)); + +struct B { B(const B&); }; +B::B (const B&) = default; + +static_assert (!__builtin_is_cpp_trivially_relocatable(B)); +static_assert (!__builtin_is_replaceable(B)); + +struct C { C& operator=(const C&); }; +C& C::operator=(const C&) = default; + +static_assert (!__builtin_is_cpp_trivially_relocatable(C)); +static_assert (!__builtin_is_replaceable(C)); +} diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index ed4802943ad3f..b9e0b17d510ab 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/gh102293.cpp b/clang/test/SemaCXX/gh102293.cpp index d4218cc13dcec..fe417e697841b 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 0007f2739cbbd..9f27741871484 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 0596e40f6c2f6..902b09097a120 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/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 36398aed7ac5f..abeaba9d8dde2 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 304ee92f6a8da..0000000000000 --- 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 60d1b57230f18..ba8a8273d5c05 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 17d7892d8dbd9..796c9ae91dedc 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 0000000000000..b38499a634fcf --- /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-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp index 9e053034acda4..5210354a66d43 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(); @@ -320,6 +320,29 @@ static_assert(__builtin_is_cpp_trivially_relocatable(UnionOfPolymorphic)); } +struct GH143599 { // expected-note 2 {{'GH143599' defined here}} + ~GH143599 (); + GH143599(const GH143599&); + GH143599& operator=(const GH143599&); +}; +GH143599::~GH143599 () = default; +GH143599::GH143599 (const GH143599&) = default; +GH143599& GH143599::operator=(const GH143599&) = default; + +static_assert (__builtin_is_cpp_trivially_relocatable(GH143599)); +// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_cpp_trivially_relocatable(GH143599)'}} \ +// expected-note@-1 {{'GH143599' is not trivially relocatable}} \ +// expected-note@-1 {{because it has a user provided copy constructor}} \ +// expected-note@-1 {{because it has a user provided copy assignment operator}} \ +// expected-note@-1 {{because it has a user-provided destructor}} + +static_assert (__builtin_is_replaceable(GH143599)); +// expected-error@-1 {{static assertion failed due to requirement '__builtin_is_replaceable(GH143599)'}} \ +// expected-note@-1 {{'GH143599' is not replaceable}} \ +// expected-note@-1 {{because it has a user provided copy constructor}} \ +// expected-note@-1 {{because it has a user provided copy assignment operator}} \ +// expected-note@-1 {{because it has a user-provided destructor}} + namespace trivially_copyable { struct B { virtual ~B(); diff --git a/clang/test/SemaCXX/typo-correction-crash.cpp b/clang/test/SemaCXX/typo-correction-crash.cpp index 2a77c9df505e8..434b70e3c5097 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 8c588203cc128..9eb5f9c299629 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 fdb1f740fda6a..0000000000000 --- 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 45f42c4260358..e4dadf83e0a08 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 4b41bfbfdc2f7..ff3b85d19fa67 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 537429d9ebdaa..bd0ee6bd14d64 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 2a22ab9fc2b09..f6f52d51f650c 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/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl new file mode 100644 index 0000000000000..32bc5f55b2abd --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s + +float4 main(float4 a : SV_Position) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 'float4':'vector' +// CHECK-NEXT: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> +} diff --git a/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl new file mode 100644 index 0000000000000..124d401a9990c --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected + +// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} +void main(vector a : SV_Position) { +} + +// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}} +void main(int2 a : SV_Position) { +} diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl new file mode 100644 index 0000000000000..19f781fa3757c --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify + +// expected-error@+1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}} +float4 main(float4 a : SV_Position) { + return a; +} diff --git a/clang/test/SemaObjC/call-super-2.m b/clang/test/SemaObjC/call-super-2.m index 01acff70c2301..885f392e353a6 100644 --- a/clang/test/SemaObjC/call-super-2.m +++ b/clang/test/SemaObjC/call-super-2.m @@ -115,7 +115,7 @@ @interface B : A @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 340f3cfe2743c..6c09127dbb8d6 100644 --- a/clang/test/SemaObjC/typo-correction-subscript.m +++ b/clang/test/SemaObjC/typo-correction-subscript.m @@ -7,8 +7,7 @@ @interface Test @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 11fd97f2c00d8..b8cbe7f69f2f5 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 @@ @interface DBGViewDebuggerSupport_iOS : DBGViewDebuggerSupport @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/block-for-lambda-conversion.mm b/clang/test/SemaObjCXX/block-for-lambda-conversion.mm index 671e83dc22019..a3bcfab677197 100644 --- a/clang/test/SemaObjCXX/block-for-lambda-conversion.mm +++ b/clang/test/SemaObjCXX/block-for-lambda-conversion.mm @@ -8,19 +8,20 @@ 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 c6dbe4db2be64..0cf27666dd030 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 7a273546db772..babebba31e82b 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/clang-builtin-version.cl b/clang/test/SemaOpenCL/clang-builtin-version.cl index ec6eecee3106c..21cbf2d8f28d4 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-recovery-expr.cpp b/clang/test/SemaTemplate/concepts-recovery-expr.cpp index b338f3bc271bf..6bed1790051f3 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 a99df2390a551..62a4f95d79c74 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 63d8366b617c1..6602670af901f 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 c9b777aebbe91..48306fb9ce805 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 b22d3aaf3183b..c0efbb7588ccb 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; + } + if (Offset + Length > CodeSize) { + errs() << "error: invalid length " << Length << ", offset + length (" + << Offset + Length << ") is outside the file\n"; + return true; } - unsigned Offset = Sources.getFileOffset(Start); - unsigned Length = Sources.getFileOffset(End) - Offset; - Ranges.push_back(tooling::Range(Offset, Length)); + 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 95b6f74af1f13..0f1fa8b329fd6 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)); - - // 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)); - } + 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)); if (Error Err = executeCommands(*ObjcopyPath, ObjcopyArgs)) return Err; diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 635d03a88d105..a6301daa672c3 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 873c6c492d18c..a1285e4bc9bf8 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 a7b258d5e537e..459a3864887e1 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 377c066f031d3..61f74929c1e98 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/Parse/CMakeLists.txt b/clang/unittests/Parse/CMakeLists.txt index 6859efed294c8..2ed43a83b8782 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 2b271d4bf7825..cc9dd4175af55 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/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 21d76c12a3cce..f892626a447e5 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; @@ -5405,7 +5406,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; } diff --git a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index f15e30cd3f8f4..161dd425fbc7b 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 b8d8ac853a5c0..e5eec5e7ca8d4 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 e347b89a85d46..bfc60f485cd32 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); } diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp index 5d6d90994cf37..9d0773e1aff8f 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/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 075c4647abf69..5e832315f3666 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 19f26c92a0f94..2d213d95f333a 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/trampoline_setup.c b/compiler-rt/lib/builtins/trampoline_setup.c index 830e25e4c0303..844eb27944142 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 93bf817a857b4..c9210c78a0631 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/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp index c2d07400593d5..2ee35555c24de 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 @@ class RtsanOpenedFileTest : public RtsanFileTest { } 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 @@ class RtsanOpenedFileTest : public RtsanFileTest { 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_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9272e2ab6cbd5..2d6cf7fc3282f 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 bc8f02826c614..08c2be47f5358 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 1565a494140f6..0b6731c89950b 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_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 9f5f41cd85514..4c8d9a9b86bed 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 4bc55d7801db7..ccc808b60ca75 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 diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h index 41e0613d6fc13..bda0f04687693 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/test/builtins/Unit/trampoline_setup_test.c b/compiler-rt/test/builtins/Unit/trampoline_setup_test.c index d51d35acaa02f..da115fe764271 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/hwasan/TestCases/Posix/dlerror.cpp b/compiler-rt/test/hwasan/TestCases/Posix/dlerror.cpp index b6e486b291f3a..91acd28a1a5ff 100644 --- a/compiler-rt/test/hwasan/TestCases/Posix/dlerror.cpp +++ b/compiler-rt/test/hwasan/TestCases/Posix/dlerror.cpp @@ -1,6 +1,9 @@ // Make sure dlerror is not classified as a leak even if we use dynamic TLS. // This is currently not implemented, so this test is XFAIL. +// Android HWAsan does not support LSan. +// UNSUPPORTED: android + // RUN: %clangxx_hwasan -O0 %s -o %t && HWASAN_OPTIONS=detect_leaks=1 %run %t #include diff --git a/compiler-rt/test/lit.common.configured.in b/compiler-rt/test/lit.common.configured.in index 8ca47a8df5aed..04d1a4df5a54f 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 91730a01f2d8a..e06775db3251a 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 af287ed64357e..93e6845e1ea7a 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/rtsan/fork_exec.cpp b/compiler-rt/test/rtsan/fork_exec.cpp index 3b2d2e5ca2f5d..5890a0936a2f7 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/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt index 76f57501e854e..ce0afa8769f03 100644 --- a/compiler-rt/test/tysan/CMakeLists.txt +++ b/compiler-rt/test/tysan/CMakeLists.txt @@ -21,9 +21,7 @@ foreach(arch ${TYSAN_TEST_ARCH}) endforeach() set(TYSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) -if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND TYSAN_TEST_DEPS tysan) -endif() +list(APPEND TYSAN_TEST_DEPS tysan) add_lit_testsuite(check-tysan "Running the TypeSanitizer tests" ${TYSAN_TESTSUITES} diff --git a/cross-project-tests/tools/llvm-objdump/RISCV/riscv-sym-search.s b/cross-project-tests/tools/llvm-objdump/RISCV/riscv-sym-search.s new file mode 100644 index 0000000000000..01fc4806116a4 --- /dev/null +++ b/cross-project-tests/tools/llvm-objdump/RISCV/riscv-sym-search.s @@ -0,0 +1,17 @@ +# RUN: %clang --target=fuchsia-elf-riscv64 -march=rv64g %s -nostdlib -o %t +# RUN: llvm-objdump -d %t | FileCheck %s + +# CHECK: auipc a0, 0x101 +# CHECK: ld a0, 0x8(a0) +.global _start +.text +_start: + la a0, gdata + +.skip 0x100000 +ldata: + .int 0 + +.data +gdata: + .int 0 diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h index 16258b3bbba9b..e579f6012ce86 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 070d0bf8673fb..dc372de53506a 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 5e79efde164f2..80301a313282f 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 @@ class SpecialBinding { 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 @@ class SpecialBinding { // 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 @@ class DerivedType { 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 @@ class DerivedType { 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 0000000000000..0daa7bc4d3384 --- /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 7b768f91af29d..aa75d4eff0511 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 a3f63b4315644..332c0872e065f 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 ef18da6ea0786..f724f0a20884b 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 bf67b5dc8b645..f936a4192a33c 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,11 +63,24 @@ 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; - } - 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)) { + WorkQueue workQueue{terminator}; + if (workQueue.BeginAssign(to, from, flags, memmoveFct, nullptr) == + StatContinue) { + workQueue.Run(); + } +} + +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()); + if (int stat{ReturnError( + workQueue.terminator(), newFrom.Allocate(kNoAsyncObject))}; + stat != StatOk) { + return stat; + } + 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; + } + } + } } - Assign(to, newFrom, terminator, - flags & - (NeedFinalization | ComponentCanBeDefinedAssignment | - ExplicitLengthCharacterLHS | CanBeDefinedAssignment)); - newFrom.Deallocate(); + 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()); } - return; + from_ = &newFrom; // this is why from_ has to be a pointer + flags_ &= NeedFinalization | ComponentCanBeDefinedAssignment | + ExplicitLengthCharacterLHS | CanBeDefinedAssignment; + toDeallocate_ = &newFrom; } } - if (to.IsAllocatable()) { + 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; + 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 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; + } + 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; + } } - 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( + // 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)}) { - return DoScalarDefinedAssignment(to, from, *special); + DoScalarDefinedAssignment(to_, *from_, *toDerived_, *special); + done_ = true; + return StatContinue; } } - if (const auto *special{toDerived->FindSpecialBinding( + if (const auto *special{declaredType_->FindSpecialBinding( typeInfo::SpecialBinding::Which::ElementalAssignment)}) { - return DoElementalDefinedAssignment(to, from, *toDerived, *special); + DoElementalDefinedAssignment(to_, *from_, *toDerived_, *special); + done_ = true; + return StatContinue; } } - 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()); + // 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()) { - terminator.Crash("Assign: mismatching types (to code %d != from code %d)", - to.type().raw(), from.type().raw()); + if (to_.type() != from_->type()) { + workQueue.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)", + 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 (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) - } - } - // 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; - } + if (toDerived_) { + if (toDerived_->noDefinedAssignment()) { // componentwise + if (int status{workQueue.BeginDerivedAssign( + to_, *from_, *toDerived_, flags_, memmoveFct_, toDeallocate_)}; + status != StatOk && status != StatContinue) { + return status; } - // 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)); + } else { // elementwise + if (int status{workQueue.BeginDerivedAssign( + to_, *from_, *toDerived_, flags_, memmoveFct_, toDeallocate_)}; + 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()) { + 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 35037036f63e7..4e36b1e2edfc8 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); + 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(); + } + 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; - 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; - } - } } - } else if (const void *init{comp.initialization()}) { + 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,51 +391,71 @@ 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 (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(); + } } - if (finalize && !derived.noFinalizationNeeded()) { - Finalize(descriptor, derived, terminator); +} + +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. - 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); + 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(); - 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)) { + 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, - descriptor.ElementComponent(at, comp.offset()), comp.rank(), - extents); - Destroy(compDesc, /*finalize=*/false, *comp.derivedType(), terminator); + 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) { diff --git a/flang-rt/lib/runtime/descriptor-io.cpp b/flang-rt/lib/runtime/descriptor-io.cpp index 3db1455af52fe..e7b99e6fc3a2b 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 eb60f106c9203..88ad59bd24b53 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::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; -} +namespace Fortran::runtime::io { +class IoStatementState; +struct NonTbpDefinedIoTable; +} // namespace Fortran::runtime::io -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; -} +namespace Fortran::runtime::io::descr { 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 -} - -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 &); +extern template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); +extern template RT_API_ATTRS bool DescriptorIO( + IoStatementState &, const Descriptor &, const NonTbpDefinedIoTable *); -// 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 1d5304254ed0e..0f0564403c0e2 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 b0cf2180fc6d4..1bef387a9771f 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 b08195cd31e05..24d05f369fcbe 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 82182696d70c6..d023c3392d559 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 0000000000000..a508ecb637102 --- /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 3833e48be3dd6..6c148b1de6f82 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/Maintainers.md b/flang/Maintainers.md index f4a7635389138..b994c300e4e2c 100644 --- a/flang/Maintainers.md +++ b/flang/Maintainers.md @@ -79,6 +79,13 @@ clementval@gmail.com (email), clementval (GitHub), clementval (Discourse) Abid Qadeer \ haqadeer@amd.com (email), abidh (GitHub), abidh (Discourse) +### Platform maintainers +These maintainers are responsible for particular platforms that Flang supports + +#### Windows +David Truby \ +david.truby@arm.com (email), davidtruby (GitHub), davidtruby (Discourse), truby (Discord) + ## Inactive Maintainers ### Lead Maintainers #### Backend : (Lowering, FIR, Codegen) diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 78d871c593e1d..871749934810c 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/docs/OpenMPSupport.md b/flang/docs/OpenMPSupport.md index 7a4f95693a89c..c9f19c37fd7fa 100644 --- a/flang/docs/OpenMPSupport.md +++ b/flang/docs/OpenMPSupport.md @@ -60,3 +60,16 @@ Note : No distinction is made between the support in Parser/Semantics, MLIR, Low | target teams distribute parallel loop construct | P | device, reduction and dist_schedule clauses are not supported | | teams distribute parallel loop simd construct | P | reduction, dist_schedule, and linear clauses are not supported | | target teams distribute parallel loop simd construct | P | device, reduction, dist_schedule and linear clauses are not supported | + +## Extensions +### ATOMIC construct +The implementation of the ATOMIC construct follows OpenMP 6.0 with the following extensions: +- `x = x` is an allowed form of ATOMIC UPDATE. +This is motivated by the fact that the equivalent forms `x = x+0` or `x = x*1` are allowed. +- Explicit type conversions are allowed in ATOMIC READ, WRITE or UPDATE constructs, and in the capture statement in ATOMIC UPDATE CAPTURE. +The OpenMP spec requires intrinsic- or pointer-assignments, which include (as per the Fortran standard) implicit type conversions. Since such conversions need to be handled, allowing explicit conversions comes at no extra cost. +- A literal `.true.` or `.false.` is an allowed condition in ATOMIC UPDATE COMPARE. [1] +- A logical variable is an allowed form of the condition even if its value is not computed within the ATOMIC UPDATE COMPARE construct [1]. +- `expr equalop x` is an allowed condition in ATOMIC UPDATE COMPARE. [1] + +[1] Code generation for ATOMIC UPDATE COMPARE is not implemented yet. diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index d1407cf0ef239..a36b8719e365d 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -445,13 +445,6 @@ struct NodeVisitor { READ_FEATURE(ObjectDecl) READ_FEATURE(OldParameterStmt) READ_FEATURE(OmpAlignedClause) - READ_FEATURE(OmpAtomic) - READ_FEATURE(OmpAtomicCapture) - READ_FEATURE(OmpAtomicCapture::Stmt1) - READ_FEATURE(OmpAtomicCapture::Stmt2) - READ_FEATURE(OmpAtomicRead) - READ_FEATURE(OmpAtomicUpdate) - READ_FEATURE(OmpAtomicWrite) READ_FEATURE(OmpBeginBlockDirective) READ_FEATURE(OmpBeginLoopDirective) READ_FEATURE(OmpBeginSectionsDirective) @@ -480,7 +473,6 @@ struct NodeVisitor { READ_FEATURE(OmpIterationOffset) READ_FEATURE(OmpIterationVector) READ_FEATURE(OmpEndAllocators) - READ_FEATURE(OmpEndAtomic) READ_FEATURE(OmpEndBlockDirective) READ_FEATURE(OmpEndCriticalDirective) READ_FEATURE(OmpEndLoopDirective) @@ -566,8 +558,6 @@ struct NodeVisitor { READ_FEATURE(OpenMPDeclareTargetConstruct) READ_FEATURE(OmpMemoryOrderType) READ_FEATURE(OmpMemoryOrderClause) - READ_FEATURE(OmpAtomicClause) - READ_FEATURE(OmpAtomicClauseList) READ_FEATURE(OmpAtomicDefaultMemOrderClause) READ_FEATURE(OpenMPFlushConstruct) READ_FEATURE(OpenMPLoopConstruct) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index bf66151d59950..feb7b4eced9e9 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -74,25 +74,19 @@ SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) { // the directive field. [&](const auto &c) -> SourcePosition { const CharBlock &source{std::get<0>(c.t).source}; - return (parsing->allCooked().GetSourcePositionRange(source))->first; + return parsing->allCooked().GetSourcePositionRange(source)->first; }, [&](const OpenMPAtomicConstruct &c) -> SourcePosition { - return std::visit( - [&](const auto &o) -> SourcePosition { - const CharBlock &source{std::get(o.t).source}; - return parsing->allCooked() - .GetSourcePositionRange(source) - ->first; - }, - c.u); + const CharBlock &source{c.source}; + return parsing->allCooked().GetSourcePositionRange(source)->first; }, [&](const OpenMPSectionConstruct &c) -> SourcePosition { const CharBlock &source{c.source}; - return (parsing->allCooked().GetSourcePositionRange(source))->first; + return parsing->allCooked().GetSourcePositionRange(source)->first; }, [&](const OpenMPUtilityConstruct &c) -> SourcePosition { const CharBlock &source{c.source}; - return (parsing->allCooked().GetSourcePositionRange(source))->first; + return parsing->allCooked().GetSourcePositionRange(source)->first; }, }, c.u); @@ -157,14 +151,9 @@ std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) { return normalize_construct_name(source.ToString()); }, [&](const OpenMPAtomicConstruct &c) -> std::string { - return std::visit( - [&](const auto &c) { - // Get source from the verbatim fields - const CharBlock &source{std::get(c.t).source}; - return "atomic-" + - normalize_construct_name(source.ToString()); - }, - c.u); + auto &dirSpec = std::get(c.t); + auto &dirName = std::get(dirSpec.t); + return normalize_construct_name(dirName.source.ToString()); }, [&](const OpenMPUtilityConstruct &c) -> std::string { const CharBlock &source{c.source}; diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 4dce1257a6507..1959d5f3a5899 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, diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index a697872836569..ae12aec518108 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 e939f10f3c3e7..bad17c8309eb8 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -154,6 +154,44 @@ class CodeGenOptions : public CodeGenOptionsBase { /// 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 b062ea1a805ac..d97abf4d864b8 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/Optimizer/Builder/Runtime/CUDA/Descriptor.h b/flang/include/flang/Optimizer/Builder/Runtime/CUDA/Descriptor.h index 14d262bf22a70..bdeb7574012c6 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 90e05ce3d5ca6..27a6ca4ebdb4e 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,11 @@ 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"; + } }]; } diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index df9278697346f..e3eed6aed8079 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -532,15 +532,6 @@ class ParseTreeDumper { NODE(parser, OmpAtClause) NODE_ENUM(OmpAtClause, ActionTime) NODE_ENUM(OmpSeverityClause, Severity) - NODE(parser, OmpAtomic) - NODE(parser, OmpAtomicCapture) - NODE(OmpAtomicCapture, Stmt1) - NODE(OmpAtomicCapture, Stmt2) - NODE(parser, OmpAtomicCompare) - NODE(parser, OmpAtomicCompareIfStmt) - NODE(parser, OmpAtomicRead) - NODE(parser, OmpAtomicUpdate) - NODE(parser, OmpAtomicWrite) NODE(parser, OmpBeginBlockDirective) NODE(parser, OmpBeginLoopDirective) NODE(parser, OmpBeginSectionsDirective) @@ -574,6 +565,7 @@ class ParseTreeDumper { NODE_ENUM(OmpDependenceType, Value) NODE(parser, OmpTaskDependenceType) NODE_ENUM(OmpTaskDependenceType, Value) + NODE(parser, OmpIndirectClause) NODE(parser, OmpIterationOffset) NODE(parser, OmpIteration) NODE(parser, OmpIterationVector) @@ -587,7 +579,6 @@ class ParseTreeDumper { NODE(parser, OmpDoacrossClause) NODE(parser, OmpDestroyClause) NODE(parser, OmpEndAllocators) - NODE(parser, OmpEndAtomic) NODE(parser, OmpEndBlockDirective) NODE(parser, OmpEndCriticalDirective) NODE(parser, OmpEndLoopDirective) @@ -716,8 +707,6 @@ class ParseTreeDumper { NODE(parser, OpenMPDeclareMapperConstruct) NODE_ENUM(common, OmpMemoryOrderType) NODE(parser, OmpMemoryOrderClause) - NODE(parser, OmpAtomicClause) - NODE(parser, OmpAtomicClauseList) NODE(parser, OmpAtomicDefaultMemOrderClause) NODE(parser, OpenMPDepobjConstruct) NODE(parser, OpenMPUtilityConstruct) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index c99006f0c1c22..61f97b855b0e5 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. // @@ -4857,94 +4863,37 @@ struct OmpMemoryOrderClause { CharBlock source; }; -// 2.17.7 Atomic construct -// atomic-clause -> memory-order-clause | HINT(hint-expression) | -// FAIL(memory-order) -struct OmpAtomicClause { - UNION_CLASS_BOILERPLATE(OmpAtomicClause); - CharBlock source; - std::variant u; -}; - -// atomic-clause-list -> [atomic-clause, [atomic-clause], ...] -struct OmpAtomicClauseList { - WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list); - CharBlock source; -}; - -// END ATOMIC -EMPTY_CLASS(OmpEndAtomic); - -// ATOMIC READ -struct OmpAtomicRead { - TUPLE_CLASS_BOILERPLATE(OmpAtomicRead); - CharBlock source; - std::tuple, std::optional> - t; -}; - -// ATOMIC WRITE -struct OmpAtomicWrite { - TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite); - CharBlock source; - std::tuple, std::optional> - t; -}; - -// ATOMIC UPDATE -struct OmpAtomicUpdate { - TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate); - CharBlock source; - std::tuple, std::optional> - t; -}; - -// ATOMIC CAPTURE -struct OmpAtomicCapture { - TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture); - CharBlock source; - WRAPPER_CLASS(Stmt1, Statement); - WRAPPER_CLASS(Stmt2, Statement); - std::tuple - t; -}; - -struct OmpAtomicCompareIfStmt { - UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt); - std::variant, common::Indirection> u; -}; - -// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4) -struct OmpAtomicCompare { - TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare); +struct OpenMPAtomicConstruct { + llvm::omp::Clause GetKind() const; + bool IsCapture() const; + bool IsCompare() const; + TUPLE_CLASS_BOILERPLATE(OpenMPAtomicConstruct); CharBlock source; - std::tuple> + std::tuple> t; -}; -// ATOMIC -struct OmpAtomic { - TUPLE_CLASS_BOILERPLATE(OmpAtomic); - CharBlock source; - std::tuple, - std::optional> - t; -}; + // Information filled out during semantic checks to avoid duplication + // of analyses. + struct Analysis { + static constexpr int None = 0; + static constexpr int Read = 1; + static constexpr int Write = 2; + static constexpr int Update = Read | Write; + static constexpr int Action = 3; // Bitmask for None, Read, Write, Update + static constexpr int IfTrue = 4; + static constexpr int IfFalse = 8; + static constexpr int Condition = 12; // Bitmask for IfTrue, IfFalse + + struct Op { + int what; + AssignmentStmt::TypedAssignment assign; + }; + TypedExpr atom, cond; + Op op0, op1; + }; -// 2.17.7 atomic -> -// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] | -// ATOMIC [atomic-clause-list] -// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE -struct OpenMPAtomicConstruct { - UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct); - std::variant - u; + mutable Analysis analysis; }; // OpenMP directives that associate with loop(s) diff --git a/flang/include/flang/Parser/tools.h b/flang/include/flang/Parser/tools.h index f1ead11734fa0..447bccd5d35a6 100644 --- a/flang/include/flang/Parser/tools.h +++ b/flang/include/flang/Parser/tools.h @@ -250,5 +250,8 @@ template std::optional GetLastSource(A &x) { return GetSourceHelper::GetSource(const_cast(x)); } +// Checks whether the assignment statement has a single variable on the RHS. +bool CheckForSingleVariableOnRHS(const AssignmentStmt &); + } // namespace Fortran::parser #endif // FORTRAN_PARSER_TOOLS_H_ diff --git a/flang/include/flang/Runtime/CUDA/descriptor.h b/flang/include/flang/Runtime/CUDA/descriptor.h index 0ee7feca10e44..06e4a4649db1b 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 bc80997a1bec2..7d198bdcc9e89 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/tools.h b/flang/include/flang/Semantics/tools.h index 3839bc1d2a215..69375a83dec25 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,29 +756,154 @@ std::string GetCommonBlockObjectName(const Symbol &, bool underscoring); // Check for ambiguous USE associations bool HadUseError(SemanticsContext &, SourceName at, const Symbol *); -/// Checks if the assignment statement has a single variable on the RHS. -inline bool checkForSingleVariableOnRHS( - const Fortran::parser::AssignmentStmt &assignmentStmt) { - const Fortran::parser::Expr &expr{ - std::get(assignmentStmt.t)}; - const Fortran::common::Indirection *designator = - std::get_if>( - &expr.u); - return designator != nullptr; -} - -/// Checks if the symbol on the LHS is present in the RHS expression. -inline bool checkForSymbolMatch(const Fortran::semantics::SomeExpr *lhs, - const Fortran::semantics::SomeExpr *rhs) { - auto lhsSyms{Fortran::evaluate::GetSymbolVector(*lhs)}; - const Fortran::semantics::Symbol &lhsSymbol{*lhsSyms.front()}; - for (const Fortran::semantics::Symbol &symbol : - Fortran::evaluate::GetSymbolVector(*rhs)) { - if (lhsSymbol == symbol) { - return true; - } +// 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 false; + 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 3f6d825e2b66c..ea0845b7d605f 100644 --- a/flang/include/flang/Support/Fortran-features.h +++ b/flang/include/flang/Support/Fortran-features.h @@ -55,7 +55,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, SavedLocalInSpecExpr, PrintNamelist, AssumedRankPassedToNonAssumedRank, IgnoreIrrelevantAttributes, Unsigned, AmbiguousStructureConstructor, ContiguousOkForSeqAssociation, ForwardRefExplicitTypeDummy, - InaccessibleDeferredOverride) + InaccessibleDeferredOverride, CudaWarpMatchFunction) // Portability and suspicious usage warnings ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, diff --git a/flang/include/flang/Support/OpenMP-features.h b/flang/include/flang/Support/OpenMP-features.h index 1dd7ea560cc96..349cd19c1224f 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/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 15bcff254756e..147849b0b7d2a 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)) { diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 1c8a419188b89..d684eeb696755 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/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 7378118cfef7f..864499e6c3431 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 02dba22c29c7f..69e9c53baa740 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -653,8 +653,8 @@ void genAtomicCapture(Fortran::lower::AbstractConverter &converter, firOpBuilder.createBlock(&(atomicCaptureOp->getRegion(0))); mlir::Block &block = atomicCaptureOp->getRegion(0).back(); firOpBuilder.setInsertionPointToStart(&block); - if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) { - if (Fortran::semantics::checkForSymbolMatch( + if (Fortran::parser::CheckForSingleVariableOnRHS(stmt1)) { + if (Fortran::semantics::CheckForSymbolMatch( Fortran::semantics::GetExpr(stmt2Var), Fortran::semantics::GetExpr(stmt2Expr))) { // Atomic capture construct is of the form [capture-stmt, update-stmt] @@ -2150,6 +2150,70 @@ privatizeIv(Fortran::lower::AbstractConverter &converter, ivPrivate.push_back(privateValue); } +static void determineDefaultLoopParMode( + Fortran::lower::AbstractConverter &converter, mlir::acc::LoopOp &loopOp, + llvm::SmallVector &seqDeviceTypes, + llvm::SmallVector &independentDeviceTypes, + llvm::SmallVector &autoDeviceTypes) { + auto hasDeviceNone = [](mlir::Attribute attr) -> bool { + return mlir::dyn_cast(attr).getValue() == + mlir::acc::DeviceType::None; + }; + bool hasDefaultSeq = llvm::any_of(seqDeviceTypes, hasDeviceNone); + bool hasDefaultIndependent = + llvm::any_of(independentDeviceTypes, hasDeviceNone); + bool hasDefaultAuto = llvm::any_of(autoDeviceTypes, hasDeviceNone); + if (hasDefaultSeq || hasDefaultIndependent || hasDefaultAuto) + return; // Default loop par mode is already specified. + + mlir::Region *currentRegion = + converter.getFirOpBuilder().getBlock()->getParent(); + mlir::Operation *parentOp = mlir::acc::getEnclosingComputeOp(*currentRegion); + const bool isOrphanedLoop = !parentOp; + if (isOrphanedLoop || + mlir::isa_and_present(parentOp)) { + // As per OpenACC 3.3 standard section 2.9.6 independent clause: + // A loop construct with no auto or seq clause is treated as if it has the + // independent clause when it is an orphaned loop construct or its parent + // compute construct is a parallel construct. + independentDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get( + converter.getFirOpBuilder().getContext(), mlir::acc::DeviceType::None)); + } else if (mlir::isa_and_present(parentOp)) { + // Serial construct implies `seq` clause on loop. However, this + // conflicts with parallelism assignment if already set. Therefore check + // that first. + bool hasDefaultGangWorkerOrVector = + loopOp.hasVector() || loopOp.getVectorValue() || loopOp.hasWorker() || + loopOp.getWorkerValue() || loopOp.hasGang() || + loopOp.getGangValue(mlir::acc::GangArgType::Num) || + loopOp.getGangValue(mlir::acc::GangArgType::Dim) || + loopOp.getGangValue(mlir::acc::GangArgType::Static); + if (!hasDefaultGangWorkerOrVector) + seqDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get( + converter.getFirOpBuilder().getContext(), + mlir::acc::DeviceType::None)); + // Since the loop has some parallelism assigned - we cannot assign `seq`. + // However, the `acc.loop` verifier will check that one of seq, independent, + // or auto is marked. Seems reasonable to mark as auto since the OpenACC + // spec does say "If not, or if it is unable to make a determination, it + // must treat the auto clause as if it is a seq clause, and it must + // ignore any gang, worker, or vector clauses on the loop construct" + else + autoDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get( + converter.getFirOpBuilder().getContext(), + mlir::acc::DeviceType::None)); + } else { + // As per OpenACC 3.3 standard section 2.9.7 auto clause: + // When the parent compute construct is a kernels construct, a loop + // construct with no independent or seq clause is treated as if it has the + // auto clause. + assert(mlir::isa_and_present(parentOp) && + "Expected kernels construct"); + autoDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get( + converter.getFirOpBuilder().getContext(), mlir::acc::DeviceType::None)); + } +} + static mlir::acc::LoopOp createLoopOp( Fortran::lower::AbstractConverter &converter, mlir::Location currentLocation, @@ -2482,6 +2546,9 @@ static mlir::acc::LoopOp createLoopOp( loopOp.setTileOperandsSegmentsAttr( builder.getDenseI32ArrayAttr(tileOperandsSegments)); + // Determine the loop's default par mode - either seq, independent, or auto. + determineDefaultLoopParMode(converter, loopOp, seqDeviceTypes, + independentDeviceTypes, autoDeviceTypes); if (!seqDeviceTypes.empty()) loopOp.setSeqAttr(builder.getArrayAttr(seqDeviceTypes)); if (!independentDeviceTypes.empty()) diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 88baad8827e92..bc8fc14bcaeb2 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -727,12 +727,15 @@ class TypeInfo { // 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); diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index f3088b18b77ff..c0c57d1832d4e 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, diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp index f8c68bfc3056a..1b8670b379f82 100644 --- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp +++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp @@ -356,26 +356,26 @@ getSource(const semantics::SemanticsContext &semaCtx, const parser::CharBlock *source = nullptr; auto ompConsVisit = [&](const parser::OpenMPConstruct &x) { - std::visit(common::visitors{ - [&](const parser::OpenMPSectionsConstruct &x) { - source = &std::get<0>(x.t).source; - }, - [&](const parser::OpenMPLoopConstruct &x) { - source = &std::get<0>(x.t).source; - }, - [&](const parser::OpenMPBlockConstruct &x) { - source = &std::get<0>(x.t).source; - }, - [&](const parser::OpenMPCriticalConstruct &x) { - source = &std::get<0>(x.t).source; - }, - [&](const parser::OpenMPAtomicConstruct &x) { - std::visit([&](const auto &x) { source = &x.source; }, - x.u); - }, - [&](const auto &x) { source = &x.source; }, - }, - x.u); + std::visit( + common::visitors{ + [&](const parser::OpenMPSectionsConstruct &x) { + source = &std::get<0>(x.t).source; + }, + [&](const parser::OpenMPLoopConstruct &x) { + source = &std::get<0>(x.t).source; + }, + [&](const parser::OpenMPBlockConstruct &x) { + source = &std::get<0>(x.t).source; + }, + [&](const parser::OpenMPCriticalConstruct &x) { + source = &std::get<0>(x.t).source; + }, + [&](const parser::OpenMPAtomicConstruct &x) { + source = &std::get(x.t).source; + }, + [&](const auto &x) { source = &x.source; }, + }, + x.u); }; eval.visit(common::visitors{ diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 6892e571e62a3..3e865a1ee7185 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -41,10 +41,13 @@ #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 //===----------------------------------------------------------------------===// @@ -198,6 +201,8 @@ class HostEvalInfo { /// 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. /// @@ -1122,6 +1127,16 @@ 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 //===----------------------------------------------------------------------===// @@ -2207,8 +2222,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, @@ -2655,6 +2674,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, @@ -2676,645 +2696,215 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, //===----------------------------------------------------------------------===// // Code generation for atomic operations //===----------------------------------------------------------------------===// +static fir::FirOpBuilder::InsertPoint +getInsertionPointBefore(mlir::Operation *op) { + return fir::FirOpBuilder::InsertPoint(op->getBlock(), + mlir::Block::iterator(op)); +} -/// Populates \p hint and \p memoryOrder with appropriate clause information -/// if present on atomic construct. -static void genOmpAtomicHintAndMemoryOrderClauses( - lower::AbstractConverter &converter, - const parser::OmpAtomicClauseList &clauseList, mlir::IntegerAttr &hint, - mlir::omp::ClauseMemoryOrderKindAttr &memoryOrder) { - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - for (const parser::OmpAtomicClause &clause : clauseList.v) { - common::visit( - common::visitors{ - [&](const parser::OmpMemoryOrderClause &s) { - auto kind = common::visit( - common::visitors{ - [&](const parser::OmpClause::AcqRel &) { - return mlir::omp::ClauseMemoryOrderKind::Acq_rel; - }, - [&](const parser::OmpClause::Acquire &) { - return mlir::omp::ClauseMemoryOrderKind::Acquire; - }, - [&](const parser::OmpClause::Relaxed &) { - return mlir::omp::ClauseMemoryOrderKind::Relaxed; - }, - [&](const parser::OmpClause::Release &) { - return mlir::omp::ClauseMemoryOrderKind::Release; - }, - [&](const parser::OmpClause::SeqCst &) { - return mlir::omp::ClauseMemoryOrderKind::Seq_cst; - }, - [&](auto &&) -> mlir::omp::ClauseMemoryOrderKind { - llvm_unreachable("Unexpected clause"); - }, - }, - s.v.u); - memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get( - firOpBuilder.getContext(), kind); - }, - [&](const parser::OmpHintClause &s) { - const auto *expr = semantics::GetExpr(s.v); - uint64_t hintExprValue = *evaluate::ToInt64(*expr); - hint = firOpBuilder.getI64IntegerAttr(hintExprValue); - }, - [&](const parser::OmpFailClause &) {}, - }, - clause.u); +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 void processOmpAtomicTODO(mlir::Type elementType, mlir::Location loc) { - if (!elementType) - return; - assert(fir::isa_trivial(fir::unwrapRefType(elementType)) && - "is supported type for omp atomic"); -} - -/// Used to generate atomic.read operation which is created in existing -/// location set by builder. -static void genAtomicCaptureStatement( - lower::AbstractConverter &converter, mlir::Value fromAddress, - mlir::Value toAddress, - const parser::OmpAtomicClauseList *leftHandClauseList, - const parser::OmpAtomicClauseList *rightHandClauseList, - mlir::Type elementType, mlir::Location loc) { - // Generate `atomic.read` operation for atomic assigment statements - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); +static mlir::omp::ClauseMemoryOrderKindAttr +getAtomicMemoryOrder(lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, + const List &clauses) { + std::optional kind; + unsigned version = semaCtx.langOptions().OpenMPVersion; - processOmpAtomicTODO(elementType, loc); - - // If no hint clause is specified, the effect is as if - // hint(omp_sync_hint_none) had been specified. - mlir::IntegerAttr hint = nullptr; - - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - if (leftHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint, - memoryOrder); - if (rightHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, - memoryOrder); - firOpBuilder.create(loc, fromAddress, toAddress, - mlir::TypeAttr::get(elementType), - hint, memoryOrder); -} - -/// Used to generate atomic.write operation which is created in existing -/// location set by builder. -static void genAtomicWriteStatement( - lower::AbstractConverter &converter, mlir::Value lhsAddr, - mlir::Value rhsExpr, const parser::OmpAtomicClauseList *leftHandClauseList, - const parser::OmpAtomicClauseList *rightHandClauseList, mlir::Location loc, - mlir::Value *evaluatedExprValue = nullptr) { - // Generate `atomic.write` operation for atomic assignment statements - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + 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; + } + } - mlir::Type varType = fir::unwrapRefType(lhsAddr.getType()); - // Create a conversion outside the capture block. - auto insertionPoint = firOpBuilder.saveInsertionPoint(); - firOpBuilder.setInsertionPointAfter(rhsExpr.getDefiningOp()); - rhsExpr = firOpBuilder.createConvert(loc, varType, rhsExpr); - firOpBuilder.restoreInsertionPoint(insertionPoint); - - processOmpAtomicTODO(varType, loc); - - // If no hint clause is specified, the effect is as if - // hint(omp_sync_hint_none) had been specified. - mlir::IntegerAttr hint = nullptr; - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - if (leftHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint, - memoryOrder); - if (rightHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, - memoryOrder); - firOpBuilder.create(loc, lhsAddr, rhsExpr, hint, - memoryOrder); -} - -/// Used to generate atomic.update operation which is created in existing -/// location set by builder. -static void genAtomicUpdateStatement( - lower::AbstractConverter &converter, mlir::Value lhsAddr, - mlir::Type varType, const parser::Variable &assignmentStmtVariable, - const parser::Expr &assignmentStmtExpr, - const parser::OmpAtomicClauseList *leftHandClauseList, - const parser::OmpAtomicClauseList *rightHandClauseList, mlir::Location loc, - mlir::Operation *atomicCaptureOp = nullptr, - lower::StatementContext *atomicCaptureStmtCtx = nullptr) { - // Generate `atomic.update` operation for atomic assignment statements - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - mlir::Location currentLocation = converter.getCurrentLocation(); + // 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"); + }(); - // Create the omp.atomic.update or acc.atomic.update operation - // - // func.func @_QPsb() { - // %0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFsbEa"} - // %1 = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFsbEb"} - // %2 = fir.load %1 : !fir.ref - // omp.atomic.update %0 : !fir.ref { - // ^bb0(%arg0: i32): - // %3 = arith.addi %arg0, %2 : i32 - // omp.yield(%3 : i32) - // } - // return - // } - - auto getArgExpression = - [](std::list::const_iterator it) { - const auto &arg{std::get((*it).t)}; - const auto *parserExpr{ - std::get_if>(&arg.u)}; - return parserExpr; - }; + 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(); - // Lower any non atomic sub-expression before the atomic operation, and - // map its lowered value to the semantic representation. - lower::ExprToValueMap exprValueOverrides; - // Max and min intrinsics can have a list of Args. Hence we need a list - // of nonAtomicSubExprs to hoist. Currently, only the load is hoisted. - llvm::SmallVector nonAtomicSubExprs; - common::visit( - common::visitors{ - [&](const common::Indirection &funcRef) - -> void { - const auto &args{std::get>( - funcRef.value().v.t)}; - std::list::const_iterator beginIt = - args.begin(); - std::list::const_iterator endIt = args.end(); - const auto *exprFirst{getArgExpression(beginIt)}; - if (exprFirst && exprFirst->value().source == - assignmentStmtVariable.GetSource()) { - // Add everything except the first - beginIt++; - } else { - // Add everything except the last - endIt--; - } - std::list::const_iterator it; - for (it = beginIt; it != endIt; it++) { - const common::Indirection *expr = - getArgExpression(it); - if (expr) - nonAtomicSubExprs.push_back(semantics::GetExpr(*expr)); - } - }, - [&](const auto &op) -> void { - using T = std::decay_t; - if constexpr (std::is_base_of::value) { - const auto &exprLeft{std::get<0>(op.t)}; - const auto &exprRight{std::get<1>(op.t)}; - if (exprLeft.value().source == assignmentStmtVariable.GetSource()) - nonAtomicSubExprs.push_back(semantics::GetExpr(exprRight)); - else - nonAtomicSubExprs.push_back(semantics::GetExpr(exprLeft)); - } - }, - }, - assignmentStmtExpr.u); - lower::StatementContext nonAtomicStmtCtx; - lower::StatementContext *stmtCtxPtr = &nonAtomicStmtCtx; - if (!nonAtomicSubExprs.empty()) { - // Generate non atomic part before all the atomic operations. - auto insertionPoint = firOpBuilder.saveInsertionPoint(); - if (atomicCaptureOp) { - assert(atomicCaptureStmtCtx && "must specify statement context"); - firOpBuilder.setInsertionPoint(atomicCaptureOp); - // Any clean-ups associated with the expression lowering - // must also be generated outside of the atomic update operation - // and after the atomic capture operation. - // The atomicCaptureStmtCtx will be finalized at the end - // of the atomic capture operation generation. - stmtCtxPtr = atomicCaptureStmtCtx; - } - mlir::Value nonAtomicVal; - for (auto *nonAtomicSubExpr : nonAtomicSubExprs) { - nonAtomicVal = fir::getBase(converter.genExprValue( - currentLocation, *nonAtomicSubExpr, *stmtCtxPtr)); - exprValueOverrides.try_emplace(nonAtomicSubExpr, nonAtomicVal); - } - if (atomicCaptureOp) - firOpBuilder.restoreInsertionPoint(insertionPoint); + builder.create(loc, value, storeAddr); } + return op; +} - mlir::Operation *atomicUpdateOp = nullptr; - // If no hint clause is specified, the effect is as if - // hint(omp_sync_hint_none) had been specified. - mlir::IntegerAttr hint = nullptr; - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - if (leftHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint, - memoryOrder); - if (rightHandClauseList) - genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, - memoryOrder); - atomicUpdateOp = firOpBuilder.create( - currentLocation, lhsAddr, hint, memoryOrder); - - processOmpAtomicTODO(varType, loc); - - llvm::SmallVector varTys = {varType}; - llvm::SmallVector locs = {currentLocation}; - firOpBuilder.createBlock(&atomicUpdateOp->getRegion(0), {}, varTys, locs); - mlir::Value val = - fir::getBase(atomicUpdateOp->getRegion(0).front().getArgument(0)); - - exprValueOverrides.try_emplace(semantics::GetExpr(assignmentStmtVariable), - val); - { - // statement context inside the atomic block. - converter.overrideExprValues(&exprValueOverrides); - lower::StatementContext atomicStmtCtx; - mlir::Value rhsExpr = fir::getBase(converter.genExprValue( - *semantics::GetExpr(assignmentStmtExpr), atomicStmtCtx)); - mlir::Type exprType = fir::unwrapRefType(rhsExpr.getType()); - if (fir::isa_complex(exprType) && !fir::isa_complex(varType)) { - // Emit an additional `ExtractValueOp` if the expression is of complex - // type - auto extract = firOpBuilder.create( - currentLocation, - mlir::cast(exprType).getElementType(), rhsExpr, - firOpBuilder.getArrayAttr( - firOpBuilder.getIntegerAttr(firOpBuilder.getIndexType(), 0))); - mlir::Value convertResult = firOpBuilder.create( - currentLocation, varType, extract); - firOpBuilder.create(currentLocation, convertResult); - } else { - mlir::Value convertResult = - firOpBuilder.createConvert(currentLocation, varType, rhsExpr); - firOpBuilder.create(currentLocation, convertResult); +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); } - converter.resetExprOverrides(); } - firOpBuilder.setInsertionPointAfter(atomicUpdateOp); -} - -/// Processes an atomic construct with write clause. -static void genAtomicWrite(lower::AbstractConverter &converter, - const parser::OmpAtomicWrite &atomicWrite, - mlir::Location loc) { - const parser::OmpAtomicClauseList *rightHandClauseList = nullptr; - const parser::OmpAtomicClauseList *leftHandClauseList = nullptr; - // Get the address of atomic read operands. - rightHandClauseList = &std::get<2>(atomicWrite.t); - leftHandClauseList = &std::get<0>(atomicWrite.t); - - const parser::AssignmentStmt &stmt = - std::get>(atomicWrite.t) - .statement; - const evaluate::Assignment &assign = *stmt.typedAssignment->v; - lower::StatementContext stmtCtx; - // Get the value and address of atomic write operands. - mlir::Value rhsExpr = - fir::getBase(converter.genExprValue(assign.rhs, stmtCtx)); - mlir::Value lhsAddr = - fir::getBase(converter.genExprAddr(assign.lhs, stmtCtx)); - genAtomicWriteStatement(converter, lhsAddr, rhsExpr, leftHandClauseList, - rightHandClauseList, loc); -} - -/* - Emit an implicit cast. Different yet compatible types on - omp.atomic.read constitute valid Fortran. The OMPIRBuilder will - emit atomic instructions (on primitive types) and `__atomic_load` - libcall (on complex type) without explicitly converting - between such compatible types. The OMPIRBuilder relies on the - frontend to resolve such inconsistencies between `omp.atomic.read ` - operand types. Similar inconsistencies between operand types in - `omp.atomic.write` are resolved through implicit casting by use of typed - assignment (i.e. `evaluate::Assignment`). However, use of typed - assignment in `omp.atomic.read` (of form `v = x`) leads to an unsafe, - non-atomic load of `x` into a temporary `alloca`, followed by an atomic - read of form `v = alloca`. Hence, it is needed to perform a custom - implicit cast. - - An atomic read of form `v = x` would (without implicit casting) - lower to `omp.atomic.read %v = %x : !fir.ref, !fir.ref, - type2`. This implicit casting will rather generate the following FIR: - - %alloca = fir.alloca type2 - omp.atomic.read %alloca = %x : !fir.ref, !fir.ref, type2 - %load = fir.load %alloca : !fir.ref - %cvt = fir.convert %load : (type2) -> type1 - fir.store %cvt to %v : !fir.ref - - These sequence of operations is thread-safe since each thread allocates - the `alloca` in its stack, and performs `%alloca = %x` atomically. Once - safely read, each thread performs the implicit cast on the local - `alloca`, and writes the final result to `%v`. - -/// \param builder : FirOpBuilder -/// \param loc : Location for FIR generation -/// \param toAddress : Address of %v -/// \param toType : Type of %v -/// \param fromType : Type of %x -/// \param alloca : Thread scoped `alloca` -// It is the responsibility of the callee -// to position the `alloca` at `AllocaIP` -// through `builder.getAllocaBlock()` -*/ - -static void emitAtomicReadImplicitCast(fir::FirOpBuilder &builder, - mlir::Location loc, - mlir::Value toAddress, mlir::Type toType, - mlir::Type fromType, - mlir::Value alloca) { - auto load = builder.create(loc, alloca); - if (fir::isa_complex(fromType) && !fir::isa_complex(toType)) { - // Emit an additional `ExtractValueOp` if `fromAddress` is of complex - // type, but `toAddress` is not. - auto extract = builder.create( - loc, mlir::cast(fromType).getElementType(), load, - builder.getArrayAttr( - builder.getIntegerAttr(builder.getIndexType(), 0))); - auto cvt = builder.create(loc, toType, extract); - builder.create(loc, cvt, toAddress); - } else if (!fir::isa_complex(fromType) && fir::isa_complex(toType)) { - // Emit an additional `InsertValueOp` if `toAddress` is of complex - // type, but `fromAddress` is not. - mlir::Value undef = builder.create(loc, toType); - mlir::Type complexEleTy = - mlir::cast(toType).getElementType(); - mlir::Value cvt = builder.create(loc, complexEleTy, load); - mlir::Value zero = builder.createRealZeroConstant(loc, complexEleTy); - mlir::Value idx0 = builder.create( - loc, toType, undef, cvt, - builder.getArrayAttr( - builder.getIntegerAttr(builder.getIndexType(), 0))); - mlir::Value idx1 = builder.create( - loc, toType, idx0, zero, - builder.getArrayAttr( - builder.getIntegerAttr(builder.getIndexType(), 1))); - builder.create(loc, idx1, toAddress); - } else { - auto cvt = builder.create(loc, toType, load); - builder.create(loc, cvt, toAddress); - } -} -/// Processes an atomic construct with read clause. -static void genAtomicRead(lower::AbstractConverter &converter, - const parser::OmpAtomicRead &atomicRead, - mlir::Location loc) { - const parser::OmpAtomicClauseList *rightHandClauseList = nullptr; - const parser::OmpAtomicClauseList *leftHandClauseList = nullptr; - // Get the address of atomic read operands. - rightHandClauseList = &std::get<2>(atomicRead.t); - leftHandClauseList = &std::get<0>(atomicRead.t); + builder.restoreInsertionPoint(atomicAt); + auto updateOp = + builder.create(loc, atomAddr, hint, memOrder); - const auto &assignmentStmtExpr = std::get( - std::get>(atomicRead.t) - .statement.t); - const auto &assignmentStmtVariable = std::get( - std::get>(atomicRead.t) - .statement.t); + 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); - lower::StatementContext stmtCtx; - const semantics::SomeExpr &fromExpr = *semantics::GetExpr(assignmentStmtExpr); - mlir::Type elementType = converter.genType(fromExpr); - mlir::Value fromAddress = - fir::getBase(converter.genExprAddr(fromExpr, stmtCtx)); - mlir::Value toAddress = fir::getBase(converter.genExprAddr( - *semantics::GetExpr(assignmentStmtVariable), stmtCtx)); - - if (fromAddress.getType() != toAddress.getType()) { - - mlir::Type toType = fir::unwrapRefType(toAddress.getType()); - mlir::Type fromType = fir::unwrapRefType(fromAddress.getType()); - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - auto oldIP = builder.saveInsertionPoint(); - builder.setInsertionPointToStart(builder.getAllocaBlock()); - mlir::Value alloca = builder.create( - loc, fromType); // Thread scope `alloca` to atomically read `%x`. - builder.restoreInsertionPoint(oldIP); - genAtomicCaptureStatement(converter, fromAddress, alloca, - leftHandClauseList, rightHandClauseList, - elementType, loc); - emitAtomicReadImplicitCast(builder, loc, toAddress, toType, fromType, - alloca); - } else - genAtomicCaptureStatement(converter, fromAddress, toAddress, - leftHandClauseList, rightHandClauseList, - elementType, loc); -} - -/// Processes an atomic construct with update clause. -static void genAtomicUpdate(lower::AbstractConverter &converter, - const parser::OmpAtomicUpdate &atomicUpdate, - mlir::Location loc) { - const parser::OmpAtomicClauseList *rightHandClauseList = nullptr; - const parser::OmpAtomicClauseList *leftHandClauseList = nullptr; - // Get the address of atomic read operands. - rightHandClauseList = &std::get<2>(atomicUpdate.t); - leftHandClauseList = &std::get<0>(atomicUpdate.t); - - const auto &assignmentStmtExpr = std::get( - std::get>(atomicUpdate.t) - .statement.t); - const auto &assignmentStmtVariable = std::get( - std::get>(atomicUpdate.t) - .statement.t); + 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(); - lower::StatementContext stmtCtx; - mlir::Value lhsAddr = fir::getBase(converter.genExprAddr( - *semantics::GetExpr(assignmentStmtVariable), stmtCtx)); - mlir::Type varType = fir::unwrapRefType(lhsAddr.getType()); - genAtomicUpdateStatement(converter, lhsAddr, varType, assignmentStmtVariable, - assignmentStmtExpr, leftHandClauseList, - rightHandClauseList, loc); -} - -/// Processes an atomic construct with no clause - which implies update clause. -static void genOmpAtomic(lower::AbstractConverter &converter, - const parser::OmpAtomic &atomicConstruct, - mlir::Location loc) { - const parser::OmpAtomicClauseList &atomicClauseList = - std::get(atomicConstruct.t); - const auto &assignmentStmtExpr = std::get( - std::get>(atomicConstruct.t) - .statement.t); - const auto &assignmentStmtVariable = std::get( - std::get>(atomicConstruct.t) - .statement.t); - lower::StatementContext stmtCtx; - mlir::Value lhsAddr = fir::getBase(converter.genExprAddr( - *semantics::GetExpr(assignmentStmtVariable), stmtCtx)); - mlir::Type varType = fir::unwrapRefType(lhsAddr.getType()); - // If atomic-clause is not present on the construct, the behaviour is as if - // the update clause is specified (for both OpenMP and OpenACC). - genAtomicUpdateStatement(converter, lhsAddr, varType, assignmentStmtVariable, - assignmentStmtExpr, &atomicClauseList, nullptr, loc); -} - -/// Processes an atomic construct with capture clause. -static void genAtomicCapture(lower::AbstractConverter &converter, - const parser::OmpAtomicCapture &atomicCapture, - mlir::Location loc) { - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + builder.restoreInsertionPoint(postAt); // For naCtx cleanups + return updateOp; +} - const parser::AssignmentStmt &stmt1 = - std::get(atomicCapture.t).v.statement; - const evaluate::Assignment &assign1 = *stmt1.typedAssignment->v; - const auto &stmt1Var{std::get(stmt1.t)}; - const auto &stmt1Expr{std::get(stmt1.t)}; - const parser::AssignmentStmt &stmt2 = - std::get(atomicCapture.t).v.statement; - const evaluate::Assignment &assign2 = *stmt2.typedAssignment->v; - const auto &stmt2Var{std::get(stmt2.t)}; - const auto &stmt2Expr{std::get(stmt2.t)}; - - // Pre-evaluate expressions to be used in the various operations inside - // `atomic.capture` since it is not desirable to have anything other than - // a `atomic.read`, `atomic.write`, or `atomic.update` operation - // inside `atomic.capture` - lower::StatementContext stmtCtx; - // LHS evaluations are common to all combinations of `atomic.capture` - mlir::Value stmt1LHSArg = - fir::getBase(converter.genExprAddr(assign1.lhs, stmtCtx)); - mlir::Value stmt2LHSArg = - fir::getBase(converter.genExprAddr(assign2.lhs, stmtCtx)); - - // Type information used in generation of `atomic.update` operation - mlir::Type stmt1VarType = - fir::getBase(converter.genExprValue(assign1.lhs, stmtCtx)).getType(); - mlir::Type stmt2VarType = - fir::getBase(converter.genExprValue(assign2.lhs, stmtCtx)).getType(); - - mlir::Operation *atomicCaptureOp = nullptr; - mlir::IntegerAttr hint = nullptr; - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - const parser::OmpAtomicClauseList &rightHandClauseList = - std::get<2>(atomicCapture.t); - const parser::OmpAtomicClauseList &leftHandClauseList = - std::get<0>(atomicCapture.t); - genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint, - memoryOrder); - genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint, - memoryOrder); - atomicCaptureOp = - firOpBuilder.create(loc, hint, memoryOrder); - - firOpBuilder.createBlock(&(atomicCaptureOp->getRegion(0))); - mlir::Block &block = atomicCaptureOp->getRegion(0).back(); - firOpBuilder.setInsertionPointToStart(&block); - if (semantics::checkForSingleVariableOnRHS(stmt1)) { - if (semantics::checkForSymbolMatch(semantics::GetExpr(stmt2Var), - semantics::GetExpr(stmt2Expr))) { - // Atomic capture construct is of the form [capture-stmt, update-stmt] - const semantics::SomeExpr &fromExpr = *semantics::GetExpr(stmt1Expr); - mlir::Type elementType = converter.genType(fromExpr); - if (stmt1VarType != stmt2VarType) { - mlir::Value alloca; - mlir::Type toType = fir::unwrapRefType(stmt1LHSArg.getType()); - mlir::Type fromType = fir::unwrapRefType(stmt2LHSArg.getType()); - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); - alloca = firOpBuilder.create(loc, fromType); - } - genAtomicCaptureStatement(converter, stmt2LHSArg, alloca, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointAfter(atomicCaptureOp); - emitAtomicReadImplicitCast(firOpBuilder, loc, stmt1LHSArg, toType, - fromType, alloca); - } - } else { - genAtomicCaptureStatement(converter, stmt2LHSArg, stmt1LHSArg, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - } - genAtomicUpdateStatement( - converter, stmt2LHSArg, stmt2VarType, stmt2Var, stmt2Expr, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, loc, atomicCaptureOp, &stmtCtx); - } else { - // Atomic capture construct is of the form [capture-stmt, write-stmt] - firOpBuilder.setInsertionPoint(atomicCaptureOp); - mlir::Value stmt2RHSArg = - fir::getBase(converter.genExprValue(assign2.rhs, stmtCtx)); - firOpBuilder.setInsertionPointToStart(&block); - const semantics::SomeExpr &fromExpr = *semantics::GetExpr(stmt1Expr); - mlir::Type elementType = converter.genType(fromExpr); - - if (stmt1VarType != stmt2VarType) { - mlir::Value alloca; - mlir::Type toType = fir::unwrapRefType(stmt1LHSArg.getType()); - mlir::Type fromType = fir::unwrapRefType(stmt2LHSArg.getType()); - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); - alloca = firOpBuilder.create(loc, fromType); - } - genAtomicCaptureStatement(converter, stmt2LHSArg, alloca, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointAfter(atomicCaptureOp); - emitAtomicReadImplicitCast(firOpBuilder, loc, stmt1LHSArg, toType, - fromType, alloca); - } - } else { - genAtomicCaptureStatement(converter, stmt2LHSArg, stmt1LHSArg, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - } - genAtomicWriteStatement(converter, stmt2LHSArg, stmt2RHSArg, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, loc); - } - } else { - // Atomic capture construct is of the form [update-stmt, capture-stmt] - const semantics::SomeExpr &fromExpr = *semantics::GetExpr(stmt2Expr); - mlir::Type elementType = converter.genType(fromExpr); - genAtomicUpdateStatement( - converter, stmt1LHSArg, stmt1VarType, stmt1Var, stmt1Expr, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, loc, atomicCaptureOp, &stmtCtx); - - if (stmt1VarType != stmt2VarType) { - mlir::Value alloca; - mlir::Type toType = fir::unwrapRefType(stmt2LHSArg.getType()); - mlir::Type fromType = fir::unwrapRefType(stmt1LHSArg.getType()); - - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); - alloca = firOpBuilder.create(loc, fromType); - } +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"); + } - genAtomicCaptureStatement(converter, stmt1LHSArg, alloca, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - { - mlir::OpBuilder::InsertionGuard guard(firOpBuilder); - firOpBuilder.setInsertionPointAfter(atomicCaptureOp); - emitAtomicReadImplicitCast(firOpBuilder, loc, stmt2LHSArg, toType, - fromType, alloca); - } - } else { - genAtomicCaptureStatement(converter, stmt1LHSArg, stmt2LHSArg, - /*leftHandClauseList=*/nullptr, - /*rightHandClauseList=*/nullptr, elementType, - loc); - } + // 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; } - firOpBuilder.setInsertionPointToEnd(&block); - firOpBuilder.create(loc); - // The clean-ups associated with the statements inside the capture - // construct must be generated after the AtomicCaptureOp. - firOpBuilder.setInsertionPointAfter(atomicCaptureOp); } //===----------------------------------------------------------------------===// @@ -3392,6 +2982,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, @@ -3875,10 +3466,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 = @@ -4212,10 +3800,6 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, standaloneConstruct.u); } -//===----------------------------------------------------------------------===// -// OpenMPConstruct visitors -//===----------------------------------------------------------------------===// - static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, @@ -4223,38 +3807,166 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct"); } +//===----------------------------------------------------------------------===// +// 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 &atomicConstruct) { - Fortran::common::visit( - common::visitors{ - [&](const parser::OmpAtomicRead &atomicRead) { - mlir::Location loc = converter.genLocation(atomicRead.source); - genAtomicRead(converter, atomicRead, loc); - }, - [&](const parser::OmpAtomicWrite &atomicWrite) { - mlir::Location loc = converter.genLocation(atomicWrite.source); - genAtomicWrite(converter, atomicWrite, loc); - }, - [&](const parser::OmpAtomic &atomicConstruct) { - mlir::Location loc = converter.genLocation(atomicConstruct.source); - genOmpAtomic(converter, atomicConstruct, loc); - }, - [&](const parser::OmpAtomicUpdate &atomicUpdate) { - mlir::Location loc = converter.genLocation(atomicUpdate.source); - genAtomicUpdate(converter, atomicUpdate, loc); - }, - [&](const parser::OmpAtomicCapture &atomicCapture) { - mlir::Location loc = converter.genLocation(atomicCapture.source); - genAtomicCapture(converter, atomicCapture, loc); - }, - [&](const parser::OmpAtomicCompare &atomicCompare) { - mlir::Location loc = converter.genLocation(atomicCompare.source); - TODO(loc, "OpenMP atomic compare"); - }, - }, - atomicConstruct.u); + 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"); + (void)action0; + (void)action1; + 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); + } + } + } } static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, @@ -4423,8 +4135,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(); @@ -4436,22 +4146,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/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp b/flang/lib/Optimizer/Builder/Runtime/CUDA/Descriptor.cpp index 90662c094c65e..a943469a76728 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 82b11ad7db32a..69bdb48146a54 100644 --- a/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp +++ b/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp @@ -274,12 +274,12 @@ class BoxedProcedurePass 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 82d960a6fc61e..a3de3ae9d116a 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/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 6181e1fad4240..ecfa2939e96a6 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/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp index 0fdb302fe10ca..28f6c8bf02813 100644 --- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp +++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp @@ -7,9 +7,11 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/OpenMP/Passes.h" #include "flang/Optimizer/OpenMP/Utils.h" +#include "flang/Support/OpenMP-utils.h" #include "mlir/Analysis/SliceAnalysis.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/IRMapping.h" @@ -308,10 +310,68 @@ class DoConcurrentConversion fir::DoConcurrentLoopOp loop, mlir::IRMapping &mapper, const mlir::omp::LoopNestOperands &clauseOps, bool isComposite) const { + mlir::omp::WsloopOperands wsloopClauseOps; + + // For `local` (and `local_init`) opernads, emit corresponding `private` + // clauses and attach these clauses to the workshare loop. + if (!loop.getLocalOperands().empty()) + for (auto [op, sym, arg] : llvm::zip_equal( + loop.getLocalOperands(), + loop.getLocalSymsAttr().getAsRange(), + loop.getRegionLocalArgs())) { + auto localizer = mlir::SymbolTable::lookupNearestSymbolFrom< + fir::LocalitySpecifierOp>(loop, sym); + if (localizer.getLocalitySpecifierType() == + fir::LocalitySpecifierType::LocalInit) + TODO(localizer.getLoc(), + "local_init conversion is not supported yet"); + + auto oldIP = rewriter.saveInsertionPoint(); + rewriter.setInsertionPointAfter(localizer); + auto privatizer = rewriter.create( + localizer.getLoc(), sym.getLeafReference().str() + ".omp", + localizer.getTypeAttr().getValue(), + mlir::omp::DataSharingClauseType::Private); + + if (!localizer.getInitRegion().empty()) { + rewriter.cloneRegionBefore(localizer.getInitRegion(), + privatizer.getInitRegion(), + privatizer.getInitRegion().begin()); + auto firYield = mlir::cast( + privatizer.getInitRegion().back().getTerminator()); + rewriter.setInsertionPoint(firYield); + rewriter.create(firYield.getLoc(), + firYield.getOperands()); + rewriter.eraseOp(firYield); + } + + if (!localizer.getDeallocRegion().empty()) { + rewriter.cloneRegionBefore(localizer.getDeallocRegion(), + privatizer.getDeallocRegion(), + privatizer.getDeallocRegion().begin()); + auto firYield = mlir::cast( + privatizer.getDeallocRegion().back().getTerminator()); + rewriter.setInsertionPoint(firYield); + rewriter.create(firYield.getLoc(), + firYield.getOperands()); + rewriter.eraseOp(firYield); + } + + rewriter.restoreInsertionPoint(oldIP); - auto wsloopOp = rewriter.create(loop.getLoc()); + wsloopClauseOps.privateVars.push_back(op); + wsloopClauseOps.privateSyms.push_back( + mlir::SymbolRefAttr::get(privatizer)); + } + + auto wsloopOp = + rewriter.create(loop.getLoc(), wsloopClauseOps); wsloopOp.setComposite(isComposite); - rewriter.createBlock(&wsloopOp.getRegion()); + + Fortran::common::openmp::EntryBlockArgs wsloopArgs; + wsloopArgs.priv.vars = wsloopClauseOps.privateVars; + Fortran::common::openmp::genEntryBlock(rewriter, wsloopArgs, + wsloopOp.getRegion()); auto loopNestOp = rewriter.create(loop.getLoc(), clauseOps); @@ -324,6 +384,18 @@ class DoConcurrentConversion rewriter.setInsertionPointToEnd(&loopNestOp.getRegion().back()); rewriter.create(loop->getLoc()); + // `local` region arguments are transferred/cloned from the `do concurrent` + // loop to the loopnest op when the region is cloned above. Instead, these + // region arguments should be on the workshare loop's region. + for (auto [wsloopArg, loopNestArg] : + llvm::zip_equal(wsloopOp.getRegion().getArguments(), + loopNestOp.getRegion().getArguments().drop_front( + clauseOps.loopLowerBounds.size()))) + rewriter.replaceAllUsesWith(loopNestArg, wsloopArg); + + for (unsigned i = 0; i < loop.getLocalVars().size(); ++i) + loopNestOp.getRegion().eraseArgument(clauseOps.loopLowerBounds.size()); + return loopNestOp; } diff --git a/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp b/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp index 8a9e9b80134b8..3d35803e6a2d3 100644 --- a/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp +++ b/flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp @@ -212,9 +212,12 @@ class CfgIfConv : public mlir::OpRewritePattern { } 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 cb9e48cced2a1..e440852b3103a 100644 --- a/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp +++ b/flang/lib/Optimizer/Transforms/SimplifyFIROperations.cpp @@ -180,41 +180,50 @@ class DoConcurrentConversion 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(); - - rewriter.eraseOp(copyRegionBody->getTerminator()); - rewriter.mergeBlocks(afterLocalInit, copyRegionBody); - rewriter.mergeBlocks(copyRegionBody, beforeLocalInit, - {localVar, localArg}); - } + 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); + }; + + 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 08326fad8c143..c55642d969503 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -24,6 +24,12 @@ // OpenMP Directives and Clauses namespace Fortran::parser { +// Helper function to print the buffer contents starting at the current point. +[[maybe_unused]] static std::string ahead(const ParseState &state) { + return std::string( + state.GetLocation(), std::min(64, state.BytesRemaining())); +} + constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; @@ -941,8 +947,10 @@ TYPE_PARSER( // parenthesized(Parser{}))) || "BIND" >> construct(construct( parenthesized(Parser{}))) || + "CAPTURE" >> construct(construct()) || "COLLAPSE" >> construct(construct( parenthesized(scalarIntConstantExpr))) || + "COMPARE" >> construct(construct()) || "CONTAINS" >> construct(construct( parenthesized(Parser{}))) || "COPYIN" >> construct(construct( @@ -996,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( @@ -1062,6 +1072,7 @@ TYPE_PARSER( // "TASK_REDUCTION" >> construct(construct( parenthesized(Parser{}))) || + "READ" >> construct(construct()) || "RELAXED" >> construct(construct()) || "RELEASE" >> construct(construct()) || "REVERSE_OFFLOAD" >> @@ -1105,6 +1116,7 @@ TYPE_PARSER( // maybe(Parser{}))) || "WHEN" >> construct(construct( parenthesized(Parser{}))) || + "WRITE" >> construct(construct()) || // Cancellable constructs construct(construct( Parser{}))) @@ -1223,6 +1235,155 @@ TYPE_PARSER(sourced(construct(first( TYPE_PARSER(sourced(construct( sourced(Parser{}), Parser{}))) +struct OmpEndDirectiveParser { + using resultType = OmpDirectiveSpecification; + + constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) : dir_(dir) {} + + std::optional Parse(ParseState &state) const { + if ((startOmpLine >> "END"_sptok).Parse(state)) { + auto &&dirSpec{Parser{}.Parse(state)}; + if (dirSpec && dirSpec->DirId() == dir_) { + return std::move(dirSpec); + } + } + return std::nullopt; + } + +private: + llvm::omp::Directive dir_; +}; + +// Parser for an arbitrary OpenMP ATOMIC construct. +// +// Depending on circumstances, an ATOMIC construct applies to one or more +// following statements. In certain cases when a single statement is +// expected, the end-directive is optional. The specifics depend on both +// the clauses used, and the form of the executable statement. To emit +// more meaningful messages in case of errors, the exact analysis of the +// structure of the construct will be delayed until semantic checks. +// +// The parser will first try the case when the end-directive is present, +// and will parse at most "BodyLimit" (and potentially zero) constructs +// while looking for the end-directive before it gives up. +// Then it will assume that no end-directive is present, and will try to +// parse a single executable construct as the body of the construct. +// +// The limit on the number of constructs is there to reduce the amount of +// unnecessary parsing when the end-directive is absent. It's higher than +// the maximum number of statements in any valid construct to accept cases +// when extra statements are present by mistake. +// A problem can occur when atomic constructs without end-directive follow +// each other closely, e.g. +// !$omp atomic write +// x = v +// !$omp atomic update +// x = x + 1 +// ... +// The speculative parsing will become "recursive", and has the potential +// to take a (practically) infinite amount of time given a sufficiently +// large number of such constructs in a row. Since atomic constructs cannot +// contain other OpenMP constructs, guarding against recursive calls to the +// atomic construct parser solves the problem. +struct OmpAtomicConstructParser { + using resultType = OpenMPAtomicConstruct; + + static constexpr size_t BodyLimit{5}; + + std::optional Parse(ParseState &state) const { + if (recursing_) { + return std::nullopt; + } + recursing_ = true; + + auto dirSpec{Parser{}.Parse(state)}; + if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_atomic) { + recursing_ = false; + return std::nullopt; + } + + auto exec{Parser{}}; + auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}}; + TailType tail; + + if (ParseOne(exec, end, tail, state)) { + if (!tail.first.empty()) { + if (auto &&rest{attempt(LimitedTailParser(BodyLimit)).Parse(state)}) { + for (auto &&s : rest->first) { + tail.first.emplace_back(std::move(s)); + } + assert(!tail.second); + tail.second = std::move(rest->second); + } + } + recursing_ = false; + return OpenMPAtomicConstruct{ + std::move(*dirSpec), std::move(tail.first), std::move(tail.second)}; + } + + recursing_ = false; + return std::nullopt; + } + +private: + // Begin-directive + TailType = entire construct. + using TailType = std::pair>; + + // Parse either an ExecutionPartConstruct, or atomic end-directive. When + // successful, record the result in the "tail" provided, otherwise fail. + static std::optional ParseOne( // + Parser &exec, OmpEndDirectiveParser &end, + TailType &tail, ParseState &state) { + auto isRecovery{[](const ExecutionPartConstruct &e) { + return std::holds_alternative(e.u); + }}; + if (auto &&stmt{attempt(exec).Parse(state)}; stmt && !isRecovery(*stmt)) { + tail.first.emplace_back(std::move(*stmt)); + } else if (auto &&dir{attempt(end).Parse(state)}) { + tail.second = std::move(*dir); + } else { + return std::nullopt; + } + return Success{}; + } + + struct LimitedTailParser { + using resultType = TailType; + + constexpr LimitedTailParser(size_t count) : count_(count) {} + + std::optional Parse(ParseState &state) const { + auto exec{Parser{}}; + auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}}; + TailType tail; + + for (size_t i{0}; i != count_; ++i) { + if (ParseOne(exec, end, tail, state)) { + if (tail.second) { + // Return when the end-directive was parsed. + return std::move(tail); + } + } else { + break; + } + } + return std::nullopt; + } + + private: + const size_t count_; + }; + + // The recursion guard should become thread_local if parsing is ever + // parallelized. + static bool recursing_; +}; + +bool OmpAtomicConstructParser::recursing_{false}; + +TYPE_PARSER(sourced( // + construct(OmpAtomicConstructParser{}))) + // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0] // memory-order-clause -> // acq_rel @@ -1237,19 +1398,6 @@ TYPE_PARSER(sourced(construct( "RELEASE" >> construct(construct()) || "SEQ_CST" >> construct(construct()))))) -// 2.17.7 Atomic construct -// atomic-clause -> memory-order-clause | HINT(hint-expression) -TYPE_PARSER(sourced(construct( - construct(Parser{}) || - construct( - "FAIL" >> parenthesized(Parser{})) || - construct( - "HINT" >> parenthesized(Parser{}))))) - -// atomic-clause-list -> [atomic-clause, [atomic-clause], ...] -TYPE_PARSER(sourced(construct( - many(maybe(","_tok) >> sourced(Parser{}))))) - static bool IsSimpleStandalone(const OmpDirectiveName &name) { switch (name.v) { case llvm::omp::Directive::OMPD_barrier: @@ -1421,67 +1569,6 @@ TYPE_PARSER(sourced( TYPE_PARSER(construct(Parser{}) || construct(Parser{})) -// 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] | -// ATOMIC [clause] -// clause -> memory-order-clause | HINT(hint-expression) -// memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED -// atomic-clause -> READ | WRITE | UPDATE | CAPTURE - -// OMP END ATOMIC -TYPE_PARSER(construct(startOmpLine >> "END ATOMIC"_tok)) - -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST] -TYPE_PARSER("ATOMIC" >> - sourced(construct( - Parser{} / maybe(","_tok), verbatim("READ"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), - maybe(Parser{} / endOmpLine)))) - -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST] -TYPE_PARSER("ATOMIC" >> - sourced(construct( - Parser{} / maybe(","_tok), verbatim("CAPTURE"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), - statement(assignmentStmt), Parser{} / endOmpLine))) - -TYPE_PARSER(construct(indirect(Parser{})) || - construct(indirect(Parser{}))) - -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] COMPARE [MEMORY-ORDER-CLAUSE-LIST] -TYPE_PARSER("ATOMIC" >> - sourced(construct( - Parser{} / maybe(","_tok), verbatim("COMPARE"_tok), - Parser{} / endOmpLine, - Parser{}, - maybe(Parser{} / endOmpLine)))) - -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST] -TYPE_PARSER("ATOMIC" >> - sourced(construct( - Parser{} / maybe(","_tok), verbatim("UPDATE"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), - maybe(Parser{} / endOmpLine)))) - -// OMP ATOMIC [atomic-clause-list] -TYPE_PARSER(sourced(construct(verbatim("ATOMIC"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), - maybe(Parser{} / endOmpLine)))) - -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST] -TYPE_PARSER("ATOMIC" >> - sourced(construct( - Parser{} / maybe(","_tok), verbatim("WRITE"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), - maybe(Parser{} / endOmpLine)))) - -// Atomic Construct -TYPE_PARSER(construct(Parser{}) || - construct(Parser{}) || - construct(Parser{}) || - construct(Parser{}) || - construct(Parser{}) || - construct(Parser{})) - // 2.13.2 OMP CRITICAL TYPE_PARSER(startOmpLine >> sourced(construct( diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp index 3dd87ad9a3650..824612e49293f 100644 --- a/flang/lib/Parser/parse-tree.cpp +++ b/flang/lib/Parser/parse-tree.cpp @@ -321,6 +321,34 @@ std::string OmpTraitSetSelectorName::ToString() const { return std::string(EnumToString(v)); } +llvm::omp::Clause OpenMPAtomicConstruct::GetKind() const { + auto &dirSpec{std::get(t)}; + for (auto &clause : dirSpec.Clauses().v) { + switch (clause.Id()) { + case llvm::omp::Clause::OMPC_read: + case llvm::omp::Clause::OMPC_write: + case llvm::omp::Clause::OMPC_update: + return clause.Id(); + default: + break; + } + } + return llvm::omp::Clause::OMPC_update; +} + +bool OpenMPAtomicConstruct::IsCapture() const { + auto &dirSpec{std::get(t)}; + return llvm::any_of(dirSpec.Clauses().v, [](auto &clause) { + return clause.Id() == llvm::omp::Clause::OMPC_capture; + }); +} + +bool OpenMPAtomicConstruct::IsCompare() const { + auto &dirSpec{std::get(t)}; + return llvm::any_of(dirSpec.Clauses().v, [](auto &clause) { + return clause.Id() == llvm::omp::Clause::OMPC_compare; + }); +} } // namespace Fortran::parser template static llvm::omp::Clause getClauseIdForClass(C &&) { diff --git a/flang/lib/Parser/tools.cpp b/flang/lib/Parser/tools.cpp index 6e5f1ed2fc66f..264ca520f38b8 100644 --- a/flang/lib/Parser/tools.cpp +++ b/flang/lib/Parser/tools.cpp @@ -174,4 +174,9 @@ const CoindexedNamedObject *GetCoindexedNamedObject( }, allocateObject.u); } + +bool CheckForSingleVariableOnRHS(const AssignmentStmt &assignmentStmt) { + return Unwrap(std::get(assignmentStmt.t)) != nullptr; +} + } // namespace Fortran::parser diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index e0abe95d07c86..ed0f227fd5b98 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2571,83 +2571,22 @@ class UnparseVisitor { Word(ToUpperCaseLetters(common::EnumToString(x))); } - void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); } - - void Unparse(const OmpAtomic &x) { - BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get(x.t)); - Put("\n"); - EndOpenMP(); - Walk(std::get>(x.t)); - BeginOpenMP(); - Walk(std::get>(x.t), "!$OMP END ATOMIC\n"); - EndOpenMP(); - } - void Unparse(const OmpAtomicCapture &x) { - BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get<0>(x.t)); - Word(" CAPTURE"); - Walk(std::get<2>(x.t)); - Put("\n"); - EndOpenMP(); - Walk(std::get(x.t)); - Put("\n"); - Walk(std::get(x.t)); - BeginOpenMP(); - Word("!$OMP END ATOMIC\n"); - EndOpenMP(); - } - void Unparse(const OmpAtomicCompare &x) { - BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get<0>(x.t)); - Word(" COMPARE"); - Walk(std::get<2>(x.t)); - Put("\n"); - EndOpenMP(); - Walk(std::get(x.t)); - } - void Unparse(const OmpAtomicRead &x) { - BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get<0>(x.t)); - Word(" READ"); - Walk(std::get<2>(x.t)); - Put("\n"); - EndOpenMP(); - Walk(std::get>(x.t)); - BeginOpenMP(); - Walk(std::get>(x.t), "!$OMP END ATOMIC\n"); - EndOpenMP(); - } - void Unparse(const OmpAtomicUpdate &x) { + void Unparse(const OpenMPAtomicConstruct &x) { BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get<0>(x.t)); - Word(" UPDATE"); - Walk(std::get<2>(x.t)); - Put("\n"); - EndOpenMP(); - Walk(std::get>(x.t)); - BeginOpenMP(); - Walk(std::get>(x.t), "!$OMP END ATOMIC\n"); - EndOpenMP(); - } - void Unparse(const OmpAtomicWrite &x) { - BeginOpenMP(); - Word("!$OMP ATOMIC"); - Walk(std::get<0>(x.t)); - Word(" WRITE"); - Walk(std::get<2>(x.t)); + Word("!$OMP "); + Walk(std::get(x.t)); Put("\n"); EndOpenMP(); - Walk(std::get>(x.t)); - BeginOpenMP(); - Walk(std::get>(x.t), "!$OMP END ATOMIC\n"); - EndOpenMP(); + Walk(std::get(x.t), ""); + if (auto &end{std::get>(x.t)}) { + BeginOpenMP(); + Word("!$OMP END "); + Walk(*end); + Put("\n"); + EndOpenMP(); + } } + void Unparse(const OpenMPExecutableAllocate &x) { const auto &fields = std::get>>( @@ -2920,23 +2859,8 @@ class UnparseVisitor { Put("\n"); EndOpenMP(); } + void Unparse(const OmpFailClause &x) { Walk(x.v); } void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); } - void Unparse(const OmpAtomicClause &x) { - common::visit(common::visitors{ - [&](const OmpMemoryOrderClause &y) { Walk(y); }, - [&](const OmpFailClause &y) { - Word("FAIL("); - Walk(y.v); - Put(")"); - }, - [&](const OmpHintClause &y) { - Word("HINT("); - Walk(y.v); - Put(")"); - }, - }, - x.u); - } void Unparse(const OmpMetadirectiveDirective &x) { BeginOpenMP(); Word("!$OMP METADIRECTIVE "); diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp index 2c215f45bf516..08053594c12e4 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-call.cpp b/flang/lib/Semantics/check-call.cpp index dfc2ddbacf071..6f2503285013d 100644 --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -1033,6 +1033,13 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, *actualDataAttr == common::CUDADataAttr::Managed)) { actualDataAttr = common::CUDADataAttr::Device; } + // For device procedures, treat actual arguments with VALUE attribute as + // device data + if (!actualDataAttr && actualLastSymbol && IsValue(*actualLastSymbol) && + (*procedure.cudaSubprogramAttrs == + common::CUDASubprogramAttrs::Device)) { + actualDataAttr = common::CUDADataAttr::Device; + } } if (dummyDataAttr == common::CUDADataAttr::Device && (dummyIsAssumedShape || dummyIsAssumedRank) && diff --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp index c024640af1220..8decfb0149829 100644 --- a/flang/lib/Semantics/check-cuda.cpp +++ b/flang/lib/Semantics/check-cuda.cpp @@ -17,6 +17,7 @@ #include "flang/Semantics/expression.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" +#include "llvm/ADT/StringSet.h" // Once labeled DO constructs have been canonicalized and their parse subtrees // transformed into parser::DoConstructs, scan the parser::Blocks of the program @@ -61,6 +62,11 @@ bool CanonicalizeCUDA(parser::Program &program) { using MaybeMsg = std::optional; +static const llvm::StringSet<> warpFunctions_ = {"match_all_syncjj", + "match_all_syncjx", "match_all_syncjf", "match_all_syncjd", + "match_any_syncjj", "match_any_syncjx", "match_any_syncjf", + "match_any_syncjd"}; + // Traverses an evaluate::Expr<> in search of unsupported operations // on the device. @@ -68,7 +74,7 @@ struct DeviceExprChecker : public evaluate::AnyTraverse { using Result = MaybeMsg; using Base = evaluate::AnyTraverse; - DeviceExprChecker() : Base(*this) {} + explicit DeviceExprChecker(SemanticsContext &c) : Base(*this), context_{c} {} using Base::operator(); Result operator()(const evaluate::ProcedureDesignator &x) const { if (const Symbol * sym{x.GetInterfaceSymbol()}) { @@ -78,10 +84,17 @@ struct DeviceExprChecker if (auto attrs{subp->cudaSubprogramAttrs()}) { if (*attrs == common::CUDASubprogramAttrs::HostDevice || *attrs == common::CUDASubprogramAttrs::Device) { + if (warpFunctions_.contains(sym->name().ToString()) && + !context_.languageFeatures().IsEnabled( + Fortran::common::LanguageFeature::CudaWarpMatchFunction)) { + return parser::MessageFormattedText( + "warp match function disabled"_err_en_US); + } return {}; } } } + const Symbol &ultimate{sym->GetUltimate()}; const Scope &scope{ultimate.owner()}; const Symbol *mod{scope.IsModule() ? scope.symbol() : nullptr}; @@ -94,9 +107,12 @@ struct DeviceExprChecker // TODO(CUDA): Check for unsupported intrinsics here return {}; } + return parser::MessageFormattedText( "'%s' may not be called in device code"_err_en_US, x.GetName()); } + + SemanticsContext &context_; }; struct FindHostArray @@ -133,9 +149,10 @@ struct FindHostArray } }; -template static MaybeMsg CheckUnwrappedExpr(const A &x) { +template +static MaybeMsg CheckUnwrappedExpr(SemanticsContext &context, const A &x) { if (const auto *expr{parser::Unwrap(x)}) { - return DeviceExprChecker{}(expr->typedExpr); + return DeviceExprChecker{context}(expr->typedExpr); } return {}; } @@ -144,104 +161,124 @@ template static void CheckUnwrappedExpr( SemanticsContext &context, SourceName at, const A &x) { if (const auto *expr{parser::Unwrap(x)}) { - if (auto msg{DeviceExprChecker{}(expr->typedExpr)}) { + if (auto msg{DeviceExprChecker{context}(expr->typedExpr)}) { context.Say(at, std::move(*msg)); } } } template struct ActionStmtChecker { - template static MaybeMsg WhyNotOk(const A &x) { + template + static MaybeMsg WhyNotOk(SemanticsContext &context, const A &x) { if constexpr (ConstraintTrait) { - return WhyNotOk(x.thing); + return WhyNotOk(context, x.thing); } else if constexpr (WrapperTrait) { - return WhyNotOk(x.v); + return WhyNotOk(context, x.v); } else if constexpr (UnionTrait) { - return WhyNotOk(x.u); + return WhyNotOk(context, x.u); } else if constexpr (TupleTrait) { - return WhyNotOk(x.t); + return WhyNotOk(context, x.t); } else { return parser::MessageFormattedText{ "Statement may not appear in device code"_err_en_US}; } } template - static MaybeMsg WhyNotOk(const common::Indirection &x) { - return WhyNotOk(x.value()); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const common::Indirection &x) { + return WhyNotOk(context, x.value()); } template - static MaybeMsg WhyNotOk(const std::variant &x) { - return common::visit([](const auto &x) { return WhyNotOk(x); }, x); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const std::variant &x) { + return common::visit( + [&context](const auto &x) { return WhyNotOk(context, x); }, x); } template - static MaybeMsg WhyNotOk(const std::tuple &x) { + static MaybeMsg WhyNotOk( + SemanticsContext &context, const std::tuple &x) { if constexpr (J == sizeof...(As)) { return {}; - } else if (auto msg{WhyNotOk(std::get(x))}) { + } else if (auto msg{WhyNotOk(context, std::get(x))}) { return msg; } else { - return WhyNotOk<(J + 1)>(x); + return WhyNotOk<(J + 1)>(context, x); } } - template static MaybeMsg WhyNotOk(const std::list &x) { + template + static MaybeMsg WhyNotOk(SemanticsContext &context, const std::list &x) { for (const auto &y : x) { - if (MaybeMsg result{WhyNotOk(y)}) { + if (MaybeMsg result{WhyNotOk(context, y)}) { return result; } } return {}; } - template static MaybeMsg WhyNotOk(const std::optional &x) { + template + static MaybeMsg WhyNotOk( + SemanticsContext &context, const std::optional &x) { if (x) { - return WhyNotOk(*x); + return WhyNotOk(context, *x); } else { return {}; } } template - static MaybeMsg WhyNotOk(const parser::UnlabeledStatement &x) { - return WhyNotOk(x.statement); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::UnlabeledStatement &x) { + return WhyNotOk(context, x.statement); } template - static MaybeMsg WhyNotOk(const parser::Statement &x) { - return WhyNotOk(x.statement); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::Statement &x) { + return WhyNotOk(context, x.statement); } - static MaybeMsg WhyNotOk(const parser::AllocateStmt &) { + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::AllocateStmt &) { return {}; // AllocateObjects are checked elsewhere } - static MaybeMsg WhyNotOk(const parser::AllocateCoarraySpec &) { + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::AllocateCoarraySpec &) { return parser::MessageFormattedText( "A coarray may not be allocated on the device"_err_en_US); } - static MaybeMsg WhyNotOk(const parser::DeallocateStmt &) { + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::DeallocateStmt &) { return {}; // AllocateObjects are checked elsewhere } - static MaybeMsg WhyNotOk(const parser::AssignmentStmt &x) { - return DeviceExprChecker{}(x.typedAssignment); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::AssignmentStmt &x) { + return DeviceExprChecker{context}(x.typedAssignment); } - static MaybeMsg WhyNotOk(const parser::CallStmt &x) { - return DeviceExprChecker{}(x.typedCall); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::CallStmt &x) { + return DeviceExprChecker{context}(x.typedCall); + } + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::ContinueStmt &) { + return {}; } - static MaybeMsg WhyNotOk(const parser::ContinueStmt &) { return {}; } - static MaybeMsg WhyNotOk(const parser::IfStmt &x) { - if (auto result{ - CheckUnwrappedExpr(std::get(x.t))}) { + static MaybeMsg WhyNotOk(SemanticsContext &context, const parser::IfStmt &x) { + if (auto result{CheckUnwrappedExpr( + context, std::get(x.t))}) { return result; } - return WhyNotOk( + return WhyNotOk(context, std::get>(x.t) .statement); } - static MaybeMsg WhyNotOk(const parser::NullifyStmt &x) { + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::NullifyStmt &x) { for (const auto &y : x.v) { - if (MaybeMsg result{DeviceExprChecker{}(y.typedExpr)}) { + if (MaybeMsg result{DeviceExprChecker{context}(y.typedExpr)}) { return result; } } return {}; } - static MaybeMsg WhyNotOk(const parser::PointerAssignmentStmt &x) { - return DeviceExprChecker{}(x.typedAssignment); + static MaybeMsg WhyNotOk( + SemanticsContext &context, const parser::PointerAssignmentStmt &x) { + return DeviceExprChecker{context}(x.typedAssignment); } }; @@ -435,12 +472,14 @@ template class DeviceContextChecker { ErrorIfHostSymbol(assign->lhs, source); ErrorIfHostSymbol(assign->rhs, source); } - if (auto msg{ActionStmtChecker::WhyNotOk(x)}) { + if (auto msg{ActionStmtChecker::WhyNotOk( + context_, x)}) { context_.Say(source, std::move(*msg)); } }, [&](const auto &x) { - if (auto msg{ActionStmtChecker::WhyNotOk(x)}) { + if (auto msg{ActionStmtChecker::WhyNotOk( + context_, x)}) { context_.Say(source, std::move(*msg)); } }, @@ -504,7 +543,7 @@ template class DeviceContextChecker { Check(DEREF(parser::Unwrap(x))); } void Check(const parser::Expr &expr) { - if (MaybeMsg msg{DeviceExprChecker{}(expr.typedExpr)}) { + if (MaybeMsg msg{DeviceExprChecker{context_}(expr.typedExpr)}) { context_.Say(expr.source, std::move(*msg)); } } diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 46a5b970fdf0c..f9d64485f1407 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 bdd078c33da92..83f4d1edf3c4f 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -11,16 +11,23 @@ #include "resolve-names-utils.h" #include "flang/Evaluate/check-expression.h" #include "flang/Evaluate/expression.h" +#include "flang/Evaluate/shape.h" #include "flang/Evaluate/type.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/expression.h" #include "flang/Semantics/openmp-modifiers.h" #include "flang/Semantics/tools.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include namespace Fortran::semantics { +template +static bool operator!=(const evaluate::Expr &e, const evaluate::Expr &f) { + return !(e == f); +} + // Use when clause falls under 'struct OmpClause' in 'parse-tree.h'. #define CHECK_SIMPLE_CLAUSE(X, Y) \ void OmpStructureChecker::Enter(const parser::OmpClause::X &) { \ @@ -79,6 +86,32 @@ static const parser::ArrayElement *GetArrayElementFromObj( return nullptr; } +static bool IsVarOrFunctionRef(const MaybeExpr &expr) { + if (expr) { + return evaluate::UnwrapProcedureRef(*expr) != nullptr || + evaluate::IsVariable(*expr); + } else { + return false; + } +} + +static std::optional GetEvaluateExpr(const parser::Expr &parserExpr) { + const parser::TypedExpr &typedExpr{parserExpr.typedExpr}; + // ForwardOwningPointer typedExpr + // `- GenericExprWrapper ^.get() + // `- std::optional ^->v + return typedExpr.get()->v; +} + +static std::optional GetDynamicType( + const parser::Expr &parserExpr) { + if (auto maybeExpr{GetEvaluateExpr(parserExpr)}) { + return maybeExpr->GetType(); + } else { + return std::nullopt; + } +} + // 'OmpWorkshareBlockChecker' is used to check the validity of the assignment // statements and the expressions enclosed in an OpenMP Workshare construct class OmpWorkshareBlockChecker { @@ -595,51 +628,26 @@ void OmpStructureChecker::CheckPredefinedAllocatorRestriction( } } -template -void OmpStructureChecker::CheckHintClause( - D *leftOmpClauseList, D *rightOmpClauseList, std::string_view dirName) { - bool foundHint{false}; +void OmpStructureChecker::Enter(const parser::OmpClause::Hint &x) { + CheckAllowedClause(llvm::omp::Clause::OMPC_hint); + auto &dirCtx{GetContext()}; - auto checkForValidHintClause = [&](const D *clauseList) { - for (const auto &clause : clauseList->v) { - const parser::OmpHintClause *ompHintClause = nullptr; - if constexpr (std::is_same_v) { - ompHintClause = std::get_if(&clause.u); - } else if constexpr (std::is_same_v) { - if (auto *hint{std::get_if(&clause.u)}) { - ompHintClause = &hint->v; - } - } - if (!ompHintClause) - continue; - if (foundHint) { - context_.Say(clause.source, - "At most one HINT clause can appear on the %s directive"_err_en_US, - parser::ToUpperCaseLetters(dirName)); - } - foundHint = true; - std::optional hintValue = GetIntValue(ompHintClause->v); - if (hintValue && *hintValue >= 0) { - /*`omp_sync_hint_nonspeculative` and `omp_lock_hint_speculative`*/ - if ((*hintValue & 0xC) == 0xC - /*`omp_sync_hint_uncontended` and omp_sync_hint_contended*/ - || (*hintValue & 0x3) == 0x3) - context_.Say(clause.source, - "Hint clause value " - "is not a valid OpenMP synchronization value"_err_en_US); - } else { - context_.Say(clause.source, - "Hint clause must have non-negative constant " - "integer expression"_err_en_US); + if (std::optional maybeVal{GetIntValue(x.v.v)}) { + int64_t val{*maybeVal}; + if (val >= 0) { + // Check contradictory values. + if ((val & 0xC) == 0xC || // omp_sync_hint_speculative and nonspeculative + (val & 0x3) == 0x3) { // omp_sync_hint_contended and uncontended + context_.Say(dirCtx.clauseSource, + "The synchronization hint is not valid"_err_en_US); } + } else { + context_.Say(dirCtx.clauseSource, + "Synchronization hint must be non-negative"_err_en_US); } - }; - - if (leftOmpClauseList) { - checkForValidHintClause(leftOmpClauseList); - } - if (rightOmpClauseList) { - checkForValidHintClause(rightOmpClauseList); + } else { + context_.Say(dirCtx.clauseSource, + "Synchronization hint must be a constant integer value"_err_en_US); } } @@ -1812,15 +1820,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); + } } } @@ -2396,8 +2413,9 @@ void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) { void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) { const auto &dir{std::get(x.t)}; + const auto &dirSource{std::get(dir.t).source}; const auto &endDir{std::get(x.t)}; - PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_critical); + PushContextAndClauseSets(dirSource, llvm::omp::Directive::OMPD_critical); const auto &block{std::get(x.t)}; CheckNoBranching(block, llvm::omp::Directive::OMPD_critical, dir.source); const auto &dirName{std::get>(dir.t)}; @@ -2430,7 +2448,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) { "Hint clause other than omp_sync_hint_none cannot be specified for " "an unnamed CRITICAL directive"_err_en_US}); } - CheckHintClause(&ompClause, nullptr, "CRITICAL"); } void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) { @@ -2667,422 +2684,1418 @@ void OmpStructureChecker::Leave(const parser::OmpEndBlockDirective &x) { } } -inline void OmpStructureChecker::ErrIfAllocatableVariable( - const parser::Variable &var) { - // Err out if the given symbol has - // ALLOCATABLE attribute - if (const auto *e{GetExpr(context_, var)}) - for (const Symbol &symbol : evaluate::CollectSymbols(*e)) - if (IsAllocatable(symbol)) { - const auto &designator = - std::get>(var.u); - const auto *dataRef = - std::get_if(&designator.value().u); - const parser::Name *name = - dataRef ? std::get_if(&dataRef->u) : nullptr; - if (name) - context_.Say(name->source, - "%s must not have ALLOCATABLE " - "attribute"_err_en_US, - name->ToString()); +/// parser::Block is a list of executable constructs, parser::BlockConstruct +/// is Fortran's BLOCK/ENDBLOCK construct. +/// Strip the outermost BlockConstructs, return the reference to the Block +/// in the executable part of the innermost of the stripped constructs. +/// Specifically, if the given `block` has a single entry (it's a list), and +/// the entry is a BlockConstruct, get the Block contained within. Repeat +/// this step as many times as possible. +static const parser::Block &GetInnermostExecPart(const parser::Block &block) { + const parser::Block *iter{&block}; + while (iter->size() == 1) { + const parser::ExecutionPartConstruct &ep{iter->front()}; + if (auto *exec{std::get_if(&ep.u)}) { + using BlockConstruct = common::Indirection; + if (auto *bc{std::get_if(&exec->u)}) { + iter = &std::get(bc->value().t); + continue; } + } + break; + } + return *iter; } -inline void OmpStructureChecker::ErrIfLHSAndRHSSymbolsMatch( - const parser::Variable &var, const parser::Expr &expr) { - // Err out if the symbol on the LHS is also used on the RHS of the assignment - // statement - const auto *e{GetExpr(context_, expr)}; - const auto *v{GetExpr(context_, var)}; - if (e && v) { - auto vSyms{evaluate::GetSymbolVector(*v)}; - const Symbol &varSymbol = vSyms.front(); - for (const Symbol &symbol : evaluate::GetSymbolVector(*e)) { - if (varSymbol == symbol) { - const common::Indirection *designator = - std::get_if>(&expr.u); - if (designator) { - auto *z{var.typedExpr.get()}; - auto *c{expr.typedExpr.get()}; - if (z->v == c->v) { - context_.Say(expr.source, - "RHS expression on atomic assignment statement cannot access '%s'"_err_en_US, - var.GetSource()); - } +// There is no consistent way to get the source of a given ActionStmt, so +// extract the source information from Statement when we can, +// and keep it around for error reporting in further analyses. +struct SourcedActionStmt { + const parser::ActionStmt *stmt{nullptr}; + parser::CharBlock source; + + operator bool() const { return stmt != nullptr; } +}; + +struct AnalyzedCondStmt { + SomeExpr cond{evaluate::NullPointer{}}; // Default ctor is deleted + parser::CharBlock source; + SourcedActionStmt ift, iff; +}; + +static SourcedActionStmt GetActionStmt( + const parser::ExecutionPartConstruct *x) { + if (x == nullptr) { + return SourcedActionStmt{}; + } + if (auto *exec{std::get_if(&x->u)}) { + using ActionStmt = parser::Statement; + if (auto *stmt{std::get_if(&exec->u)}) { + return SourcedActionStmt{&stmt->statement, stmt->source}; + } + } + return SourcedActionStmt{}; +} + +static SourcedActionStmt GetActionStmt(const parser::Block &block) { + if (block.size() == 1) { + return GetActionStmt(&block.front()); + } + return SourcedActionStmt{}; +} + +// Compute the `evaluate::Assignment` from parser::ActionStmt. The assumption +// is that the ActionStmt will be either an assignment or a pointer-assignment, +// otherwise return std::nullopt. +// Note: This function can return std::nullopt on [Pointer]AssignmentStmt where +// the "typedAssignment" is unset. This can happen if there are semantic errors +// in the purported assignment. +static std::optional GetEvaluateAssignment( + const parser::ActionStmt *x) { + if (x == nullptr) { + return std::nullopt; + } + + using AssignmentStmt = common::Indirection; + using PointerAssignmentStmt = + common::Indirection; + using TypedAssignment = parser::AssignmentStmt::TypedAssignment; + + return common::visit( + [](auto &&s) -> std::optional { + using BareS = llvm::remove_cvref_t; + if constexpr (std::is_same_v || + std::is_same_v) { + const TypedAssignment &typed{s.value().typedAssignment}; + // ForwardOwningPointer typedAssignment + // `- GenericAssignmentWrapper ^.get() + // `- std::optional ^->v + return typed.get()->v; } else { - context_.Say(expr.source, - "RHS expression on atomic assignment statement cannot access '%s'"_err_en_US, - var.GetSource()); + return std::nullopt; + } + }, + x->u); +} + +// Check if the ActionStmt is actually a [Pointer]AssignmentStmt. This is +// to separate cases where the source has something that looks like an +// assignment, but is semantically wrong (diagnosed by general semantic +// checks), and where the source has some other statement (which we want +// to report as "should be an assignment"). +static bool IsAssignment(const parser::ActionStmt *x) { + if (x == nullptr) { + return false; + } + + using AssignmentStmt = common::Indirection; + using PointerAssignmentStmt = + common::Indirection; + + return common::visit( + [](auto &&s) -> bool { + using BareS = llvm::remove_cvref_t; + return std::is_same_v || + std::is_same_v; + }, + x->u); +} + +static std::optional AnalyzeConditionalStmt( + const parser::ExecutionPartConstruct *x) { + if (x == nullptr) { + return std::nullopt; + } + + // Extract the evaluate::Expr from ScalarLogicalExpr. + auto getFromLogical{[](const parser::ScalarLogicalExpr &logical) { + // ScalarLogicalExpr is Scalar>> + const parser::Expr &expr{logical.thing.thing.value()}; + return GetEvaluateExpr(expr); + }}; + + // Recognize either + // ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> IfStmt, or + // ExecutionPartConstruct -> ExecutableConstruct -> IfConstruct. + + if (auto &&action{GetActionStmt(x)}) { + if (auto *ifs{std::get_if>( + &action.stmt->u)}) { + const parser::IfStmt &s{ifs->value()}; + auto &&maybeCond{ + getFromLogical(std::get(s.t))}; + auto &thenStmt{ + std::get>(s.t)}; + if (maybeCond) { + return AnalyzedCondStmt{std::move(*maybeCond), action.source, + SourcedActionStmt{&thenStmt.statement, thenStmt.source}, + SourcedActionStmt{}}; + } + } + return std::nullopt; + } + + if (auto *exec{std::get_if(&x->u)}) { + if (auto *ifc{ + std::get_if>(&exec->u)}) { + using ElseBlock = parser::IfConstruct::ElseBlock; + using ElseIfBlock = parser::IfConstruct::ElseIfBlock; + const parser::IfConstruct &s{ifc->value()}; + + if (!std::get>(s.t).empty()) { + // Not expecting any else-if statements. + return std::nullopt; + } + auto &stmt{std::get>(s.t)}; + auto &&maybeCond{getFromLogical( + std::get(stmt.statement.t))}; + if (!maybeCond) { + return std::nullopt; + } + + if (auto &maybeElse{std::get>(s.t)}) { + AnalyzedCondStmt result{std::move(*maybeCond), stmt.source, + GetActionStmt(std::get(s.t)), + GetActionStmt(std::get(maybeElse->t))}; + if (result.ift.stmt && result.iff.stmt) { + return result; + } + } else { + AnalyzedCondStmt result{std::move(*maybeCond), stmt.source, + GetActionStmt(std::get(s.t)), SourcedActionStmt{}}; + if (result.ift.stmt) { + return result; } } } + return std::nullopt; } + + return std::nullopt; } -inline void OmpStructureChecker::ErrIfNonScalarAssignmentStmt( - const parser::Variable &var, const parser::Expr &expr) { - // Err out if either the variable on the LHS or the expression on the RHS of - // the assignment statement are non-scalar (i.e. have rank > 0 or is of - // CHARACTER type) - const auto *e{GetExpr(context_, expr)}; - const auto *v{GetExpr(context_, var)}; - if (e && v) { - if (e->Rank() != 0 || - (e->GetType().has_value() && - e->GetType().value().category() == common::TypeCategory::Character)) - context_.Say(expr.source, - "Expected scalar expression " - "on the RHS of atomic assignment " - "statement"_err_en_US); - if (v->Rank() != 0 || - (v->GetType().has_value() && - v->GetType()->category() == common::TypeCategory::Character)) - context_.Say(var.GetSource(), - "Expected scalar variable " - "on the LHS of atomic assignment " - "statement"_err_en_US); - } -} - -template -bool OmpStructureChecker::IsOperatorValid(const T &node, const D &variable) { - using AllowedBinaryOperators = - std::variant; - using BinaryOperators = std::variant; - - if constexpr (common::HasMember) { - const auto &variableName{variable.GetSource().ToString()}; - const auto &exprLeft{std::get<0>(node.t)}; - const auto &exprRight{std::get<1>(node.t)}; - if ((exprLeft.value().source.ToString() != variableName) && - (exprRight.value().source.ToString() != variableName)) { - context_.Say(variable.GetSource(), - "Atomic update statement should be of form " - "`%s = %s operator expr` OR `%s = expr operator %s`"_err_en_US, - variableName, variableName, variableName, variableName); - } - return common::HasMember; +static std::pair SplitAssignmentSource( + parser::CharBlock source) { + // Find => in the range, if not found, find = that is not a part of + // <=, >=, ==, or /=. + auto trim{[](std::string_view v) { + const char *begin{v.data()}; + const char *end{begin + v.size()}; + while (*begin == ' ' && begin != end) { + ++begin; + } + while (begin != end && end[-1] == ' ') { + --end; + } + assert(begin != end && "Source should not be empty"); + return parser::CharBlock(begin, end - begin); + }}; + + std::string_view sv(source.begin(), source.size()); + + if (auto where{sv.find("=>")}; where != sv.npos) { + std::string_view lhs(sv.data(), where); + std::string_view rhs(sv.data() + where + 2, sv.size() - where - 2); + return std::make_pair(trim(lhs), trim(rhs)); } - return false; + + // Go backwards, since all the exclusions above end with a '='. + for (size_t next{source.size()}; next > 1; --next) { + if (sv[next - 1] == '=' && !llvm::is_contained("<>=/", sv[next - 2])) { + std::string_view lhs(sv.data(), next - 1); + std::string_view rhs(sv.data() + next, sv.size() - next); + return std::make_pair(trim(lhs), trim(rhs)); + } + } + llvm_unreachable("Could not find assignment operator"); } -void OmpStructureChecker::CheckAtomicCaptureStmt( - const parser::AssignmentStmt &assignmentStmt) { - const auto &var{std::get(assignmentStmt.t)}; - const auto &expr{std::get(assignmentStmt.t)}; - common::visit( - common::visitors{ - [&](const common::Indirection &designator) { - const auto *dataRef = - std::get_if(&designator.value().u); - const auto *name = - dataRef ? std::get_if(&dataRef->u) : nullptr; - if (name && IsAllocatable(*name->symbol)) - context_.Say(name->source, - "%s must not have ALLOCATABLE " - "attribute"_err_en_US, - name->ToString()); - }, - [&](const auto &) { - // Anything other than a `parser::Designator` is not allowed - context_.Say(expr.source, - "Expected scalar variable " - "of intrinsic type on RHS of atomic " - "assignment statement"_err_en_US); - }}, - expr.u); - ErrIfLHSAndRHSSymbolsMatch(var, expr); - ErrIfNonScalarAssignmentStmt(var, expr); -} - -void OmpStructureChecker::CheckAtomicWriteStmt( - const parser::AssignmentStmt &assignmentStmt) { - const auto &var{std::get(assignmentStmt.t)}; - const auto &expr{std::get(assignmentStmt.t)}; - ErrIfAllocatableVariable(var); - ErrIfLHSAndRHSSymbolsMatch(var, expr); - ErrIfNonScalarAssignmentStmt(var, expr); -} - -void OmpStructureChecker::CheckAtomicUpdateStmt( - const parser::AssignmentStmt &assignment) { - const auto &expr{std::get(assignment.t)}; - const auto &var{std::get(assignment.t)}; - bool isIntrinsicProcedure{false}; - bool isValidOperator{false}; - common::visit( - common::visitors{ - [&](const common::Indirection &x) { - isIntrinsicProcedure = true; - const auto &procedureDesignator{ - std::get(x.value().v.t)}; - const parser::Name *name{ - std::get_if(&procedureDesignator.u)}; - if (name && - !(name->source == "max" || name->source == "min" || - name->source == "iand" || name->source == "ior" || - name->source == "ieor")) { - context_.Say(expr.source, - "Invalid intrinsic procedure name in " - "OpenMP ATOMIC (UPDATE) statement"_err_en_US); - } - }, - [&](const auto &x) { - if (!IsOperatorValid(x, var)) { - context_.Say(expr.source, - "Invalid or missing operator in atomic update " - "statement"_err_en_US); - } else - isValidOperator = true; - }, - }, - expr.u); - if (const auto *e{GetExpr(context_, expr)}) { - const auto *v{GetExpr(context_, var)}; - if (e->Rank() != 0 || - (e->GetType().has_value() && - e->GetType().value().category() == common::TypeCategory::Character)) - context_.Say(expr.source, - "Expected scalar expression " - "on the RHS of atomic update assignment " - "statement"_err_en_US); - if (v->Rank() != 0 || - (v->GetType().has_value() && - v->GetType()->category() == common::TypeCategory::Character)) - context_.Say(var.GetSource(), - "Expected scalar variable " - "on the LHS of atomic update assignment " - "statement"_err_en_US); - auto vSyms{evaluate::GetSymbolVector(*v)}; - const Symbol &varSymbol = vSyms.front(); - int numOfSymbolMatches{0}; - SymbolVector exprSymbols{evaluate::GetSymbolVector(*e)}; - for (const Symbol &symbol : exprSymbols) { - if (varSymbol == symbol) { - numOfSymbolMatches++; +namespace atomic { + +struct DesignatorCollector : public evaluate::Traverse, false> { + using Result = std::vector; + using Base = evaluate::Traverse; + DesignatorCollector() : Base(*this) {} + + Result Default() const { return {}; } + + using Base::operator(); + + template // + Result operator()(const evaluate::Designator &x) const { + // Once in a designator, don't traverse it any further (i.e. only + // collect top-level designators). + auto copy{x}; + return Result{AsGenericExpr(std::move(copy))}; + } + + template // + Result Combine(Result &&result, Rs &&...results) const { + Result v(std::move(result)); + auto moveAppend{[](auto &accum, auto &&other) { + for (auto &&s : other) { + accum.push_back(std::move(s)); } + }}; + (moveAppend(v, std::move(results)), ...); + return v; + } +}; + +struct VariableFinder : public evaluate::AnyTraverse { + using Base = evaluate::AnyTraverse; + VariableFinder(const SomeExpr &v) : Base(*this), var(v) {} + + using Base::operator(); + + template + bool operator()(const evaluate::Designator &x) const { + auto copy{x}; + return evaluate::AsGenericExpr(std::move(copy)) == var; + } + + template + bool operator()(const evaluate::FunctionRef &x) const { + auto copy{x}; + return evaluate::AsGenericExpr(std::move(copy)) == var; + } + +private: + const SomeExpr &var; +}; +} // namespace atomic + +static bool IsPointerAssignment(const evaluate::Assignment &x) { + return std::holds_alternative(x.u) || + std::holds_alternative(x.u); +} + +static bool IsCheckForAssociated(const SomeExpr &cond) { + return GetTopLevelOperation(cond).first == operation::Operator::Associated; +} + +static bool HasCommonDesignatorSymbols( + const evaluate::SymbolVector &baseSyms, const SomeExpr &other) { + // Compare the designators used in "other" with the designators whose + // symbols are given in baseSyms. + // This is a part of the check if these two expressions can access the same + // storage: if the designators used in them are different enough, then they + // will be assumed not to access the same memory. + // + // Consider an (array element) expression x%y(w%z), the corresponding symbol + // vector will be {x, y, w, z} (i.e. the symbols for these names). + // Check whether this exact sequence appears anywhere in any the symbol + // vector for "other". This will be true for x(y) and x(y+1), so this is + // not a sufficient condition, but can be used to eliminate candidates + // before doing more exhaustive checks. + // + // If any of the symbols in this sequence are function names, assume that + // there is no storage overlap, mostly because it would be impossible in + // general to determine what storage the function will access. + // Note: if f is pure, then two calls to f will access the same storage + // when called with the same arguments. This check is not done yet. + + if (llvm::any_of( + baseSyms, [](const SymbolRef &s) { return s->IsSubprogram(); })) { + // If there is a function symbol in the chain then we can't infer much + // about the accessed storage. + return false; + } + + auto isSubsequence{// Is u a subsequence of v. + [](const evaluate::SymbolVector &u, const evaluate::SymbolVector &v) { + size_t us{u.size()}, vs{v.size()}; + if (us > vs) { + return false; + } + for (size_t off{0}; off != vs - us + 1; ++off) { + bool same{true}; + for (size_t i{0}; i != us; ++i) { + if (u[i] != v[off + i]) { + same = false; + break; + } + } + if (same) { + return true; + } + } + return false; + }}; + + evaluate::SymbolVector otherSyms{evaluate::GetSymbolVector(other)}; + return isSubsequence(baseSyms, otherSyms); +} + +static bool HasCommonTopLevelDesignators( + const std::vector &baseDsgs, const SomeExpr &other) { + // Compare designators directly as expressions. This will ensure + // that x(y) and x(y+1) are not flagged as overlapping, whereas + // the symbol vectors for both of these would be identical. + std::vector otherDsgs{atomic::DesignatorCollector{}(other)}; + + for (auto &s : baseDsgs) { + if (llvm::any_of(otherDsgs, [&](auto &&t) { return s == t; })) { + return true; } - if (isIntrinsicProcedure) { - std::string varName = var.GetSource().ToString(); - if (numOfSymbolMatches != 1) - context_.Say(expr.source, - "Intrinsic procedure" - " arguments in atomic update statement" - " must have exactly one occurence of '%s'"_err_en_US, - varName); - else if (varSymbol != exprSymbols.front() && - varSymbol != exprSymbols.back()) - context_.Say(expr.source, - "Atomic update statement " - "should be of the form `%s = intrinsic_procedure(%s, expr_list)` " - "OR `%s = intrinsic_procedure(expr_list, %s)`"_err_en_US, - varName, varName, varName, varName); - } else if (isValidOperator) { - if (numOfSymbolMatches != 1) - context_.Say(expr.source, - "Exactly one occurence of '%s' " - "expected on the RHS of atomic update assignment statement"_err_en_US, - var.GetSource().ToString()); + } + return false; +} + +static const SomeExpr *HasStorageOverlap( + const SomeExpr &base, llvm::ArrayRef exprs) { + evaluate::SymbolVector baseSyms{evaluate::GetSymbolVector(base)}; + std::vector baseDsgs{atomic::DesignatorCollector{}(base)}; + + for (const SomeExpr &expr : exprs) { + if (!HasCommonDesignatorSymbols(baseSyms, expr)) { + continue; + } + if (HasCommonTopLevelDesignators(baseDsgs, expr)) { + return &expr; } } + return nullptr; +} + +static bool IsMaybeAtomicWrite(const evaluate::Assignment &assign) { + // This ignores function calls, so it will accept "f(x) = f(x) + 1" + // for example. + return HasStorageOverlap(assign.lhs, assign.rhs) == nullptr; +} - ErrIfAllocatableVariable(var); +static bool IsSubexpressionOf(const SomeExpr &sub, const SomeExpr &super) { + return atomic::VariableFinder{sub}(super); } -void OmpStructureChecker::CheckAtomicCompareConstruct( - const parser::OmpAtomicCompare &atomicCompareConstruct) { +static void SetExpr(parser::TypedExpr &expr, MaybeExpr value) { + if (value) { + expr.Reset(new evaluate::GenericExprWrapper(std::move(value)), + evaluate::GenericExprWrapper::Deleter); + } +} - // TODO: Check that the if-stmt is `if (var == expr) var = new` - // [with or without then/end-do] +static void SetAssignment(parser::AssignmentStmt::TypedAssignment &assign, + std::optional value) { + if (value) { + assign.Reset(new evaluate::GenericAssignmentWrapper(std::move(value)), + evaluate::GenericAssignmentWrapper::Deleter); + } +} - unsigned version{context_.langOptions().OpenMPVersion}; - if (version < 51) { - context_.Say(atomicCompareConstruct.source, - "%s construct not allowed in %s, %s"_err_en_US, - atomicCompareConstruct.source, ThisVersion(version), TryVersion(51)); - } - - // TODO: More work needed here. Some of the Update restrictions need to - // be added, but Update isn't the same either. -} - -// TODO: Allow cond-update-stmt once compare clause is supported. -void OmpStructureChecker::CheckAtomicCaptureConstruct( - const parser::OmpAtomicCapture &atomicCaptureConstruct) { - const parser::AssignmentStmt &stmt1 = - std::get(atomicCaptureConstruct.t) - .v.statement; - const auto &stmt1Var{std::get(stmt1.t)}; - const auto &stmt1Expr{std::get(stmt1.t)}; - const auto *v1 = GetExpr(context_, stmt1Var); - const auto *e1 = GetExpr(context_, stmt1Expr); - - const parser::AssignmentStmt &stmt2 = - std::get(atomicCaptureConstruct.t) - .v.statement; - const auto &stmt2Var{std::get(stmt2.t)}; - const auto &stmt2Expr{std::get(stmt2.t)}; - const auto *v2 = GetExpr(context_, stmt2Var); - const auto *e2 = GetExpr(context_, stmt2Expr); - - if (e1 && v1 && e2 && v2) { - if (semantics::checkForSingleVariableOnRHS(stmt1)) { - CheckAtomicCaptureStmt(stmt1); - if (semantics::checkForSymbolMatch(v2, e2)) { - // ATOMIC CAPTURE construct is of the form [capture-stmt, update-stmt] - CheckAtomicUpdateStmt(stmt2); +static parser::OpenMPAtomicConstruct::Analysis::Op MakeAtomicAnalysisOp( + int what, + const std::optional &maybeAssign = std::nullopt) { + parser::OpenMPAtomicConstruct::Analysis::Op operation; + operation.what = what; + SetAssignment(operation.assign, maybeAssign); + return operation; +} + +static parser::OpenMPAtomicConstruct::Analysis MakeAtomicAnalysis( + const SomeExpr &atom, const MaybeExpr &cond, + parser::OpenMPAtomicConstruct::Analysis::Op &&op0, + parser::OpenMPAtomicConstruct::Analysis::Op &&op1) { + // Defined in flang/include/flang/Parser/parse-tree.h + // + // struct Analysis { + // struct Kind { + // static constexpr int None = 0; + // static constexpr int Read = 1; + // static constexpr int Write = 2; + // static constexpr int Update = Read | Write; + // static constexpr int Action = 3; // Bits containing N, R, W, U + // static constexpr int IfTrue = 4; + // static constexpr int IfFalse = 8; + // static constexpr int Condition = 12; // Bits containing IfTrue, IfFalse + // }; + // struct Op { + // int what; + // TypedAssignment assign; + // }; + // TypedExpr atom, cond; + // Op op0, op1; + // }; + + parser::OpenMPAtomicConstruct::Analysis an; + SetExpr(an.atom, atom); + SetExpr(an.cond, cond); + an.op0 = std::move(op0); + an.op1 = std::move(op1); + return an; +} + +void OmpStructureChecker::CheckStorageOverlap(const SomeExpr &base, + llvm::ArrayRef> exprs, + parser::CharBlock source) { + if (auto *expr{HasStorageOverlap(base, exprs)}) { + context_.Say(source, + "Within atomic operation %s and %s access the same storage"_warn_en_US, + base.AsFortran(), expr->AsFortran()); + } +} + +void OmpStructureChecker::ErrorShouldBeVariable( + const MaybeExpr &expr, parser::CharBlock source) { + if (expr) { + context_.Say(source, "Atomic expression %s should be a variable"_err_en_US, + expr->AsFortran()); + } else { + context_.Say(source, "Atomic expression should be a variable"_err_en_US); + } +} + +/// Check if `expr` satisfies the following conditions for x and v: +/// +/// [6.0:189:10-12] +/// - x and v (as applicable) are either scalar variables or +/// function references with scalar data pointer result of non-character +/// intrinsic type or variables that are non-polymorphic scalar pointers +/// and any length type parameter must be constant. +void OmpStructureChecker::CheckAtomicType( + SymbolRef sym, parser::CharBlock source, std::string_view name) { + const DeclTypeSpec *typeSpec{sym->GetType()}; + if (!typeSpec) { + return; + } + + if (!IsPointer(sym)) { + using Category = DeclTypeSpec::Category; + Category cat{typeSpec->category()}; + if (cat == Category::Character) { + context_.Say(source, + "Atomic variable %s cannot have CHARACTER type"_err_en_US, name); + } else if (cat != Category::Numeric && cat != Category::Logical) { + context_.Say(source, + "Atomic variable %s should have an intrinsic type"_err_en_US, name); + } + return; + } + + // Variable is a pointer. + if (typeSpec->IsPolymorphic()) { + context_.Say(source, + "Atomic variable %s cannot be a pointer to a polymorphic type"_err_en_US, + name); + return; + } + + // Go over all length parameters, if any, and check if they are + // explicit. + if (const DerivedTypeSpec *derived{typeSpec->AsDerived()}) { + if (llvm::any_of(derived->parameters(), [](auto &&entry) { + // "entry" is a map entry + return entry.second.isLen() && !entry.second.isExplicit(); + })) { + context_.Say(source, + "Atomic variable %s is a pointer to a type with non-constant length parameter"_err_en_US, + name); + } + } +} + +void OmpStructureChecker::CheckAtomicVariable( + const SomeExpr &atom, parser::CharBlock source) { + if (atom.Rank() != 0) { + context_.Say(source, "Atomic variable %s should be a scalar"_err_en_US, + atom.AsFortran()); + } + + std::vector dsgs{atomic::DesignatorCollector{}(atom)}; + assert(dsgs.size() == 1 && "Should have a single top-level designator"); + evaluate::SymbolVector syms{evaluate::GetSymbolVector(dsgs.front())}; + + CheckAtomicType(syms.back(), source, atom.AsFortran()); + + if (IsAllocatable(syms.back()) && !IsArrayElement(atom)) { + context_.Say(source, "Atomic variable %s cannot be ALLOCATABLE"_err_en_US, + atom.AsFortran()); + } +} + +std::pair +OmpStructureChecker::CheckUpdateCapture( + const parser::ExecutionPartConstruct *ec1, + const parser::ExecutionPartConstruct *ec2, parser::CharBlock source) { + // Decide which statement is the atomic update and which is the capture. + // + // The two allowed cases are: + // x = ... atomic-var = ... + // ... = x capture-var = atomic-var (with optional converts) + // or + // ... = x capture-var = atomic-var (with optional converts) + // x = ... atomic-var = ... + // + // The case of 'a = b; b = a' is ambiguous, so pick the first one as capture + // (which makes more sense, as it captures the original value of the atomic + // variable). + // + // If the two statements don't fit these criteria, return a pair of default- + // constructed values. + using ReturnTy = std::pair; + + SourcedActionStmt act1{GetActionStmt(ec1)}; + SourcedActionStmt act2{GetActionStmt(ec2)}; + auto maybeAssign1{GetEvaluateAssignment(act1.stmt)}; + auto maybeAssign2{GetEvaluateAssignment(act2.stmt)}; + if (!maybeAssign1 || !maybeAssign2) { + if (!IsAssignment(act1.stmt) || !IsAssignment(act2.stmt)) { + context_.Say(source, + "ATOMIC UPDATE operation with CAPTURE should contain two assignments"_err_en_US); + } + return std::make_pair(nullptr, nullptr); + } + + auto as1{*maybeAssign1}, as2{*maybeAssign2}; + + auto isUpdateCapture{ + [](const evaluate::Assignment &u, const evaluate::Assignment &c) { + return IsSameOrConvertOf(c.rhs, u.lhs); + }}; + + // Do some checks that narrow down the possible choices for the update + // and the capture statements. This will help to emit better diagnostics. + // 1. An assignment could be an update (cbu) if the left-hand side is a + // subexpression of the right-hand side. + // 2. An assignment could be a capture (cbc) if the right-hand side is + // a variable (or a function ref), with potential type conversions. + bool cbu1{IsSubexpressionOf(as1.lhs, as1.rhs)}; // Can as1 be an update? + bool cbu2{IsSubexpressionOf(as2.lhs, as2.rhs)}; // Can as2 be an update? + bool cbc1{IsVarOrFunctionRef(GetConvertInput(as1.rhs))}; // Can 1 be capture? + bool cbc2{IsVarOrFunctionRef(GetConvertInput(as2.rhs))}; // Can 2 be capture? + + // We want to diagnose cases where both assignments cannot be an update, + // or both cannot be a capture, as well as cases where either assignment + // cannot be any of these two. + // + // If we organize these boolean values into a matrix + // |cbu1 cbu2| + // |cbc1 cbc2| + // then we want to diagnose cases where the matrix has a zero (i.e. "false") + // row or column, including the case where everything is zero. All these + // cases correspond to the determinant of the matrix being 0, which suggests + // that checking the det may be a convenient diagnostic check. There is only + // one additional case where the det is 0, which is when the matrix is all 1 + // ("true"). The "all true" case represents the situation where both + // assignments could be an update as well as a capture. On the other hand, + // whenever det != 0, the roles of the update and the capture can be + // unambiguously assigned to as1 and as2 [1]. + // + // [1] This can be easily verified by hand: there are 10 2x2 matrices with + // det = 0, leaving 6 cases where det != 0: + // 0 1 0 1 1 0 1 0 1 1 1 1 + // 1 0 1 1 0 1 1 1 0 1 1 0 + // In each case the classification is unambiguous. + + // |cbu1 cbu2| + // det |cbc1 cbc2| = cbu1*cbc2 - cbu2*cbc1 + int det{int(cbu1) * int(cbc2) - int(cbu2) * int(cbc1)}; + + auto errorCaptureShouldRead{[&](const parser::CharBlock &source, + const std::string &expr) { + context_.Say(source, + "In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read %s"_err_en_US, + expr); + }}; + + auto errorNeitherWorks{[&]() { + context_.Say(source, + "In ATOMIC UPDATE operation with CAPTURE neither statement could be the update or the capture"_err_en_US); + }}; + + auto makeSelectionFromDet{[&](int det) -> ReturnTy { + // If det != 0, then the checks unambiguously suggest a specific + // categorization. + // If det == 0, then this function should be called only if the + // checks haven't ruled out any possibility, i.e. when both assigments + // could still be either updates or captures. + if (det > 0) { + // as1 is update, as2 is capture + if (isUpdateCapture(as1, as2)) { + return std::make_pair(/*Update=*/ec1, /*Capture=*/ec2); } else { - // ATOMIC CAPTURE construct is of the form [capture-stmt, write-stmt] - CheckAtomicWriteStmt(stmt2); + errorCaptureShouldRead(act2.source, as1.lhs.AsFortran()); + return std::make_pair(nullptr, nullptr); } - if (!(*e1 == *v2)) { - context_.Say(stmt1Expr.source, - "Captured variable/array element/derived-type component %s expected to be assigned in the second statement of ATOMIC CAPTURE construct"_err_en_US, - stmt1Expr.source); + } else if (det < 0) { + // as2 is update, as1 is capture + if (isUpdateCapture(as2, as1)) { + return std::make_pair(/*Update=*/ec2, /*Capture=*/ec1); + } else { + errorCaptureShouldRead(act1.source, as2.lhs.AsFortran()); + return std::make_pair(nullptr, nullptr); + } + } else { + bool updateFirst{isUpdateCapture(as1, as2)}; + bool captureFirst{isUpdateCapture(as2, as1)}; + if (updateFirst && captureFirst) { + // If both assignment could be the update and both could be the + // capture, emit a warning about the ambiguity. + context_.Say(act1.source, + "In ATOMIC UPDATE operation with CAPTURE either statement could be the update and the capture, assuming the first one is the capture statement"_warn_en_US); + return std::make_pair(/*Update=*/ec2, /*Capture=*/ec1); } - } else if (semantics::checkForSymbolMatch(v1, e1) && - semantics::checkForSingleVariableOnRHS(stmt2)) { - // ATOMIC CAPTURE construct is of the form [update-stmt, capture-stmt] - CheckAtomicUpdateStmt(stmt1); - CheckAtomicCaptureStmt(stmt2); - // Variable updated in stmt1 should be captured in stmt2 - if (!(*v1 == *e2)) { - context_.Say(stmt1Var.GetSource(), - "Updated variable/array element/derived-type component %s expected to be captured in the second statement of ATOMIC CAPTURE construct"_err_en_US, - stmt1Var.GetSource()); + if (updateFirst != captureFirst) { + const parser::ExecutionPartConstruct *upd{updateFirst ? ec1 : ec2}; + const parser::ExecutionPartConstruct *cap{captureFirst ? ec1 : ec2}; + return std::make_pair(upd, cap); } + assert(!updateFirst && !captureFirst); + errorNeitherWorks(); + return std::make_pair(nullptr, nullptr); + } + }}; + + if (det != 0 || (cbu1 && cbu2 && cbc1 && cbc2)) { + return makeSelectionFromDet(det); + } + assert(det == 0 && "Prior checks should have covered det != 0"); + + // If neither of the statements is an RMW update, it could still be a + // "write" update. Pretty much any assignment can be a write update, so + // recompute det with cbu1 = cbu2 = true. + if (int writeDet{int(cbc2) - int(cbc1)}; writeDet || (cbc1 && cbc2)) { + return makeSelectionFromDet(writeDet); + } + + // It's only errors from here on. + + if (!cbu1 && !cbu2 && !cbc1 && !cbc2) { + errorNeitherWorks(); + return std::make_pair(nullptr, nullptr); + } + + // The remaining cases are that + // - no candidate for update, or for capture, + // - one of the assigments cannot be anything. + + if (!cbu1 && !cbu2) { + context_.Say(source, + "In ATOMIC UPDATE operation with CAPTURE neither statement could be the update"_err_en_US); + return std::make_pair(nullptr, nullptr); + } else if (!cbc1 && !cbc2) { + context_.Say(source, + "In ATOMIC UPDATE operation with CAPTURE neither statement could be the capture"_err_en_US); + return std::make_pair(nullptr, nullptr); + } + + if ((!cbu1 && !cbc1) || (!cbu2 && !cbc2)) { + auto &src = (!cbu1 && !cbc1) ? act1.source : act2.source; + context_.Say(src, + "In ATOMIC UPDATE operation with CAPTURE the statement could be neither the update nor the capture"_err_en_US); + return std::make_pair(nullptr, nullptr); + } + + // All cases should have been covered. + llvm_unreachable("Unchecked condition"); +} + +void OmpStructureChecker::CheckAtomicCaptureAssignment( + const evaluate::Assignment &capture, const SomeExpr &atom, + parser::CharBlock source) { + auto [lsrc, rsrc]{SplitAssignmentSource(source)}; + const SomeExpr &cap{capture.lhs}; + + if (!IsVarOrFunctionRef(atom)) { + ErrorShouldBeVariable(atom, rsrc); + } else { + CheckAtomicVariable(atom, rsrc); + // This part should have been checked prior to calling this function. + assert(*GetConvertInput(capture.rhs) == atom && + "This cannot be a capture assignment"); + CheckStorageOverlap(atom, {cap}, source); + } +} + +void OmpStructureChecker::CheckAtomicReadAssignment( + const evaluate::Assignment &read, parser::CharBlock source) { + auto [lsrc, rsrc]{SplitAssignmentSource(source)}; + + if (auto maybe{GetConvertInput(read.rhs)}) { + const SomeExpr &atom{*maybe}; + + if (!IsVarOrFunctionRef(atom)) { + ErrorShouldBeVariable(atom, rsrc); } else { - context_.Say(stmt1Expr.source, - "Invalid ATOMIC CAPTURE construct statements. Expected one of [update-stmt, capture-stmt], [capture-stmt, update-stmt], or [capture-stmt, write-stmt]"_err_en_US); + CheckAtomicVariable(atom, rsrc); + CheckStorageOverlap(atom, {read.lhs}, source); } + } else { + ErrorShouldBeVariable(read.rhs, rsrc); } } -void OmpStructureChecker::CheckAtomicMemoryOrderClause( - const parser::OmpAtomicClauseList *leftHandClauseList, - const parser::OmpAtomicClauseList *rightHandClauseList) { - int numMemoryOrderClause{0}; - int numFailClause{0}; - auto checkForValidMemoryOrderClause = [&](const parser::OmpAtomicClauseList - *clauseList) { - for (const auto &clause : clauseList->v) { - if (std::get_if(&clause.u)) { - numFailClause++; - if (numFailClause > 1) { - context_.Say(clause.source, - "More than one FAIL clause not allowed on OpenMP ATOMIC construct"_err_en_US); - return; +void OmpStructureChecker::CheckAtomicWriteAssignment( + const evaluate::Assignment &write, parser::CharBlock source) { + // [6.0:190:13-15] + // A write structured block is write-statement, a write statement that has + // one of the following forms: + // x = expr + // x => expr + auto [lsrc, rsrc]{SplitAssignmentSource(source)}; + const SomeExpr &atom{write.lhs}; + + if (!IsVarOrFunctionRef(atom)) { + ErrorShouldBeVariable(atom, rsrc); + } else { + CheckAtomicVariable(atom, lsrc); + CheckStorageOverlap(atom, {write.rhs}, source); + } +} + +void OmpStructureChecker::CheckAtomicUpdateAssignment( + const evaluate::Assignment &update, parser::CharBlock source) { + // [6.0:191:1-7] + // An update structured block is update-statement, an update statement + // that has one of the following forms: + // x = x operator expr + // x = expr operator x + // x = intrinsic-procedure-name (x) + // x = intrinsic-procedure-name (x, expr-list) + // x = intrinsic-procedure-name (expr-list, x) + auto [lsrc, rsrc]{SplitAssignmentSource(source)}; + const SomeExpr &atom{update.lhs}; + + if (!IsVarOrFunctionRef(atom)) { + ErrorShouldBeVariable(atom, rsrc); + // Skip other checks. + return; + } + + CheckAtomicVariable(atom, lsrc); + + std::pair> top{ + operation::Operator::Unknown, {}}; + if (auto &&maybeInput{GetConvertInput(update.rhs)}) { + top = GetTopLevelOperation(*maybeInput); + } + switch (top.first) { + case operation::Operator::Add: + case operation::Operator::Sub: + case operation::Operator::Mul: + case operation::Operator::Div: + case operation::Operator::And: + case operation::Operator::Or: + case operation::Operator::Eqv: + case operation::Operator::Neqv: + case operation::Operator::Min: + case operation::Operator::Max: + case operation::Operator::Identity: + break; + case operation::Operator::Call: + context_.Say(source, + "A call to this function is not a valid ATOMIC UPDATE operation"_err_en_US); + return; + case operation::Operator::Convert: + context_.Say(source, + "An implicit or explicit type conversion is not a valid ATOMIC UPDATE operation"_err_en_US); + return; + case operation::Operator::Intrinsic: + context_.Say(source, + "This intrinsic function is not a valid ATOMIC UPDATE operation"_err_en_US); + return; + case operation::Operator::Constant: + case operation::Operator::Unknown: + context_.Say( + source, "This is not a valid ATOMIC UPDATE operation"_err_en_US); + return; + default: + assert( + top.first != operation::Operator::Identity && "Handle this separately"); + context_.Say(source, + "The %s operator is not a valid ATOMIC UPDATE operation"_err_en_US, + operation::ToString(top.first)); + return; + } + // Check if `atom` occurs exactly once in the argument list. + 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; } else { - if (std::get_if(&clause.u)) { - numMemoryOrderClause++; - if (numMemoryOrderClause > 1) { - context_.Say(clause.source, - "More than one memory order clause not allowed on OpenMP ATOMIC construct"_err_en_US); - return; - } + nonAtom.push_back(*i); + } + } + return found; + }()}; + + if (unique == top.second.end()) { + if (top.first == operation::Operator::Identity) { + // This is "x = y". + 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)); + } + } else { + CheckStorageOverlap(atom, nonAtom, source); + } +} + +void OmpStructureChecker::CheckAtomicConditionalUpdateAssignment( + const SomeExpr &cond, parser::CharBlock condSource, + const evaluate::Assignment &assign, parser::CharBlock assignSource) { + auto [alsrc, arsrc]{SplitAssignmentSource(assignSource)}; + const SomeExpr &atom{assign.lhs}; + + if (!IsVarOrFunctionRef(atom)) { + ErrorShouldBeVariable(atom, arsrc); + // Skip other checks. + return; + } + + CheckAtomicVariable(atom, alsrc); + + auto top{GetTopLevelOperation(cond)}; + // Missing arguments to operations would have been diagnosed by now. + + switch (top.first) { + case operation::Operator::Associated: + if (atom != top.second.front()) { + context_.Say(assignSource, + "The pointer argument to ASSOCIATED must be same as the target of the assignment"_err_en_US); + } + break; + // x equalop e | e equalop x (allowing "e equalop x" is an extension) + case operation::Operator::Eq: + case operation::Operator::Eqv: + // x ordop expr | expr ordop x + case operation::Operator::Lt: + case operation::Operator::Gt: { + const SomeExpr &arg0{top.second[0]}; + const SomeExpr &arg1{top.second[1]}; + if (IsSameOrConvertOf(arg0, atom)) { + CheckStorageOverlap(atom, {arg1}, condSource); + } else if (IsSameOrConvertOf(arg1, atom)) { + CheckStorageOverlap(atom, {arg0}, condSource); + } else { + assert(top.first != operation::Operator::Identity && + "Handle this separately"); + context_.Say(assignSource, + "An argument of the %s operator should be the target of the assignment"_err_en_US, + operation::ToString(top.first)); + } + break; + } + case operation::Operator::Identity: + case operation::Operator::True: + case operation::Operator::False: + break; + default: + assert( + top.first != operation::Operator::Identity && "Handle this separately"); + context_.Say(condSource, + "The %s operator is not a valid condition for ATOMIC operation"_err_en_US, + operation::ToString(top.first)); + break; + } +} + +void OmpStructureChecker::CheckAtomicConditionalUpdateStmt( + const AnalyzedCondStmt &update, parser::CharBlock source) { + // The condition/statements must be: + // - cond: x equalop e ift: x = d iff: - + // - cond: x ordop expr ift: x = expr iff: - (+ commute ordop) + // - cond: associated(x) ift: x => expr iff: - + // - cond: associated(x, e) ift: x => expr iff: - + + // The if-true statement must be present, and must be an assignment. + auto maybeAssign{GetEvaluateAssignment(update.ift.stmt)}; + if (!maybeAssign) { + if (update.ift.stmt && !IsAssignment(update.ift.stmt)) { + context_.Say(update.ift.source, + "In ATOMIC UPDATE COMPARE the update statement should be an assignment"_err_en_US); + } else { + context_.Say( + source, "Invalid body of ATOMIC UPDATE COMPARE operation"_err_en_US); + } + return; + } + const evaluate::Assignment assign{*maybeAssign}; + const SomeExpr &atom{assign.lhs}; + + CheckAtomicConditionalUpdateAssignment( + update.cond, update.source, assign, update.ift.source); + + CheckStorageOverlap(atom, {assign.rhs}, update.ift.source); + + if (update.iff) { + context_.Say(update.iff.source, + "In ATOMIC UPDATE COMPARE the update statement should not have an ELSE branch"_err_en_US); + } +} + +void OmpStructureChecker::CheckAtomicUpdateOnly( + const parser::OpenMPAtomicConstruct &x, const parser::Block &body, + parser::CharBlock source) { + if (body.size() == 1) { + SourcedActionStmt action{GetActionStmt(&body.front())}; + if (auto maybeUpdate{GetEvaluateAssignment(action.stmt)}) { + const SomeExpr &atom{maybeUpdate->lhs}; + CheckAtomicUpdateAssignment(*maybeUpdate, action.source); + + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + x.analysis = MakeAtomicAnalysis(atom, std::nullopt, + MakeAtomicAnalysisOp(Analysis::Update, maybeUpdate), + MakeAtomicAnalysisOp(Analysis::None)); + } else if (!IsAssignment(action.stmt)) { + context_.Say( + source, "ATOMIC UPDATE operation should be an assignment"_err_en_US); + } + } else { + context_.Say(x.source, + "ATOMIC UPDATE operation should have a single statement"_err_en_US); + } +} + +void OmpStructureChecker::CheckAtomicConditionalUpdate( + const parser::OpenMPAtomicConstruct &x, const parser::Block &body, + parser::CharBlock source) { + // Allowable forms are (single-statement): + // - if ... + // - x = (... ? ... : x) + // and two-statement: + // - r = cond ; if (r) ... + + const parser::ExecutionPartConstruct *ust{nullptr}; // update + const parser::ExecutionPartConstruct *cst{nullptr}; // condition + + if (body.size() == 1) { + ust = &body.front(); + } else if (body.size() == 2) { + cst = &body.front(); + ust = &body.back(); + } else { + context_.Say(source, + "ATOMIC UPDATE COMPARE operation should contain one or two statements"_err_en_US); + return; + } + + // Flang doesn't support conditional-expr yet, so all update statements + // are if-statements. + + // IfStmt: if (...) ... + // IfConstruct: if (...) then ... endif + auto maybeUpdate{AnalyzeConditionalStmt(ust)}; + if (!maybeUpdate) { + context_.Say(source, + "In ATOMIC UPDATE COMPARE the update statement should be a conditional statement"_err_en_US); + return; + } + + AnalyzedCondStmt &update{*maybeUpdate}; + + if (SourcedActionStmt action{GetActionStmt(cst)}) { + // The "condition" statement must be `r = cond`. + if (auto maybeCond{GetEvaluateAssignment(action.stmt)}) { + if (maybeCond->lhs != update.cond) { + context_.Say(update.source, + "In ATOMIC UPDATE COMPARE the conditional statement must use %s as the condition"_err_en_US, + maybeCond->lhs.AsFortran()); + } else { + // If it's "r = ...; if (r) ..." then put the original condition + // in `update`. + update.cond = maybeCond->rhs; + } + } else { + context_.Say(action.source, + "In ATOMIC UPDATE COMPARE with two statements the first statement should compute the condition"_err_en_US); + } + } + + evaluate::Assignment assign{*GetEvaluateAssignment(update.ift.stmt)}; + + CheckAtomicConditionalUpdateStmt(update, source); + if (IsCheckForAssociated(update.cond)) { + if (!IsPointerAssignment(assign)) { + context_.Say(source, + "The assignment should be a pointer-assignment when the condition is ASSOCIATED"_err_en_US); + } + } else { + if (IsPointerAssignment(assign)) { + context_.Say(source, + "The assignment cannot be a pointer-assignment except when the condition is ASSOCIATED"_err_en_US); + } + } + + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + x.analysis = MakeAtomicAnalysis(assign.lhs, update.cond, + MakeAtomicAnalysisOp(Analysis::Update | Analysis::IfTrue, assign), + MakeAtomicAnalysisOp(Analysis::None)); +} + +void OmpStructureChecker::CheckAtomicUpdateCapture( + const parser::OpenMPAtomicConstruct &x, const parser::Block &body, + parser::CharBlock source) { + if (body.size() != 2) { + context_.Say(source, + "ATOMIC UPDATE operation with CAPTURE should contain two statements"_err_en_US); + return; + } + + auto [uec, cec]{CheckUpdateCapture(&body.front(), &body.back(), source)}; + if (!uec || !cec) { + // Diagnostics already emitted. + return; + } + SourcedActionStmt uact{GetActionStmt(uec)}; + SourcedActionStmt cact{GetActionStmt(cec)}; + // The "dereferences" of std::optional are guaranteed to be valid after + // CheckUpdateCapture. + evaluate::Assignment update{*GetEvaluateAssignment(uact.stmt)}; + evaluate::Assignment capture{*GetEvaluateAssignment(cact.stmt)}; + + const SomeExpr &atom{update.lhs}; + + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + int action; + + if (IsMaybeAtomicWrite(update)) { + action = Analysis::Write; + CheckAtomicWriteAssignment(update, uact.source); + } else { + action = Analysis::Update; + CheckAtomicUpdateAssignment(update, uact.source); + } + CheckAtomicCaptureAssignment(capture, atom, cact.source); + + if (IsPointerAssignment(update) != IsPointerAssignment(capture)) { + context_.Say(cact.source, + "The update and capture assignments should both be pointer-assignments or both be non-pointer-assignments"_err_en_US); + return; + } + + if (GetActionStmt(&body.front()).stmt == uact.stmt) { + x.analysis = MakeAtomicAnalysis(atom, std::nullopt, + MakeAtomicAnalysisOp(action, update), + MakeAtomicAnalysisOp(Analysis::Read, capture)); + } else { + x.analysis = MakeAtomicAnalysis(atom, std::nullopt, + MakeAtomicAnalysisOp(Analysis::Read, capture), + MakeAtomicAnalysisOp(action, update)); + } +} + +void OmpStructureChecker::CheckAtomicConditionalUpdateCapture( + const parser::OpenMPAtomicConstruct &x, const parser::Block &body, + parser::CharBlock source) { + // There are two different variants of this: + // (1) conditional-update and capture separately: + // This form only allows single-statement updates, i.e. the update + // form "r = cond; if (r) ..." is not allowed. + // (2) conditional-update combined with capture in a single statement: + // This form does allow the condition to be calculated separately, + // i.e. "r = cond; if (r) ...". + // Regardless of what form it is, the actual update assignment is a + // proper write, i.e. "x = d", where d does not depend on x. + + AnalyzedCondStmt update; + SourcedActionStmt capture; + bool captureAlways{true}, captureFirst{true}; + + auto extractCapture{[&]() { + capture = update.iff; + captureAlways = false; + update.iff = SourcedActionStmt{}; + }}; + + auto classifyNonUpdate{[&](const SourcedActionStmt &action) { + // The non-update statement is either "r = cond" or the capture. + if (auto maybeAssign{GetEvaluateAssignment(action.stmt)}) { + if (update.cond == maybeAssign->lhs) { + // If this is "r = cond; if (r) ...", then update the condition. + update.cond = maybeAssign->rhs; + update.source = action.source; + // In this form, the update and the capture are combined into + // an IF-THEN-ELSE statement. + extractCapture(); + } else { + // Assume this is the capture-statement. + capture = action; + } + } + }}; + + if (body.size() == 2) { + // This could be + // - capture; conditional-update (in any order), or + // - r = cond; if (r) capture-update + const parser::ExecutionPartConstruct *st1{&body.front()}; + const parser::ExecutionPartConstruct *st2{&body.back()}; + // In either case, the conditional statement can be analyzed by + // AnalyzeConditionalStmt, whereas the other statement cannot. + if (auto maybeUpdate1{AnalyzeConditionalStmt(st1)}) { + update = *maybeUpdate1; + classifyNonUpdate(GetActionStmt(st2)); + captureFirst = false; + } else if (auto maybeUpdate2{AnalyzeConditionalStmt(st2)}) { + update = *maybeUpdate2; + classifyNonUpdate(GetActionStmt(st1)); + } else { + // None of the statements are conditional, this rules out the + // "r = cond; if (r) ..." and the "capture + conditional-update" + // variants. This could still be capture + write (which is classified + // as conditional-update-capture in the spec). + auto [uec, cec]{CheckUpdateCapture(st1, st2, source)}; + if (!uec || !cec) { + // Diagnostics already emitted. + return; + } + SourcedActionStmt uact{GetActionStmt(uec)}; + SourcedActionStmt cact{GetActionStmt(cec)}; + update.ift = uact; + capture = cact; + if (uec == st1) { + captureFirst = false; + } + } + } else if (body.size() == 1) { + if (auto maybeUpdate{AnalyzeConditionalStmt(&body.front())}) { + update = *maybeUpdate; + // This is the form with update and capture combined into an IF-THEN-ELSE + // statement. The capture-statement is always the ELSE branch. + extractCapture(); + } else { + goto invalid; + } + } else { + context_.Say(source, + "ATOMIC UPDATE COMPARE CAPTURE operation should contain one or two statements"_err_en_US); + return; + invalid: + context_.Say(source, + "Invalid body of ATOMIC UPDATE COMPARE CAPTURE operation"_err_en_US); + return; + } + + // The update must have a form `x = d` or `x => d`. + if (auto maybeWrite{GetEvaluateAssignment(update.ift.stmt)}) { + const SomeExpr &atom{maybeWrite->lhs}; + CheckAtomicWriteAssignment(*maybeWrite, update.ift.source); + if (auto maybeCapture{GetEvaluateAssignment(capture.stmt)}) { + CheckAtomicCaptureAssignment(*maybeCapture, atom, capture.source); + + if (IsPointerAssignment(*maybeWrite) != + IsPointerAssignment(*maybeCapture)) { + context_.Say(capture.source, + "The update and capture assignments should both be pointer-assignments or both be non-pointer-assignments"_err_en_US); + return; + } + } else { + if (!IsAssignment(capture.stmt)) { + context_.Say(capture.source, + "In ATOMIC UPDATE COMPARE CAPTURE the capture statement should be an assignment"_err_en_US); + } + return; + } + } else { + if (!IsAssignment(update.ift.stmt)) { + context_.Say(update.ift.source, + "In ATOMIC UPDATE COMPARE CAPTURE the update statement should be an assignment"_err_en_US); + } + return; + } + + // update.iff should be empty here, the capture statement should be + // stored in "capture". + + // Fill out the analysis in the AST node. + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + bool condUnused{std::visit( + [](auto &&s) { + using BareS = llvm::remove_cvref_t; + if constexpr (std::is_same_v) { + return true; + } else { + return false; } + }, + update.cond.u)}; + + int updateWhen{!condUnused ? Analysis::IfTrue : 0}; + int captureWhen{!captureAlways ? Analysis::IfFalse : 0}; + + evaluate::Assignment updAssign{*GetEvaluateAssignment(update.ift.stmt)}; + evaluate::Assignment capAssign{*GetEvaluateAssignment(capture.stmt)}; + + if (captureFirst) { + x.analysis = MakeAtomicAnalysis(updAssign.lhs, update.cond, + MakeAtomicAnalysisOp(Analysis::Read | captureWhen, capAssign), + MakeAtomicAnalysisOp(Analysis::Write | updateWhen, updAssign)); + } else { + x.analysis = MakeAtomicAnalysis(updAssign.lhs, update.cond, + MakeAtomicAnalysisOp(Analysis::Write | updateWhen, updAssign), + MakeAtomicAnalysisOp(Analysis::Read | captureWhen, capAssign)); + } +} + +void OmpStructureChecker::CheckAtomicRead( + const parser::OpenMPAtomicConstruct &x) { + // [6.0:190:5-7] + // A read structured block is read-statement, a read statement that has one + // of the following forms: + // v = x + // v => x + auto &dirSpec{std::get(x.t)}; + auto &block{std::get(x.t)}; + + // Read cannot be conditional or have a capture statement. + if (x.IsCompare() || x.IsCapture()) { + context_.Say(dirSpec.source, + "ATOMIC READ cannot have COMPARE or CAPTURE clauses"_err_en_US); + return; + } + + const parser::Block &body{GetInnermostExecPart(block)}; + + if (body.size() == 1) { + SourcedActionStmt action{GetActionStmt(&body.front())}; + if (auto maybeRead{GetEvaluateAssignment(action.stmt)}) { + CheckAtomicReadAssignment(*maybeRead, action.source); + + if (auto maybe{GetConvertInput(maybeRead->rhs)}) { + const SomeExpr &atom{*maybe}; + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + x.analysis = MakeAtomicAnalysis(atom, std::nullopt, + MakeAtomicAnalysisOp(Analysis::Read, maybeRead), + MakeAtomicAnalysisOp(Analysis::None)); } + } else if (!IsAssignment(action.stmt)) { + context_.Say( + x.source, "ATOMIC READ operation should be an assignment"_err_en_US); } - }; - if (leftHandClauseList) { - checkForValidMemoryOrderClause(leftHandClauseList); + } else { + context_.Say(x.source, + "ATOMIC READ operation should have a single statement"_err_en_US); } - if (rightHandClauseList) { - checkForValidMemoryOrderClause(rightHandClauseList); +} + +void OmpStructureChecker::CheckAtomicWrite( + const parser::OpenMPAtomicConstruct &x) { + auto &dirSpec{std::get(x.t)}; + auto &block{std::get(x.t)}; + + // Write cannot be conditional or have a capture statement. + if (x.IsCompare() || x.IsCapture()) { + context_.Say(dirSpec.source, + "ATOMIC WRITE cannot have COMPARE or CAPTURE clauses"_err_en_US); + return; + } + + const parser::Block &body{GetInnermostExecPart(block)}; + + if (body.size() == 1) { + SourcedActionStmt action{GetActionStmt(&body.front())}; + if (auto maybeWrite{GetEvaluateAssignment(action.stmt)}) { + const SomeExpr &atom{maybeWrite->lhs}; + CheckAtomicWriteAssignment(*maybeWrite, action.source); + + using Analysis = parser::OpenMPAtomicConstruct::Analysis; + x.analysis = MakeAtomicAnalysis(atom, std::nullopt, + MakeAtomicAnalysisOp(Analysis::Write, maybeWrite), + MakeAtomicAnalysisOp(Analysis::None)); + } else if (!IsAssignment(action.stmt)) { + context_.Say( + x.source, "ATOMIC WRITE operation should be an assignment"_err_en_US); + } + } else { + context_.Say(x.source, + "ATOMIC WRITE operation should have a single statement"_err_en_US); + } +} + +void OmpStructureChecker::CheckAtomicUpdate( + const parser::OpenMPAtomicConstruct &x) { + auto &block{std::get(x.t)}; + + bool isConditional{x.IsCompare()}; + bool isCapture{x.IsCapture()}; + const parser::Block &body{GetInnermostExecPart(block)}; + + if (isConditional && isCapture) { + CheckAtomicConditionalUpdateCapture(x, body, x.source); + } else if (isConditional) { + CheckAtomicConditionalUpdate(x, body, x.source); + } else if (isCapture) { + CheckAtomicUpdateCapture(x, body, x.source); + } else { // update-only + CheckAtomicUpdateOnly(x, body, x.source); } } void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) { - common::visit( - common::visitors{ - [&](const parser::OmpAtomic &atomicConstruct) { - const auto &dir{std::get(atomicConstruct.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicUpdateStmt( - std::get>( - atomicConstruct.t) - .statement); - CheckAtomicMemoryOrderClause( - &std::get(atomicConstruct.t), - nullptr); - CheckHintClause( - &std::get(atomicConstruct.t), - nullptr, "ATOMIC"); - }, - [&](const parser::OmpAtomicUpdate &atomicUpdate) { - const auto &dir{std::get(atomicUpdate.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicUpdateStmt( - std::get>( - atomicUpdate.t) - .statement); - CheckAtomicMemoryOrderClause( - &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t)); - CheckHintClause( - &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t), - "UPDATE"); - }, - [&](const parser::OmpAtomicRead &atomicRead) { - const auto &dir{std::get(atomicRead.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicMemoryOrderClause( - &std::get<0>(atomicRead.t), &std::get<2>(atomicRead.t)); - CheckHintClause( - &std::get<0>(atomicRead.t), &std::get<2>(atomicRead.t), "READ"); - CheckAtomicCaptureStmt( - std::get>( - atomicRead.t) - .statement); - }, - [&](const parser::OmpAtomicWrite &atomicWrite) { - const auto &dir{std::get(atomicWrite.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicMemoryOrderClause( - &std::get<0>(atomicWrite.t), &std::get<2>(atomicWrite.t)); - CheckHintClause( - &std::get<0>(atomicWrite.t), &std::get<2>(atomicWrite.t), - "WRITE"); - CheckAtomicWriteStmt( - std::get>( - atomicWrite.t) - .statement); - }, - [&](const parser::OmpAtomicCapture &atomicCapture) { - const auto &dir{std::get(atomicCapture.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicMemoryOrderClause( - &std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t)); - CheckHintClause( - &std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t), - "CAPTURE"); - CheckAtomicCaptureConstruct(atomicCapture); - }, - [&](const parser::OmpAtomicCompare &atomicCompare) { - const auto &dir{std::get(atomicCompare.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicMemoryOrderClause( - &std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t)); - CheckHintClause( - &std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t), - "CAPTURE"); - CheckAtomicCompareConstruct(atomicCompare); - }, - }, - x.u); + // 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 + // clauses, with clause groups defined in OMP.td. + std::array atomic{llvm::omp::Clause::OMPC_read, + llvm::omp::Clause::OMPC_update, llvm::omp::Clause::OMPC_write}; + std::array memoryOrder{llvm::omp::Clause::OMPC_acq_rel, + llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_relaxed, + llvm::omp::Clause::OMPC_release, llvm::omp::Clause::OMPC_seq_cst}; + + auto checkExclusive{[&](llvm::ArrayRef group, + std::string_view name, + const parser::OmpClauseList &clauses) { + const parser::OmpClause *present{nullptr}; + for (const parser::OmpClause &clause : clauses.v) { + llvm::omp::Clause id{clause.Id()}; + if (!llvm::is_contained(group, id)) { + continue; + } + if (present == nullptr) { + present = &clause; + continue; + } else if (id == present->Id()) { + // Ignore repetitions of the same clause, those will be diagnosed + // separately. + continue; + } + parser::MessageFormattedText txt( + "At most one clause from the '%s' group is allowed on ATOMIC construct"_err_en_US, + name.data()); + parser::Message message(clause.source, txt); + message.Attach(present->source, + "Previous clause from this group provided here"_en_US); + context_.Say(std::move(message)); + return; + } + }}; + + auto &dirSpec{std::get(x.t)}; + auto &dir{std::get(dirSpec.t)}; + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_atomic); + llvm::omp::Clause kind{x.GetKind()}; + + checkExclusive(atomic, "atomic", dirSpec.Clauses()); + checkExclusive(memoryOrder, "memory-order", dirSpec.Clauses()); + + switch (kind) { + case llvm::omp::Clause::OMPC_read: + CheckAtomicRead(x); + break; + case llvm::omp::Clause::OMPC_write: + CheckAtomicWrite(x); + break; + case llvm::omp::Clause::OMPC_update: + CheckAtomicUpdate(x); + break; + default: + break; + } } void OmpStructureChecker::Leave(const parser::OpenMPAtomicConstruct &) { @@ -3332,7 +4345,6 @@ CHECK_SIMPLE_CLAUSE(Final, OMPC_final) CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush) CHECK_SIMPLE_CLAUSE(Full, OMPC_full) CHECK_SIMPLE_CLAUSE(Grainsize, OMPC_grainsize) -CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint) CHECK_SIMPLE_CLAUSE(Holds, OMPC_holds) CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive) CHECK_SIMPLE_CLAUSE(Initializer, OMPC_initializer) @@ -4014,40 +5026,6 @@ void OmpStructureChecker::CheckIsLoopIvPartOfClause( } } } -// Following clauses have a separate node in parse-tree.h. -// Atomic-clause -CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read) -CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write) -CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicUpdate, OMPC_update) -CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicCapture, OMPC_capture) - -void OmpStructureChecker::Leave(const parser::OmpAtomicRead &) { - CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_read, - {llvm::omp::Clause::OMPC_release, llvm::omp::Clause::OMPC_acq_rel}); -} - -void OmpStructureChecker::Leave(const parser::OmpAtomicWrite &) { - CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_write, - {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel}); -} - -void OmpStructureChecker::Leave(const parser::OmpAtomicUpdate &) { - CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_update, - {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel}); -} - -// OmpAtomic node represents atomic directive without atomic-clause. -// atomic-clause - READ,WRITE,UPDATE,CAPTURE. -void OmpStructureChecker::Leave(const parser::OmpAtomic &) { - if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acquire)}) { - context_.Say(clause->source, - "Clause ACQUIRE is not allowed on the ATOMIC directive"_err_en_US); - } - if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acq_rel)}) { - context_.Say(clause->source, - "Clause ACQ_REL is not allowed on the ATOMIC directive"_err_en_US); - } -} // Restrictions specific to each clause are implemented apart from the // generalized restrictions. @@ -5026,21 +6004,6 @@ void OmpStructureChecker::Leave(const parser::OmpContextSelector &) { ExitDirectiveNest(ContextSelectorNest); } -std::optional OmpStructureChecker::GetDynamicType( - const common::Indirection &parserExpr) { - // Indirection parserExpr - // `- parser::Expr ^.value() - const parser::TypedExpr &typedExpr{parserExpr.value().typedExpr}; - // ForwardOwningPointer typedExpr - // `- GenericExprWrapper ^.get() - // `- std::optional ^->v - if (auto maybeExpr{typedExpr.get()->v}) { - return maybeExpr->GetType(); - } else { - return std::nullopt; - } -} - const std::list & OmpStructureChecker::GetTraitPropertyList( const parser::OmpTraitSelector &trait) { @@ -5430,7 +6393,7 @@ void OmpStructureChecker::CheckTraitCondition( const parser::OmpTraitProperty &property{properties.front()}; auto &scalarExpr{std::get(property.u)}; - auto maybeType{GetDynamicType(scalarExpr.thing)}; + auto maybeType{GetDynamicType(scalarExpr.thing.value())}; if (!maybeType || maybeType->category() != TypeCategory::Logical) { context_.Say(property.source, "%s trait requires a single LOGICAL expression"_err_en_US, @@ -5571,6 +6534,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{ @@ -5588,6 +6574,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)}; @@ -5611,6 +6601,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 1a8059d8548ed..2074ec611dc2a 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -48,6 +48,7 @@ static const OmpDirectiveSet noWaitClauseNotAllowedSet{ } // namespace llvm namespace Fortran::semantics { +struct AnalyzedCondStmt; // Mapping from 'Symbol' to 'Source' to keep track of the variables // used in multiple clauses @@ -144,15 +145,6 @@ class OmpStructureChecker void Leave(const parser::OmpClauseList &); void Enter(const parser::OmpClause &); - void Enter(const parser::OmpAtomicRead &); - void Leave(const parser::OmpAtomicRead &); - void Enter(const parser::OmpAtomicWrite &); - void Leave(const parser::OmpAtomicWrite &); - void Enter(const parser::OmpAtomicUpdate &); - void Leave(const parser::OmpAtomicUpdate &); - void Enter(const parser::OmpAtomicCapture &); - void Leave(const parser::OmpAtomic &); - void Enter(const parser::DoConstruct &); void Leave(const parser::DoConstruct &); @@ -192,8 +184,6 @@ class OmpStructureChecker void CheckAllowedMapTypes(const parser::OmpMapType::Value &, const std::list &); - std::optional GetDynamicType( - const common::Indirection &); const std::list &GetTraitPropertyList( const parser::OmpTraitSelector &); std::optional GetClauseFromProperty( @@ -265,14 +255,44 @@ class OmpStructureChecker void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x); template bool IsOperatorValid(const T &, const D &); - void CheckAtomicMemoryOrderClause( - const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); - void CheckAtomicUpdateStmt(const parser::AssignmentStmt &); - void CheckAtomicCaptureStmt(const parser::AssignmentStmt &); - void CheckAtomicWriteStmt(const parser::AssignmentStmt &); - void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &); - void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &); - void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); + + void CheckStorageOverlap(const evaluate::Expr &, + llvm::ArrayRef>, parser::CharBlock); + void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source); + void CheckAtomicType( + SymbolRef sym, parser::CharBlock source, std::string_view name); + void CheckAtomicVariable( + const evaluate::Expr &, parser::CharBlock); + std::pair + CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1, + const parser::ExecutionPartConstruct *ec2, parser::CharBlock source); + void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture, + const SomeExpr &atom, parser::CharBlock source); + void CheckAtomicReadAssignment( + const evaluate::Assignment &read, parser::CharBlock source); + void CheckAtomicWriteAssignment( + const evaluate::Assignment &write, parser::CharBlock source); + void CheckAtomicUpdateAssignment( + const evaluate::Assignment &update, parser::CharBlock source); + void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond, + parser::CharBlock condSource, const evaluate::Assignment &assign, + parser::CharBlock assignSource); + void CheckAtomicConditionalUpdateStmt( + const AnalyzedCondStmt &update, parser::CharBlock source); + void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x, + const parser::Block &body, parser::CharBlock source); + void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x, + const parser::Block &body, parser::CharBlock source); + void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x, + const parser::Block &body, parser::CharBlock source); + void CheckAtomicConditionalUpdateCapture( + const parser::OpenMPAtomicConstruct &x, const parser::Block &body, + parser::CharBlock source); + void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x); + void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x); + void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x); + void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); void CheckTargetNest(const parser::OpenMPConstruct &x); @@ -324,7 +344,6 @@ class OmpStructureChecker void EnterDirectiveNest(const int index) { directiveNest_[index]++; } void ExitDirectiveNest(const int index) { directiveNest_[index]--; } int GetDirectiveNest(const int index) { return directiveNest_[index]; } - template void CheckHintClause(D *, D *, std::string_view); inline void ErrIfAllocatableVariable(const parser::Variable &); inline void ErrIfLHSAndRHSSymbolsMatch( const parser::Variable &, const parser::Expr &); diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index a72641866aa15..82c8536902eb2 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 65823adcef19d..282660684e78a 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -384,6 +384,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { 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(); } @@ -2003,6 +2006,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)}; @@ -2382,7 +2391,9 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) { dsa = prevDSA; } else if (taskGenDir) { // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate - if (prevDSA.test(Symbol::Flag::OmpShared) || isStaticStorageDuration) { + if (prevDSA.test(Symbol::Flag::OmpShared) || + (isStaticStorageDuration && + (prevDSA & dataSharingAttributeFlags).none())) { // 6) shared in enclosing context -> shared dsa = {Symbol::Flag::OmpShared}; makeSymbol(dsa); @@ -3021,10 +3032,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_ @@ -3036,7 +3056,7 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source, } if (sourceContext && (!targetContext || - (sourceContext->scope != targetContext->scope && + (!dirContextsSame(*sourceContext, *targetContext) && !DoesScopeContain( &sourceContext->scope, targetContext->scope)))) { context_ diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 3e133b156a9f3..f66918e5c140e 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1684,11 +1684,8 @@ class OmpVisitor : public virtual DeclarationVisitor { messageHandler().set_currStmtSource(std::nullopt); } bool Pre(const parser::OpenMPAtomicConstruct &x) { - return common::visit(common::visitors{[&](const auto &u) -> bool { - AddOmpSourceRange(u.source); - return true; - }}, - x.u); + AddOmpSourceRange(x.source); + return true; } void Post(const parser::OpenMPAtomicConstruct &) { messageHandler().set_currStmtSource(std::nullopt); @@ -1732,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; @@ -2831,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)); } @@ -2870,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()}; @@ -9558,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()) { @@ -9626,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) { @@ -10190,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 index 104a77885d276..91b60ea151dee 100644 --- a/flang/lib/Semantics/rewrite-directives.cpp +++ b/flang/lib/Semantics/rewrite-directives.cpp @@ -51,23 +51,21 @@ class OmpRewriteMutator : public DirectiveRewriteMutator { bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) { // Find top-level parent of the operation. - Symbol *topLevelParent{common::visit( - [&](auto &atomic) { - Symbol *symbol{nullptr}; - Scope *scope{ - &context_.FindScope(std::get(atomic.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; - }, - x.u)}; + 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; @@ -86,66 +84,61 @@ bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) { return false; } - auto findMemOrderClause = - [](const std::list &clauses) { - return llvm::any_of(clauses, [](const auto &clause) { - return std::get_if(&clause.u); + 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; + } }); - }; - - // Get the clause list to which the new memory order clause must be added, - // only if there are no other memory order clauses present for this atomic - // directive. - std::list *clauseList = common::visit( - common::visitors{[&](parser::OmpAtomic &atomicConstruct) { - // OmpAtomic only has a single list of clauses. - auto &clauses{std::get( - atomicConstruct.t)}; - return !findMemOrderClause(clauses.v) ? &clauses.v - : nullptr; - }, - [&](auto &atomicConstruct) { - // All other atomic constructs have two lists of clauses. - auto &clausesLhs{std::get<0>(atomicConstruct.t)}; - auto &clausesRhs{std::get<2>(atomicConstruct.t)}; - return !findMemOrderClause(clausesLhs.v) && - !findMemOrderClause(clausesRhs.v) - ? &clausesRhs.v - : nullptr; - }}, - x.u); + }}; - // Add a memory order clause to the atomic directive. + auto &dirSpec{std::get(x.t)}; + auto &clauseList{std::get>(dirSpec.t)}; if (clauseList) { - atomicDirectiveDefaultOrderFound_ = true; - switch (*defaultMemOrder) { - case common::OmpMemoryOrderType::Acq_Rel: - clauseList->emplace_back(common::visit( - common::visitors{[](parser::OmpAtomicRead &) -> parser::OmpClause { - return parser::OmpClause::Acquire{}; - }, - [](parser::OmpAtomicCapture &) -> parser::OmpClause { - return parser::OmpClause::AcqRel{}; - }, - [](auto &) -> parser::OmpClause { - // parser::{OmpAtomic, OmpAtomicUpdate, OmpAtomicWrite} - return parser::OmpClause::Release{}; - }}, - x.u)); - break; - case common::OmpMemoryOrderType::Relaxed: - clauseList->emplace_back( - parser::OmpClause{parser::OmpClause::Relaxed{}}); - break; - case common::OmpMemoryOrderType::Seq_Cst: - clauseList->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; + if (findMemOrderClause(*clauseList)) { + return false; + } + } else { + clauseList = parser::OmpClauseList(decltype(parser::OmpClauseList::v){}); + } + + // Add a memory order clause to the atomic directive. + atomicDirectiveDefaultOrderFound_ = true; + llvm::omp::Clause kind{x.GetKind()}; + switch (*defaultMemOrder) { + case common::OmpMemoryOrderType::Acq_Rel: + // FIXME: Implement 5.0 rules, pending clarification on later spec + // versions. + // [5.0:62:22-26] + if (kind == llvm::omp::Clause::OMPC_read) { + clauseList->v.emplace_back( + parser::OmpClause{parser::OmpClause::Acquire{}}); + } else if (kind == llvm::omp::Clause::OMPC_update && x.IsCapture()) { + clauseList->v.emplace_back( + parser::OmpClause{parser::OmpClause::AcqRel{}}); + } else { + clauseList->v.emplace_back( + parser::OmpClause{parser::OmpClause::Release{}}); } + 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; diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index ccc5e37c840a9..51ba21a9e5edf 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -82,17 +82,17 @@ class RuntimeTableBuilder { 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 (auto pair : dtScope) { + 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,14 +1249,25 @@ 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, SomeExpr{evaluate::ProcedureDesignator{specific}}); // index might already be present in the case of an override - specials.emplace(*index, + specials.insert_or_assign(*index, evaluate::StructureConstructor{ DEREF(specialSchema_.AsDerived()), std::move(values)}); } @@ -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 1d1e3ac044166..bf520d04a50cc 100644 --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -17,6 +17,7 @@ #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 @@ -813,6 +814,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 && @@ -1756,4 +1789,332 @@ bool HadUseError( } } -} // namespace Fortran::semantics +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/module/__fortran_type_info.f90 b/flang/module/__fortran_type_info.f90 index b30a6bf697563..8dd27d6e4c01b 100644 --- a/flang/module/__fortran_type_info.f90 +++ b/flang/module/__fortran_type_info.f90 @@ -52,7 +52,8 @@ 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 @@ 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 a658f6f984faf..8520bec646971 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/darwin-version.f90 b/flang/test/Driver/darwin-version.f90 new file mode 100644 index 0000000000000..99d19ee44be9b --- /dev/null +++ b/flang/test/Driver/darwin-version.f90 @@ -0,0 +1,107 @@ +! Based on clang's darwin-version.c test with tests for ios watchos and tvos +! removed + +! RUN: %flang -target i686-apple-darwin8 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX4 %s +! RUN: %flang -target i686-apple-darwin9 -mmacos-version-min=10.4 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX4 %s +! CHECK-VERSION-OSX4: "i686-apple-macosx10.4.0" +! RUN: %flang -target i686-apple-darwin9 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX5 %s +! RUN: %flang -target i686-apple-darwin9 -mmacos-version-min=10.5 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX5 %s +! CHECK-VERSION-OSX5: "i686-apple-macosx10.5.0" +! RUN: %flang -target i686-apple-darwin10 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX6 %s +! RUN: %flang -target i686-apple-darwin9 -mmacos-version-min=10.6 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX6 %s +! CHECK-VERSION-OSX6: "i686-apple-macosx10.6.0" +! RUN: %flang -target x86_64-apple-darwin14 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s +! RUN: %flang -target x86_64-apple-darwin -mmacos-version-min=10.10 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s +! RUN: %flang -target x86_64-apple-darwin -mmacos-version-min=10.10 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s +! CHECK-VERSION-OSX10: "x86_64-apple-macosx10.10.0" +! RUN: not %flang -target x86_64-apple-darwin -mmacos-version-min= -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-MISSING %s +! RUN: not %flang -target x86_64-apple-darwin -mmacos-version-min= -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-MISSING %s +! CHECK-VERSION-MISSING: missing version number + +! RUN: %flang -target x86_64-apple-driverkit19.0 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-DRIVERKIT190 %s +! CHECK-VERSION-DRIVERKIT190: "x86_64-apple-driverkit19.0.0" + +! Check environment variable gets interpreted correctly +! RUN: env MACOSX_DEPLOYMENT_TARGET=10.5 IPHONEOS_DEPLOYMENT_TARGET=2.0 \ +! RUN: %flang -target i686-apple-darwin9 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX5 %s + +! RUN: env MACOSX_DEPLOYMENT_TARGET=10.4.10 \ +! RUN: %flang -target i386-apple-darwin9 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-OSX49 %s +! CHECK-VERSION-OSX49: "i386-apple-macosx10.4.10" +! RUN: env IPHONEOS_DEPLOYMENT_TARGET=2.3.1 \ + +! Target can specify the OS version: + +! RUN: %flang -target x86_64-apple-macos10.11.2 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TMAC2 %s +! CHECK-VERSION-TMAC2: "x86_64-apple-macosx10.11.2" + +! Warn about -m-version-min when it's used with target: + +! RUN: %flang -target x86_64-apple-macos10.11.2 -mmacos-version-min=10.6 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TNO-OSV1 %s +! CHECK-VERSION-TNO-OSV1: overriding '-mmacos-version-min=10.6' option with '-target x86_64-apple-macos10.11.2' + +! RUN: %flang -target x86_64-apple-macos10.6 -mmacos-version-min=10.6 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TNO-SAME %s +! CHECK-VERSION-TNO-SAME-NOT: overriding +! CHECK-VERSION-TNO-SAME-NOT: argument unused during compilation + +! Target with OS version is not overridden by -m-version-min variables: + +! RUN: %flang -target x86_64-apple-macos10.11.2 -mmacos-version-min=10.6 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TIGNORE-OSV1 %s +! CHECK-VERSION-TIGNORE-OSV1: "x86_64-apple-macosx10.11.2" + +! Target without OS version includes the OS given by -m-version-min arguments: + +! RUN: %flang -target x86_64-apple-macos -mmacos-version-min=10.11 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-USE-OS-ARG1 %s +! CHECK-VERSION-USE-OS-ARG1: "x86_64-apple-macosx10.11.0" + +! Target with OS version is not overridden by environment variables: + +! RUN: env MACOSX_DEPLOYMENT_TARGET=10.1 \ +! RUN: %flang -target i386-apple-macos10.5 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TMACOS-CMD %s +! CHECK-VERSION-TMACOS-CMD: "i386-apple-macosx10.5.0" + +! Target with OS version is not overridden by arch: + +! RUN: %flang -target uknown-apple-macos10.11.2 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-VERSION-TIGNORE-ARCH1 %s +! CHECK-VERSION-TIGNORE-ARCH1: "unknown-apple-macosx10.11.2" + +! Target can be used to specify the environment: + +! RUN: %flang -target x86_64-apple-macos11 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-MACOS11 %s +! RUN: %flang -target x86_64-apple-darwin20 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-MACOS11 %s +! RUN: %flang -target x86_64-apple-darwin -mmacos-version-min=11 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-MACOS11 %s +! CHECK-MACOS11: "x86_64-apple-macosx11.0.0" + +! RUN: %flang -target arm64-apple-macosx10.16 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-IMPLICIT-MACOS11 %s +! CHECK-IMPLICIT-MACOS11: warning: overriding deployment version +! CHECK-IMPLICIT-MACOS11: "arm64-apple-macosx11.0.0" + +! RUN: %flang -target arm64-apple-macos999 -c %s -### 2>&1 | \ +! RUN: FileCheck --check-prefix=CHECK-MACOS999 %s + +! CHECK-MACOS999: "arm64-apple-macosx999.0.0" diff --git a/flang/test/Driver/flang-f-opts.f90 b/flang/test/Driver/flang-f-opts.f90 index 4493a519e2010..b972b9b7b2a59 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 95b3071544d06..f690ab3819482 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/Driver/pic-flags.f90 b/flang/test/Driver/pic-flags.f90 index cb62d353cc18c..5a06163c485cd 100644 --- a/flang/test/Driver/pic-flags.f90 +++ b/flang/test/Driver/pic-flags.f90 @@ -1,6 +1,6 @@ ! RUN: %if aarch64-registered-target %{ %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fno-pie 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-STATIC,CHECK-STATIC-IR %} -! RUN: %if aarch64-registered-target %{ %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL2,CHECK-PIE-LEVEL2-IR %} +! RUN: %if aarch64-registered-target && clang_default_pie_on_linux %{ %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL2,CHECK-PIE-LEVEL2-IR %} ! RUN: %if aarch64-registered-target %{ %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fpie 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL1,CHECK-PIE-LEVEL1-IR %} ! RUN: %if aarch64-registered-target %{ %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fPIE 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL2,CHECK-PIE-LEVEL2-IR %} diff --git a/flang/test/Examples/omp-atomic.f90 b/flang/test/Examples/omp-atomic.f90 index dcca34b633a3e..934f84f132484 100644 --- a/flang/test/Examples/omp-atomic.f90 +++ b/flang/test/Examples/omp-atomic.f90 @@ -26,25 +26,31 @@ ! CHECK:--- ! CHECK-NEXT:- file: '{{[^"]*}}omp-atomic.f90' ! CHECK-NEXT: line: 9 -! CHECK-NEXT: construct: atomic-read +! CHECK-NEXT: construct: atomic ! CHECK-NEXT: clauses: -! CHECK-NEXT: - clause: seq_cst +! CHECK-NEXT: - clause: read ! CHECK-NEXT: details: '' +! CHECK-NEXT: - clause: seq_cst +! CHECK-NEXT: details: 'name_modifier=atomic;' ! CHECK-NEXT:- file: '{{[^"]*}}omp-atomic.f90' ! CHECK-NEXT: line: 12 -! CHECK-NEXT: construct: atomic-write +! CHECK-NEXT: construct: atomic ! CHECK-NEXT: clauses: ! CHECK-NEXT: - clause: seq_cst +! CHECK-NEXT: details: 'name_modifier=atomic;' +! CHECK-NEXT: - clause: write ! CHECK-NEXT: details: '' ! CHECK-NEXT:- file: '{{[^"]*}}omp-atomic.f90' ! CHECK-NEXT: line: 16 -! CHECK-NEXT: construct: atomic-capture +! CHECK-NEXT: construct: atomic ! CHECK-NEXT: clauses: +! CHECK-NEXT: - clause: capture +! CHECK-NEXT: details: 'name_modifier=atomic;name_modifier=atomic;' ! CHECK-NEXT: - clause: seq_cst ! CHECK-NEXT: details: '' ! CHECK-NEXT:- file: '{{[^"]*}}omp-atomic.f90' ! CHECK-NEXT: line: 21 -! CHECK-NEXT: construct: atomic-atomic +! CHECK-NEXT: construct: atomic ! CHECK-NEXT: clauses: [] ! CHECK-NEXT:- file: '{{[^"]*}}omp-atomic.f90' ! CHECK-NEXT: line: 8 diff --git a/flang/test/Fir/boxproc.fir b/flang/test/Fir/boxproc.fir index 5d82522055adc..97d9b38ed6f40 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 0000000000000..1e30ee8e64f02 --- /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 9c444d2f4e0bc..3585bf9efca3e 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 45cae1f82cb8e..aca0ecc1abdc1 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 0000000000000..006f5ca944670 --- /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/assign-side-effects.fir b/flang/test/HLFIR/assign-side-effects.fir index dfd1c5886e4fa..cac9530e2277c 100644 --- a/flang/test/HLFIR/assign-side-effects.fir +++ b/flang/test/HLFIR/assign-side-effects.fir @@ -2,14 +2,14 @@ // RUN: fir-opt %s --test-side-effects --verify-diagnostics func.func @test1(%x: !fir.ref, %i: i32) { - // expected-remark @below {{found an instance of 'write' on a op operand, on resource ''}} + // expected-remark @below {{found an instance of 'write' on op operand 1, on resource ''}} hlfir.assign %i to %x : i32, !fir.ref return } func.func @test2(%x: !fir.ref, %y: !fir.ref) { - // expected-remark @below {{found an instance of 'write' on a op operand, on resource ''}} - // expected-remark @below {{found an instance of 'read' on a op operand, on resource ''}} + // expected-remark @below {{found an instance of 'write' on op operand 1, on resource ''}} + // expected-remark @below {{found an instance of 'read' on op operand 0, on resource ''}} hlfir.assign %y to %x : !fir.ref, !fir.ref return } @@ -22,7 +22,8 @@ func.func @test3(%x: !fir.ref>, %y: !fir.ref>) { } func.func @test4(%x: !fir.ref>>>, %y: !fir.box>) { - // expected-remark @below {{found an instance of 'read' on a op operand, on resource ''}} + // expected-remark @below {{found an instance of 'read' on op operand 0, on resource ''}} + // expected-remark @below {{found an instance of 'read' on op operand 1, on resource ''}} // expected-remark @below {{found an instance of 'write' on resource ''}} // expected-remark @below {{found an instance of 'free' on resource ''}} // expected-remark @below {{found an instance of 'allocate' on resource ''}} diff --git a/flang/test/HLFIR/memory-effects.fir b/flang/test/HLFIR/memory-effects.fir index cac887ebe67de..6c791f1260be7 100644 --- a/flang/test/HLFIR/memory-effects.fir +++ b/flang/test/HLFIR/memory-effects.fir @@ -3,8 +3,9 @@ func.func @concat(%arg0: !fir.ref>, %arg1: !fir.ref>) { // expected-remark@+1 {{operation has no memory effects}} %c30 = arith.constant 30 : index -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+3 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 1, on resource ''}} %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref>, !fir.ref>, index) -> (!hlfir.expr>) return } @@ -16,8 +17,8 @@ func.func @all_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { } func.func @all_effects(%arg0: !fir.ref>>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %all = hlfir.all %arg0 dim %arg1 : (!fir.ref>>, i32) -> !hlfir.expr> return } @@ -29,8 +30,8 @@ func.func @any_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { } func.func @any_effects(%arg0: !fir.ref>>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %all = hlfir.any %arg0 dim %arg1 : (!fir.ref>>, i32) -> !hlfir.expr> return } @@ -42,7 +43,7 @@ func.func @count_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { } func.func @count_effects(%arg0: !fir.ref>>, %arg1: i32) { -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %all = hlfir.count %arg0 dim %arg1 : (!fir.ref>>, i32) -> i32 return } @@ -54,15 +55,15 @@ func.func @product_no_effects(%arg0: !hlfir.expr) { } func.func @product_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %product = hlfir.product %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> return } func.func @set_length_read(%arg0: !fir.ref>, %arg1: index) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %0 = hlfir.set_length %arg0 len %arg1 : (!fir.ref>, index) -> !hlfir.expr> return } @@ -74,8 +75,8 @@ func.func @sum_no_effects(%arg0: !hlfir.expr) { } func.func @sum_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %sum = hlfir.sum %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> return } @@ -87,8 +88,8 @@ func.func @maxval_no_effects(%arg0: !hlfir.expr) { } func.func @maxval_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %maxval = hlfir.maxval %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> return } @@ -100,34 +101,34 @@ func.func @minval_no_effects(%arg0: !hlfir.expr) { } func.func @minval_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %minval = hlfir.minval %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> return } func.func @minloc_effects_simple(%arg0: !hlfir.expr) { -// expected-remark@+1 {{found an instance of 'allocate' on a op result, on resource ''}} +// expected-remark@+1 {{found an instance of 'allocate' on op result 0, on resource ''}} %minloc = hlfir.minloc %arg0 : (!hlfir.expr) -> !hlfir.expr return } func.func @minloc_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %minloc = hlfir.minloc %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xi32> return } func.func @maxloc_effects_simple(%arg0: !hlfir.expr) { -// expected-remark@+1 {{found an instance of 'allocate' on a op result, on resource ''}} +// expected-remark@+1 {{found an instance of 'allocate' on op result 0, on resource ''}} %maxloc = hlfir.maxloc %arg0 : (!hlfir.expr) -> !hlfir.expr return } func.func @maxloc_effects(%arg0: !fir.ref>, %arg1: i32) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %maxloc = hlfir.maxloc %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xi32> return } @@ -139,49 +140,49 @@ func.func @dot_product_no_effects(%arg0: !hlfir.expr, %arg1: !hlfir.expr< } func.func @dot_product_effects(%arg0: !fir.ref>, %arg1: !fir.ref>) { -// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 1, on resource ''}} %0 = hlfir.dot_product %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> f32 return } func.func @matmul_no_reads(%arg0: !hlfir.expr, %arg1: !hlfir.expr) { -// expected-remark@+1 {{found an instance of 'allocate' on a op result, on resource ''}} +// expected-remark@+1 {{found an instance of 'allocate' on op result 0, on resource ''}} %0 = hlfir.matmul %arg0 %arg1 : (!hlfir.expr, !hlfir.expr) -> !hlfir.expr return } func.func @matmul_reads(%arg0: !fir.ref>, %arg1: !fir.ref>) { -// expected-remark@+3 {{found an instance of 'allocate' on a op result, on resource ''}} -// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+3 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 1, on resource ''}} %0 = hlfir.matmul %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr<10x10xf32> return } func.func @transpose_no_reads(%arg0: !hlfir.expr) { -// expected-remark@+1 {{found an instance of 'allocate' on a op result, on resource ''}} +// expected-remark@+1 {{found an instance of 'allocate' on op result 0, on resource ''}} %0 = hlfir.transpose %arg0 : (!hlfir.expr) -> !hlfir.expr return } func.func @transpose_read(%arg0: !fir.ref>) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %0 = hlfir.transpose %arg0 : (!fir.ref>) -> !hlfir.expr<5x10xf32> return } func.func @matmul_transpose_no_reads(%arg0: !hlfir.expr, %arg1: !hlfir.expr) { -// expected-remark@+1 {{found an instance of 'allocate' on a op result, on resource ''}} +// expected-remark@+1 {{found an instance of 'allocate' on op result 0, on resource ''}} %0 = hlfir.matmul_transpose %arg0 %arg1 : (!hlfir.expr, !hlfir.expr) -> !hlfir.expr return } func.func @matmul_transpose_reads(%arg0: !fir.ref>, %arg1: !fir.ref>) { -// expected-remark@+3 {{found an instance of 'allocate' on a op result, on resource ''}} -// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+3 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 1, on resource ''}} %0 = hlfir.matmul_transpose %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr<10x10xf32> return } @@ -195,8 +196,8 @@ func.func @associate(%arg0: i32) { } func.func @as_expr_read(%arg0: !fir.ref>) { -// expected-remark@+2 {{found an instance of 'allocate' on a op result, on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} %0 = hlfir.as_expr %arg0 : (!fir.ref>) -> !hlfir.expr // expected-remark@+1 {{found an instance of 'free' on resource ''}} hlfir.destroy %0 : !hlfir.expr @@ -204,28 +205,28 @@ func.func @as_expr_read(%arg0: !fir.ref>) { } func.func @char_extremum(%arg0: !fir.ref>, %arg1: !fir.ref>) { -// expected-remark@+3 {{found an instance of 'allocate' on a op result, on resource ''}} -// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+3 {{found an instance of 'allocate' on op result 0, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 1, on resource ''}} %0 = hlfir.char_extremum min, %arg0, %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr> return } func.func @copy_in(%box: !fir.box>, %temp: !fir.ref>>>, %is_present: i1) { // expected-remark@+3 {{found an instance of 'allocate' on resource ''}} -// expected-remark@+2 {{found an instance of 'read' on a op operand, on resource ''}} -// expected-remark@+1 {{found an instance of 'write' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'write' on op operand 1, on resource ''}} %0:2 = hlfir.copy_in %box to %temp : (!fir.box>, !fir.ref>>>) -> (!fir.box>, i1) return } func.func @copy_out(%box: !fir.box>, %temp: !fir.ref>>>, %was_copied: i1) { // expected-remark@+2 {{found an instance of 'free' on resource ''}} -// expected-remark@+1 {{found an instance of 'read' on a op operand, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on op operand 0, on resource ''}} hlfir.copy_out %temp, %was_copied : (!fir.ref>>>, i1) -> () // expected-remark@+3 {{found an instance of 'free' on resource ''}} -// expected-remark@+2 {{found an instance of 'read' on a op operand, on resource ''}} -// expected-remark@+1 {{found an instance of 'write' on a op operand, on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on op operand 0, on resource ''}} +// expected-remark@+1 {{found an instance of 'write' on op operand 2, on resource ''}} hlfir.copy_out %temp, %was_copied to %box : (!fir.ref>>>, i1, !fir.box>) -> () return } 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 0000000000000..f26d372769cab --- /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/OpenACC/acc-kernels-loop.f90 b/flang/test/Lower/OpenACC/acc-kernels-loop.f90 index 8608b0ad98ce6..4e968144399a8 100644 --- a/flang/test/Lower/OpenACC/acc-kernels-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-kernels-loop.f90 @@ -47,7 +47,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels { ! CHECK: acc.loop private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type]{{.*}}} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -59,7 +59,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels combined(loop) { ! CHECK: acc.loop combined(kernels) private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type]{{.*}}} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -490,7 +490,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels {{.*}} { ! CHECK: acc.loop {{.*}} gang {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -503,7 +503,7 @@ subroutine acc_kernels_loop ! CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32 ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM1]] : i32}) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -516,7 +516,7 @@ subroutine acc_kernels_loop ! CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM2]] : i32}) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -528,7 +528,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels {{.*}} { ! CHECK: acc.loop {{.*}} gang({num=%{{.*}} : i32, static=%{{.*}} : i32}) ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -540,7 +540,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels {{.*}} { ! CHECK: acc.loop {{.*}} vector {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -553,7 +553,7 @@ subroutine acc_kernels_loop ! CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop {{.*}} vector([[CONSTANT128]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -566,7 +566,7 @@ subroutine acc_kernels_loop ! CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop {{.*}} vector([[VECTORLENGTH]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -578,7 +578,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels {{.*}} { ! CHECK: acc.loop {{.*}} worker {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -591,7 +591,7 @@ subroutine acc_kernels_loop ! CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop {{.*}} worker([[WORKER128]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -605,7 +605,7 @@ subroutine acc_kernels_loop ! CHECK: acc.kernels {{.*}} { ! CHECK: acc.loop {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {collapse = [2], collapseDeviceType = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {{{.*}}collapse = [2], collapseDeviceType = [#acc.device_type]{{.*}}} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} @@ -621,9 +621,9 @@ subroutine acc_kernels_loop ! CHECK: acc.loop {{.*}} { ! CHECK: acc.loop {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type]{{.*}}} ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type]{{.*}}} ! CHECK: acc.terminator ! CHECK-NEXT: }{{$}} diff --git a/flang/test/Lower/OpenACC/acc-loop.f90 b/flang/test/Lower/OpenACC/acc-loop.f90 index 0246f60705898..5baa485534b2a 100644 --- a/flang/test/Lower/OpenACC/acc-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-loop.f90 @@ -29,7 +29,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]}{{$}} !$acc loop seq DO i = 1, n @@ -65,7 +65,7 @@ program acc_loop ! CHECK: acc.loop gang private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop gang(num: 8) DO i = 1, n @@ -75,7 +75,7 @@ program acc_loop ! CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32 ! CHECK: acc.loop gang({num=[[GANGNUM1]] : i32}) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop gang(num: gangNum) DO i = 1, n @@ -85,7 +85,7 @@ program acc_loop ! CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop gang({num=[[GANGNUM2]] : i32}) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop gang(num: gangNum, static: gangStatic) DO i = 1, n @@ -94,7 +94,7 @@ program acc_loop ! CHECK: acc.loop gang({num=%{{.*}} : i32, static=%{{.*}} : i32}) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop vector DO i = 1, n @@ -103,7 +103,7 @@ program acc_loop ! CHECK: acc.loop vector private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop vector(128) DO i = 1, n @@ -113,7 +113,7 @@ program acc_loop ! CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop vector([[CONSTANT128]] : i32) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop vector(vectorLength) DO i = 1, n @@ -123,7 +123,7 @@ program acc_loop ! CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop vector([[VECTORLENGTH]] : i32) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop worker DO i = 1, n @@ -132,7 +132,7 @@ program acc_loop ! CHECK: acc.loop worker private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop worker(128) DO i = 1, n @@ -142,7 +142,7 @@ program acc_loop ! CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop worker([[WORKER128]] : i32) private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop private(c) DO i = 1, n @@ -151,7 +151,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_10x10xf32 -> %{{.*}} : !fir.ref>, @privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! When the induction variable is explicitly private - only a single private entry should be created. !$acc loop private(i) @@ -161,7 +161,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop private(c, d) DO i = 1, n @@ -170,7 +170,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_10x10xf32 -> %{{.*}} : !fir.ref>, @privatization_ref_10x10xf32 -> %{{.*}} : !fir.ref>, @privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop private(c) private(d) DO i = 1, n @@ -179,7 +179,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_10x10xf32 -> %{{.*}} : !fir.ref>, @privatization_ref_10x10xf32 -> %{{.*}} : !fir.ref>, @privatization_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop tile(2) DO i = 1, n @@ -189,7 +189,7 @@ program acc_loop ! CHECK: [[TILESIZE:%.*]] = arith.constant 2 : i32 ! CHECK: acc.loop {{.*}} tile({[[TILESIZE]] : i32}) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop tile(*) DO i = 1, n @@ -198,7 +198,7 @@ program acc_loop ! CHECK: [[TILESIZEM1:%.*]] = arith.constant -1 : i32 ! CHECK: acc.loop {{.*}} tile({[[TILESIZEM1]] : i32}) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop tile(2, 2) DO i = 1, n @@ -211,7 +211,7 @@ program acc_loop ! CHECK: [[TILESIZE2:%.*]] = arith.constant 2 : i32 ! CHECK: acc.loop {{.*}} tile({[[TILESIZE1]] : i32, [[TILESIZE2]] : i32}) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop tile(tileSize) DO i = 1, n @@ -220,7 +220,7 @@ program acc_loop ! CHECK: acc.loop {{.*}} tile({%{{.*}} : i32}) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop tile(tileSize, tileSize) DO i = 1, n @@ -231,7 +231,7 @@ program acc_loop ! CHECK: acc.loop {{.*}} tile({%{{.*}} : i32, %{{.*}} : i32}) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop collapse(2) DO i = 1, n @@ -244,7 +244,7 @@ program acc_loop ! CHECK: fir.store %arg0 to %{{.*}} : !fir.ref ! CHECK: fir.store %arg1 to %{{.*}} : !fir.ref ! CHECK: acc.yield -! CHECK-NEXT: } attributes {collapse = [2], collapseDeviceType = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {collapse = [2], collapseDeviceType = [#acc.device_type]{{.*}}} !$acc loop DO i = 1, n @@ -257,9 +257,9 @@ program acc_loop ! CHECK: acc.loop {{.*}} control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.loop {{.*}} control(%arg1 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop reduction(+:reduction_r) reduction(*:reduction_i) do i = 1, n @@ -269,7 +269,7 @@ program acc_loop ! CHECK: acc.loop private(@privatization_ref_i32 -> %{{.*}} : !fir.ref) reduction(@reduction_add_ref_f32 -> %{{.*}} : !fir.ref, @reduction_mul_ref_i32 -> %{{.*}} : !fir.ref) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop gang(dim: gangDim, static: gangStatic) DO i = 1, n @@ -278,7 +278,7 @@ program acc_loop ! CHECK: acc.loop gang({dim=%{{.*}}, static=%{{.*}} : i32}) {{.*}} control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop gang(dim: 1) DO i = 1, n @@ -287,7 +287,7 @@ program acc_loop ! CHECK: acc.loop gang({dim={{.*}} : i32}) {{.*}} control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} !$acc loop DO i = 1, n @@ -335,4 +335,4 @@ subroutine sub1(i, j, k) ! CHECK: %[[P_J:.*]] = acc.private varPtr(%[[DC_J]] : !fir.ref) -> !fir.ref {implicit = true, name = "j"} ! CHECK: %[[P_K:.*]] = acc.private varPtr(%[[DC_K]] : !fir.ref) -> !fir.ref {implicit = true, name = "k"} ! CHECK: acc.loop combined(parallel) private(@privatization_ref_i32 -> %[[P_I]] : !fir.ref, @privatization_ref_i32 -> %[[P_J]] : !fir.ref, @privatization_ref_i32 -> %[[P_K]] : !fir.ref) control(%{{.*}} : i32, %{{.*}} : i32, %{{.*}} : i32) = (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) to (%c10{{.*}}, %c100{{.*}}, %c200{{.*}} : i32, i32, i32) step (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) -! CHECK: } attributes {inclusiveUpperbound = array} +! CHECK: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} diff --git a/flang/test/Lower/OpenACC/acc-parallel-loop.f90 b/flang/test/Lower/OpenACC/acc-parallel-loop.f90 index 4cf268d2517f5..32060179acdf1 100644 --- a/flang/test/Lower/OpenACC/acc-parallel-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-parallel-loop.f90 @@ -49,7 +49,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel { ! CHECK: acc.loop private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -61,7 +61,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel combined(loop) { ! CHECK: acc.loop combined(parallel) private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -505,7 +505,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel {{.*}} { ! CHECK: acc.loop {{.*}} gang ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -518,7 +518,7 @@ subroutine acc_parallel_loop ! CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32 ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM1]] : i32}) ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -531,7 +531,7 @@ subroutine acc_parallel_loop ! CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM2]] : i32}) ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -543,7 +543,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel {{.*}} { ! CHECK: acc.loop {{.*}} gang({num=%{{.*}} : i32, static=%{{.*}} : i32}) ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -555,7 +555,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel {{.*}} { ! CHECK: acc.loop {{.*}} vector ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -568,7 +568,7 @@ subroutine acc_parallel_loop ! CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop {{.*}} vector([[CONSTANT128]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -582,7 +582,7 @@ subroutine acc_parallel_loop ! CHECK: acc.loop {{.*}} vector([[VECTORLENGTH]] : i32) {{.*}} { ! CHECK-NOT: fir.do_loop ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -595,7 +595,7 @@ subroutine acc_parallel_loop ! CHECK: acc.loop {{.*}} worker {{.*}} { ! CHECK-NOT: fir.do_loop ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -609,7 +609,7 @@ subroutine acc_parallel_loop ! CHECK: acc.loop {{.*}} worker([[WORKER128]] : i32) {{.*}} { ! CHECK-NOT: fir.do_loop ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -623,7 +623,7 @@ subroutine acc_parallel_loop ! CHECK: acc.parallel {{.*}} { ! CHECK: acc.loop {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {collapse = [2], collapseDeviceType = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {{{.*}}collapse = [2], collapseDeviceType = [#acc.device_type]{{.*}}} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -639,9 +639,9 @@ subroutine acc_parallel_loop ! CHECK: acc.loop {{.*}} { ! CHECK: acc.loop {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}independent = [#acc.device_type]} ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}independent = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} diff --git a/flang/test/Lower/OpenACC/acc-serial-loop.f90 b/flang/test/Lower/OpenACC/acc-serial-loop.f90 index 34391f78ae707..af7bb0fac158c 100644 --- a/flang/test/Lower/OpenACC/acc-serial-loop.f90 +++ b/flang/test/Lower/OpenACC/acc-serial-loop.f90 @@ -68,7 +68,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial { ! CHECK: acc.loop private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}seq = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -80,7 +80,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial combined(loop) { ! CHECK: acc.loop combined(serial) private{{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}seq = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -446,7 +446,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial {{.*}} { ! CHECK: acc.loop {{.*}} gang {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -459,7 +459,7 @@ subroutine acc_serial_loop ! CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32 ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM1]] : i32}) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -472,7 +472,7 @@ subroutine acc_serial_loop ! CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop {{.*}} gang({num=[[GANGNUM2]] : i32}) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -484,7 +484,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial {{.*}} { ! CHECK: acc.loop {{.*}} gang({num=%{{.*}} : i32, static=%{{.*}} : i32}) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -496,7 +496,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial {{.*}} { ! CHECK: acc.loop {{.*}} vector {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -509,7 +509,7 @@ subroutine acc_serial_loop ! CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop {{.*}} vector([[CONSTANT128]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -522,7 +522,7 @@ subroutine acc_serial_loop ! CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref ! CHECK: acc.loop {{.*}} vector([[VECTORLENGTH]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -534,7 +534,7 @@ subroutine acc_serial_loop ! CHECK: acc.serial {{.*}} { ! CHECK: acc.loop {{.*}} worker {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: } attributes {inclusiveUpperbound = array}{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -547,7 +547,7 @@ subroutine acc_serial_loop ! CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32 ! CHECK: acc.loop {{.*}} worker([[WORKER128]] : i32) {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -562,7 +562,7 @@ subroutine acc_serial_loop ! CHECK: acc.loop {{.*}} { ! CHECK-NOT: fir.do_loop ! CHECK: acc.yield -! CHECK-NEXT: } attributes {collapse = [2], collapseDeviceType = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NEXT: } attributes {{{.*}}collapse = [2], collapseDeviceType = [#acc.device_type]{{.*}}} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} @@ -578,9 +578,9 @@ subroutine acc_serial_loop ! CHECK: acc.loop {{.*}} { ! CHECK: acc.loop {{.*}} { ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}seq = [#acc.device_type]} ! CHECK: acc.yield -! CHECK-NEXT: }{{$}} +! CHECK-NEXT: } attributes {{{.*}}seq = [#acc.device_type]} ! CHECK: acc.yield ! CHECK-NEXT: }{{$}} diff --git a/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 b/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 index b82bd13622764..6f58e0939a787 100644 --- a/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 +++ b/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 @@ -1,6 +1,6 @@ ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s -! CHECK: not yet implemented: OpenMP atomic compare +! CHECK: not yet implemented: OpenMP ATOMIC COMPARE program p integer :: x logical :: r diff --git a/flang/test/Lower/OpenMP/Todo/atomic-compare.f90 b/flang/test/Lower/OpenMP/Todo/atomic-compare.f90 index 88ec6fe910b9e..6729be6e5cf8b 100644 --- a/flang/test/Lower/OpenMP/Todo/atomic-compare.f90 +++ b/flang/test/Lower/OpenMP/Todo/atomic-compare.f90 @@ -1,6 +1,6 @@ ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s -! CHECK: not yet implemented: OpenMP atomic compare +! CHECK: not yet implemented: OpenMP ATOMIC COMPARE program p integer :: x logical :: r 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 0000000000000..d441cac47f5da --- /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/atomic-capture.f90 b/flang/test/Lower/OpenMP/atomic-capture.f90 index 2f800d534dc36..14fd0c942a9b4 100644 --- a/flang/test/Lower/OpenMP/atomic-capture.f90 +++ b/flang/test/Lower/OpenMP/atomic-capture.f90 @@ -79,16 +79,16 @@ subroutine pointers_in_atomic_capture() !CHECK: %[[VAL_A_BOX_ADDR:.*]] = fir.box_addr %[[VAL_A_LOADED]] : (!fir.box>) -> !fir.ptr !CHECK: %[[VAL_B_LOADED:.*]] = fir.load %[[VAL_B_DECLARE]]#0 : !fir.ref>> !CHECK: %[[VAL_B_BOX_ADDR:.*]] = fir.box_addr %[[VAL_B_LOADED]] : (!fir.box>) -> !fir.ptr +!CHECK: %[[VAL_B:.*]] = fir.load %[[VAL_B_BOX_ADDR]] : !fir.ptr !CHECK: %[[VAL_B_LOADED_2:.*]] = fir.load %[[VAL_B_DECLARE]]#0 : !fir.ref>> !CHECK: %[[VAL_B_BOX_ADDR_2:.*]] = fir.box_addr %[[VAL_B_LOADED_2]] : (!fir.box>) -> !fir.ptr -!CHECK: %[[VAL_B:.*]] = fir.load %[[VAL_B_BOX_ADDR_2]] : !fir.ptr !CHECK: omp.atomic.capture { !CHECK: omp.atomic.update %[[VAL_A_BOX_ADDR]] : !fir.ptr { !CHECK: ^bb0(%[[ARG:.*]]: i32): !CHECK: %[[TEMP:.*]] = arith.addi %[[ARG]], %[[VAL_B]] : i32 !CHECK: omp.yield(%[[TEMP]] : i32) !CHECK: } -!CHECK: omp.atomic.read %[[VAL_B_BOX_ADDR]] = %[[VAL_A_BOX_ADDR]] : !fir.ptr, !fir.ptr, i32 +!CHECK: omp.atomic.read %[[VAL_B_BOX_ADDR_2]] = %[[VAL_A_BOX_ADDR]] : !fir.ptr, !fir.ptr, i32 !CHECK: } !CHECK: return !CHECK: } diff --git a/flang/test/Lower/OpenMP/atomic-implicit-cast.f90 b/flang/test/Lower/OpenMP/atomic-implicit-cast.f90 index 4c1be1ca91ac0..5e00235b85e74 100644 --- a/flang/test/Lower/OpenMP/atomic-implicit-cast.f90 +++ b/flang/test/Lower/OpenMP/atomic-implicit-cast.f90 @@ -1,5 +1,3 @@ -! REQUIRES : openmp_runtime - ! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s ! CHECK: func.func @_QPatomic_implicit_cast_read() { @@ -97,9 +95,9 @@ subroutine atomic_implicit_cast_read ! CHECK: } ! CHECK: omp.atomic.read %[[ALLOCA6]] = %[[X_DECL]]#0 : !fir.ref, !fir.ref, i32 ! CHECK: %[[LOAD:.*]] = fir.load %[[ALLOCA6]] : !fir.ref -! CHECK: %[[UNDEF:.*]] = fir.undefined complex ! CHECK: %[[CVT:.*]] = fir.convert %[[LOAD]] : (i32) -> f32 ! CHECK: %[[CST:.*]] = arith.constant 0.000000e+00 : f32 +! CHECK: %[[UNDEF:.*]] = fir.undefined complex ! CHECK: %[[IDX1:.*]] = fir.insert_value %[[UNDEF]], %[[CVT]], [0 : index] : (complex, f32) -> complex ! CHECK: %[[IDX2:.*]] = fir.insert_value %[[IDX1]], %[[CST]], [1 : index] : (complex, f32) -> complex ! CHECK: fir.store %[[IDX2]] to %[[W_DECL]]#0 : !fir.ref> @@ -109,14 +107,14 @@ subroutine atomic_implicit_cast_read !$omp end atomic -! CHECK: omp.atomic.capture { -! CHECK: omp.atomic.update %[[M_DECL]]#0 : !fir.ref> { -! CHECK: ^bb0(%[[ARG:.*]]: complex): ! CHECK: %[[CST1:.*]] = arith.constant 1.000000e+00 : f64 ! CHECK: %[[CST2:.*]] = arith.constant 0.000000e+00 : f64 ! CHECK: %[[UNDEF:.*]] = fir.undefined complex ! CHECK: %[[IDX1:.*]] = fir.insert_value %[[UNDEF]], %[[CST1]], [0 : index] : (complex, f64) -> complex ! CHECK: %[[IDX2:.*]] = fir.insert_value %[[IDX1]], %[[CST2]], [1 : index] : (complex, f64) -> complex +! CHECK: omp.atomic.capture { +! CHECK: omp.atomic.update %[[M_DECL]]#0 : !fir.ref> { +! CHECK: ^bb0(%[[ARG:.*]]: complex): ! CHECK: %[[RESULT:.*]] = fir.addc %[[ARG]], %[[IDX2]] {fastmath = #arith.fastmath} : complex ! CHECK: omp.yield(%[[RESULT]] : complex) ! CHECK: } diff --git a/flang/test/Lower/OpenMP/atomic-privatize.f90 b/flang/test/Lower/OpenMP/atomic-privatize.f90 index f922095264fca..c876266cf018c 100644 --- a/flang/test/Lower/OpenMP/atomic-privatize.f90 +++ b/flang/test/Lower/OpenMP/atomic-privatize.f90 @@ -8,7 +8,7 @@ !CHECK: omp.task private(@_QFfredEprv_firstprivate_i32 %{{[0-9]+}}#0 -> %arg0 !CHECK: %[[DECL:[0-9]+]]:2 = hlfir.declare %arg0 {uniq_name = "_QFfredEprv"} -!CHECK: omp.atomic.update %[[DECL]]#0 +!CHECK: omp.atomic.update memory_order(relaxed) %[[DECL]]#0 integer function fred integer :: prv diff --git a/flang/test/Lower/OpenMP/atomic-write.f90 b/flang/test/Lower/OpenMP/atomic-write.f90 index 13392ad76471f..6eded49b0b15d 100644 --- a/flang/test/Lower/OpenMP/atomic-write.f90 +++ b/flang/test/Lower/OpenMP/atomic-write.f90 @@ -44,9 +44,9 @@ end program OmpAtomicWrite !CHECK-LABEL: func.func @_QPatomic_write_pointer() { !CHECK: %[[X_REF:.*]] = fir.alloca !fir.box> {bindc_name = "x", uniq_name = "_QFatomic_write_pointerEx"} !CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_REF]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFatomic_write_pointerEx"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) -!CHECK: %[[C1:.*]] = arith.constant 1 : i32 !CHECK: %[[X_ADDR_BOX:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref>> !CHECK: %[[X_POINTEE_ADDR:.*]] = fir.box_addr %[[X_ADDR_BOX]] : (!fir.box>) -> !fir.ptr +!CHECK: %[[C1:.*]] = arith.constant 1 : i32 !CHECK: omp.atomic.write %[[X_POINTEE_ADDR]] = %[[C1]] : !fir.ptr, i32 !CHECK: %[[C2:.*]] = arith.constant 2 : i32 !CHECK: %[[X_ADDR_BOX:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref>> diff --git a/flang/test/Lower/OpenMP/copyprivate5.f90 b/flang/test/Lower/OpenMP/copyprivate5.f90 new file mode 100644 index 0000000000000..c75eb82a45e9f --- /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 0000000000000..488696b565077 --- /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 0000000000000..5de11e06cc10b --- /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/dump-atomic-analysis.f90 b/flang/test/Lower/OpenMP/dump-atomic-analysis.f90 new file mode 100644 index 0000000000000..cbaf7bc9f2d8a --- /dev/null +++ b/flang/test/Lower/OpenMP/dump-atomic-analysis.f90 @@ -0,0 +1,82 @@ +!RUN: %flang_fc1 -fopenmp -fopenmp-version=60 -emit-hlfir -mmlir -fdebug-dump-atomic-analysis %s -o /dev/null 2>&1 | FileCheck %s + +subroutine f00(x) + integer :: x, v + !$omp atomic read + v = x +end + +!CHECK: Analysis { +!CHECK-NEXT: atom: x +!CHECK-NEXT: cond: +!CHECK-NEXT: op0 { +!CHECK-NEXT: what: Read +!CHECK-NEXT: assign: v=x +!CHECK-NEXT: } +!CHECK-NEXT: op1 { +!CHECK-NEXT: what: None +!CHECK-NEXT: assign: +!CHECK-NEXT: } +!CHECK-NEXT: } + + +subroutine f01(v) + integer :: x, v + !$omp atomic write + x = v +end + +!CHECK: Analysis { +!CHECK-NEXT: atom: x +!CHECK-NEXT: cond: +!CHECK-NEXT: op0 { +!CHECK-NEXT: what: Write +!CHECK-NEXT: assign: x=v +!CHECK-NEXT: } +!CHECK-NEXT: op1 { +!CHECK-NEXT: what: None +!CHECK-NEXT: assign: +!CHECK-NEXT: } +!CHECK-NEXT: } + + +subroutine f02(x, v) + integer :: x, v + !$omp atomic update + x = x + v +end + +!CHECK: Analysis { +!CHECK-NEXT: atom: x +!CHECK-NEXT: cond: +!CHECK-NEXT: op0 { +!CHECK-NEXT: what: Update +!CHECK-NEXT: assign: x=x+v +!CHECK-NEXT: } +!CHECK-NEXT: op1 { +!CHECK-NEXT: what: None +!CHECK-NEXT: assign: +!CHECK-NEXT: } +!CHECK-NEXT: } + + +subroutine f03(x, v) + integer :: x, v, t + !$omp atomic update capture + t = x + x = x + v + !$omp end atomic +end + +!CHECK: Analysis { +!CHECK-NEXT: atom: x +!CHECK-NEXT: cond: +!CHECK-NEXT: op0 { +!CHECK-NEXT: what: Read +!CHECK-NEXT: assign: t=x +!CHECK-NEXT: } +!CHECK-NEXT: op1 { +!CHECK-NEXT: what: Update +!CHECK-NEXT: assign: x=x+v +!CHECK-NEXT: } +!CHECK-NEXT: } diff --git a/flang/test/Lower/OpenMP/flush02.f90 b/flang/test/Lower/OpenMP/flush02.f90 new file mode 100644 index 0000000000000..b372e700e1a1d --- /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/implicit-dsa.f90 b/flang/test/Lower/OpenMP/implicit-dsa.f90 index f0f149bb415b0..0d2db63edfe79 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/requires-atomic-default-mem-order.f90 b/flang/test/Lower/OpenMP/requires-atomic-default-mem-order.f90 new file mode 100644 index 0000000000000..91cb654aeeb3a --- /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-parallel-private.f90 b/flang/test/Lower/OpenMP/target-parallel-private.f90 new file mode 100644 index 0000000000000..cc04b77e4a527 --- /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 0000000000000..65d97649b5cf3 --- /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 0000000000000..1e996a030c23a --- /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/volatile-openmp.f90 b/flang/test/Lower/volatile-openmp.f90 index 28f0bf78f33c9..2e05b652822b5 100644 --- a/flang/test/Lower/volatile-openmp.f90 +++ b/flang/test/Lower/volatile-openmp.f90 @@ -23,11 +23,11 @@ ! 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/atomic-compare.f90 b/flang/test/Parser/OpenMP/atomic-compare.f90 index 5cd02698ff482..e09da4a359fcc 100644 --- a/flang/test/Parser/OpenMP/atomic-compare.f90 +++ b/flang/test/Parser/OpenMP/atomic-compare.f90 @@ -1,16 +1,290 @@ -! RUN: not %flang_fc1 -fopenmp-version=51 -fopenmp %s 2>&1 | FileCheck %s -! OpenMP version for documentation purposes only - it isn't used until Sema. -! This is testing for Parser errors that bail out before Sema. -program main - implicit none - integer :: i, j = 10 - logical :: r - - !CHECK: error: expected OpenMP construct - !$omp atomic compare write - r = i .eq. j + 1 - - !CHECK: error: expected end of line - !$omp atomic compare num_threads(4) - r = i .eq. j -end program main +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine f00(a, b) + integer :: a, b + integer :: x + !$omp atomic update compare + if (x < a) x = b +end + +!UNPARSE: SUBROUTINE f00 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x +!UNPARSE: !$OMP ATOMIC UPDATE COMPARE +!UNPARSE: IF (x ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> IfStmt +!PARSE-TREE: | | | Scalar -> Logical -> Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'a' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: | | | ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | Variable = 'x' +!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | Expr = 'b' +!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'b' + +subroutine f01(a, b) + integer :: a, b + integer :: x + !$omp atomic update compare + if (x < a) then + x = b + endif +end + +!UNPARSE: SUBROUTINE f01 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x +!UNPARSE: !$OMP ATOMIC UPDATE COMPARE +!UNPARSE: IF (x ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> IfConstruct +!PARSE-TREE: | | | IfThenStmt +!PARSE-TREE: | | | | Scalar -> Logical -> Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | | | | Expr = 'a' +!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: | | | Block +!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | | Variable = 'x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'b' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | | | EndIfStmt -> + +subroutine f02(a, b) + integer :: a, b + integer :: x + logical :: c + c = x < a + !$omp atomic update compare + if (c) then + x = b + endif +end + +!UNPARSE: SUBROUTINE f02 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x +!UNPARSE: LOGICAL c +!UNPARSE: c=x ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'c=x DataRef -> Name = 'c' +!PARSE-TREE: | Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | Expr = 'a' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> IfConstruct +!PARSE-TREE: | | | IfThenStmt +!PARSE-TREE: | | | | Scalar -> Logical -> Expr = 'c' +!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'c' +!PARSE-TREE: | | | Block +!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | | Variable = 'x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'b' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | | | EndIfStmt -> + +subroutine g00(a, b) + integer :: a, b + integer :: x, v + !$omp atomic update capture compare + v = x + if (x < a) x = b + !$omp end atomic +end + +!UNPARSE: SUBROUTINE g00 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x, v +!UNPARSE: !$OMP ATOMIC UPDATE CAPTURE COMPARE +!UNPARSE: v=x +!UNPARSE: IF (x ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Capture +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'v=x' +!PARSE-TREE: | | | Variable = 'v' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'v' +!PARSE-TREE: | | | Expr = 'x' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> IfStmt +!PARSE-TREE: | | | Scalar -> Logical -> Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'a' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: | | | ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | Variable = 'x' +!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | Expr = 'b' +!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> +!PARSE-TREE: | | Flags = None + +subroutine g01(a, b) + integer :: a, b + integer :: x, v + !$omp atomic update capture compare + v = x + if (x < a) then + x = b + endif + !$omp end atomic +end + +!UNPARSE: SUBROUTINE g01 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x, v +!UNPARSE: !$OMP ATOMIC UPDATE CAPTURE COMPARE +!UNPARSE: v=x +!UNPARSE: IF (x ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Capture +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'v=x' +!PARSE-TREE: | | | Variable = 'v' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'v' +!PARSE-TREE: | | | Expr = 'x' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> IfConstruct +!PARSE-TREE: | | | IfThenStmt +!PARSE-TREE: | | | | Scalar -> Logical -> Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | | | | Expr = 'a' +!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: | | | Block +!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | | Variable = 'x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'b' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | | | EndIfStmt -> +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> +!PARSE-TREE: | | Flags = None + +subroutine g02(a, b) + integer :: a, b + integer :: x, v + !$omp atomic update capture compare + if (x < a) then + x = b + else + v = x + endif + !$omp end atomic +end + +!UNPARSE: SUBROUTINE g02 (a, b) +!UNPARSE: INTEGER a, b +!UNPARSE: INTEGER x, v +!UNPARSE: !$OMP ATOMIC UPDATE CAPTURE COMPARE +!UNPARSE: IF (x ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Update -> +!PARSE-TREE: | | OmpClause -> Capture +!PARSE-TREE: | | OmpClause -> Compare +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> IfConstruct +!PARSE-TREE: | | | IfThenStmt +!PARSE-TREE: | | | | Scalar -> Logical -> Expr = 'x DataRef -> Name = 'x' +!PARSE-TREE: | | | | | | Expr = 'a' +!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'a' +!PARSE-TREE: | | | Block +!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=b' +!PARSE-TREE: | | | | | Variable = 'x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | | | Expr = 'b' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | | | ElseBlock +!PARSE-TREE: | | | | ElseStmt -> +!PARSE-TREE: | | | | Block +!PARSE-TREE: | | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'v=x' +!PARSE-TREE: | | | | | | Variable = 'v' +!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'v' +!PARSE-TREE: | | | | | | Expr = 'x' +!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | | EndIfStmt -> +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> +!PARSE-TREE: | | Flags = None diff --git a/flang/test/Parser/OpenMP/atomic-end.f90 b/flang/test/Parser/OpenMP/atomic-end.f90 new file mode 100644 index 0000000000000..e5eac87517b1e --- /dev/null +++ b/flang/test/Parser/OpenMP/atomic-end.f90 @@ -0,0 +1,63 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine f00 + integer :: x, v + !$omp atomic read + v = x + !$omp end atomic +end + +!UNPARSE: SUBROUTINE f00 +!UNPARSE: INTEGER x, v +!UNPARSE: !$OMP ATOMIC READ +!UNPARSE: v=x +!UNPARSE: !$OMP END ATOMIC +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Read +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'v=x' +!PARSE-TREE: | | | Variable = 'v' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'v' +!PARSE-TREE: | | | Expr = 'x' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> +!PARSE-TREE: | | Flags = None + + +subroutine f01 + integer :: x, v + !$omp atomic read + v = x + !$omp endatomic +end + +!UNPARSE: SUBROUTINE f01 +!UNPARSE: INTEGER x, v +!UNPARSE: !$OMP ATOMIC READ +!UNPARSE: v=x +!UNPARSE: !$OMP END ATOMIC +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Read +!PARSE-TREE: | | Flags = None +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'v=x' +!PARSE-TREE: | | | Variable = 'v' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'v' +!PARSE-TREE: | | | Expr = 'x' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpDirectiveSpecification +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = atomic +!PARSE-TREE: | | OmpClauseList -> +!PARSE-TREE: | | Flags = None 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 0000000000000..df85942ec15a5 --- /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 346e04cc56d38..0b680dd5751b9 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 0000000000000..2650fb5ebfd35 --- /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 0000000000000..c4a2a26557e80 --- /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 0000000000000..4490c45232d28 --- /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/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90 index 54492bf6a22a6..11e23e062bce7 100644 --- a/flang/test/Semantics/OpenMP/atomic-compare.f90 +++ b/flang/test/Semantics/OpenMP/atomic-compare.f90 @@ -44,46 +44,37 @@ !$omp end atomic ! Check for error conditions: - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst compare if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic compare seq_cst seq_cst if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst compare seq_cst if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire acquire compare if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic compare acquire acquire if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire compare acquire if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the COMPARE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed compare if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the COMPARE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic compare relaxed relaxed if (b .eq. c) b = a - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the COMPARE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed compare relaxed if (b .eq. c) b = a - !ERROR: More than one FAIL clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one FAIL clause can appear on the ATOMIC directive !$omp atomic fail(release) compare fail(release) if (c .eq. a) a = b !$omp end atomic diff --git a/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 b/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 index c13a11a8dd5dc..8adb0f1a67409 100644 --- a/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 +++ b/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 @@ -16,20 +16,21 @@ program sample !$omp atomic read hint(2) y = x - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp atomic hint(3) y = y + 10 !$omp atomic update hint(5) y = x + y - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp atomic hint(7) capture + !WARNING: In ATOMIC UPDATE operation with CAPTURE either statement could be the update and the capture, assuming the first one is the capture statement y = x x = y !$omp end atomic - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp atomic update hint(x) y = y * 1 @@ -46,7 +47,7 @@ program sample !$omp atomic hint(omp_lock_hint_speculative) x = y + x - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint) read y = x @@ -69,36 +70,36 @@ program sample !$omp atomic hint(omp_lock_hint_contended + omp_sync_hint_nonspeculative) x = y + x - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint_contended) read y = x - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp atomic hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative) y = y * 9 - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must have INTEGER type, but is REAL(4) !$omp atomic hint(1.0) read y = x - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4) !$omp atomic hint(z + omp_sync_hint_nonspeculative) read y = x - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp atomic hint(k + omp_sync_hint_speculative) read y = x - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp atomic hint(p(1) + omp_sync_hint_uncontended) write x = 10 * y !$omp atomic write hint(a) - !ERROR: RHS expression on atomic assignment statement cannot access 'x' + !ERROR: Within atomic operation x and y+x access the same storage x = y + x !$omp atomic hint(abs(-1)) write diff --git a/flang/test/Semantics/OpenMP/atomic-read.f90 b/flang/test/Semantics/OpenMP/atomic-read.f90 new file mode 100644 index 0000000000000..06c301cb78b77 --- /dev/null +++ b/flang/test/Semantics/OpenMP/atomic-read.f90 @@ -0,0 +1,118 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + +subroutine f00 + integer :: x, v + ! The end-directive is optional in ATOMIC READ. Expect no diagnostics. + !$omp atomic read + v = x + + !$omp atomic read + v = x + !$omp end atomic +end + +subroutine f01 + integer, pointer :: x, v + ! Intrinsic assignment and pointer assignment are both ok. Expect no + ! diagnostics. + !$omp atomic read + v = x + + !$omp atomic read + v => x +end + +subroutine f02(i) + integer :: i, v + interface + function p(i) + integer, pointer :: p + integer :: i + end + end interface + + ! Atomic variable can be a function reference. Expect no diagostics. + !$omp atomic read + v = p(i) +end + +subroutine f03 + integer :: x(3), y(5), v(3) + + !$omp atomic read + !ERROR: Atomic variable x should be a scalar + v = x + + !$omp atomic read + !ERROR: Atomic variable y(2_8:4_8:1_8) should be a scalar + v = y(2:4) +end + +subroutine f04 + integer :: x, y(3), v + + !$omp atomic read + !ERROR: Within atomic operation x and x access the same storage + x = x + + ! Accessing same array, but not the same storage. Expect no diagnostics. + !$omp atomic read + y(1) = y(2) +end + +subroutine f05 + integer :: x, v + + !$omp atomic read + !ERROR: Atomic expression x+1_4 should be a variable + v = x + 1 +end + +subroutine f06 + character :: x, v + + !$omp atomic read + !ERROR: Atomic variable x cannot have CHARACTER type + v = x +end + +subroutine f07 + integer, allocatable :: x + integer :: v + + allocate(x) + + !$omp atomic read + !ERROR: Atomic variable x cannot be ALLOCATABLE + v = x +end + +subroutine f08 + type :: struct + integer :: m + end type + type(struct) :: x, v + + !$omp atomic read + !ERROR: Atomic variable x should have an intrinsic type + v = x +end + +subroutine f09(x, v) + class(*), pointer :: x, v + + !$omp atomic read + !ERROR: Atomic variable x cannot be a pointer to a polymorphic type + v => x +end + +subroutine f10(x, v) + type struct(length) + integer, len :: length + end type + type(struct(*)), pointer :: x, v + + !$omp atomic read + !ERROR: Atomic variable x is a pointer to a type with non-constant length parameter + v => x +end diff --git a/flang/test/Semantics/OpenMP/atomic-update-capture.f90 b/flang/test/Semantics/OpenMP/atomic-update-capture.f90 new file mode 100644 index 0000000000000..f808ed916fb7e --- /dev/null +++ b/flang/test/Semantics/OpenMP/atomic-update-capture.f90 @@ -0,0 +1,77 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + +subroutine f00 + integer :: x, y, v + + !ERROR: ATOMIC UPDATE operation with CAPTURE should contain two statements + !$omp atomic update capture + x = v + x = x + 1 + y = x + !$omp end atomic +end + +subroutine f01 + integer :: x, y, v + + !ERROR: ATOMIC UPDATE operation with CAPTURE should contain two assignments + !$omp atomic update capture + x = v + block + x = x + 1 + y = x + end block + !$omp end atomic +end + +subroutine f02 + integer :: x, y + + ! The update and capture statements can be inside of a single BLOCK. + ! The end-directive is then optional. Expect no diagnostics. + !$omp atomic update capture + block + x = x + 1 + y = x + end block +end + +subroutine f03 + integer :: x + + !ERROR: In ATOMIC UPDATE operation with CAPTURE neither statement could be the capture + !$omp atomic update capture + x = x + 1 + x = x + 2 + !$omp end atomic +end + +subroutine f04 + integer :: x, v + + !$omp atomic update capture + !WARNING: In ATOMIC UPDATE operation with CAPTURE either statement could be the update and the capture, assuming the first one is the capture statement + v = x + x = v + !$omp end atomic +end + +subroutine f05 + integer :: x, v, z + + !$omp atomic update capture + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read z + v = x + z = x + 1 + !$omp end atomic +end + +subroutine f06 + integer :: x, v, z + + !$omp atomic update capture + z = x + 1 + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read z + v = x + !$omp end atomic +end diff --git a/flang/test/Semantics/OpenMP/atomic-update-only.f90 b/flang/test/Semantics/OpenMP/atomic-update-only.f90 new file mode 100644 index 0000000000000..28d0e264359cb --- /dev/null +++ b/flang/test/Semantics/OpenMP/atomic-update-only.f90 @@ -0,0 +1,83 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + +subroutine f00 + integer :: x, y + + ! The x is a direct argument of the + operator. Expect no diagnostics. + !$omp atomic update + x = x + (y - 1) +end + +subroutine f01 + integer :: x + + ! x + 0 is unusual, but legal. Expect no diagnostics. + !$omp atomic update + x = x + 0 +end + +subroutine f02 + integer :: x + + ! This is formally not allowed by the syntax restrictions of the spec, + ! but it's equivalent to either x+0 or x*1, both of which are legal. + ! Allow this case. Expect no diagnostics. + !$omp atomic update + x = x +end + +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 + x = (x + y) + 1 +end + +subroutine f04 + integer :: x + real :: y + + !$omp atomic update + !ERROR: This intrinsic function is not a valid ATOMIC UPDATE operation + x = floor(x + y) +end + +subroutine f05 + integer :: x + real :: y + + ! An explicit conversion is accepted as an extension. + !$omp atomic update + x = int(x + y) +end + +subroutine f06 + integer :: x, y + interface + function f(i, j) + integer :: f, i, j + end + end interface + + !$omp atomic update + !ERROR: A call to this function is not a valid ATOMIC UPDATE operation + x = f(x, y) +end + +subroutine f07 + real :: x + integer :: y + + !$omp atomic update + !ERROR: The ** operator is not a valid ATOMIC UPDATE operation + x = x ** y +end + +subroutine f08 + integer :: x, y + + !$omp atomic update + !ERROR: The atomic variable x should appear as an argument in the update operation + x = y +end diff --git a/flang/test/Semantics/OpenMP/atomic-update-overloaded-ops.f90 b/flang/test/Semantics/OpenMP/atomic-update-overloaded-ops.f90 index 21a9b87d26345..3084376b4275d 100644 --- a/flang/test/Semantics/OpenMP/atomic-update-overloaded-ops.f90 +++ b/flang/test/Semantics/OpenMP/atomic-update-overloaded-ops.f90 @@ -22,10 +22,10 @@ program sample x = x / y !$omp atomic update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: A call to this function is not a valid ATOMIC UPDATE operation x = x .MYOPERATOR. y !$omp atomic - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: A call to this function is not a valid ATOMIC UPDATE operation x = x .MYOPERATOR. y end program diff --git a/flang/test/Semantics/OpenMP/atomic-write.f90 b/flang/test/Semantics/OpenMP/atomic-write.f90 new file mode 100644 index 0000000000000..7965ad2dc7dbf --- /dev/null +++ b/flang/test/Semantics/OpenMP/atomic-write.f90 @@ -0,0 +1,81 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + +subroutine f00 + integer :: x, v + ! The end-directive is optional in ATOMIC WRITE. Expect no diagnostics. + !$omp atomic write + x = v + 1 + + !$omp atomic write + x = v + 3 + !$omp end atomic +end + +subroutine f01 + integer, pointer :: x, v + ! Intrinsic assignment and pointer assignment are both ok. Expect no + ! diagnostics. + !$omp atomic write + x = 2 * v + 3 + + !$omp atomic write + x => v +end + +subroutine f02(i) + integer :: i, v + interface + function p(i) + integer, pointer :: p + integer :: i + end + end interface + + ! Atomic variable can be a function reference. Expect no diagostics. + !$omp atomic write + p(i) = v +end + +subroutine f03 + integer :: x(3), y(5), v(3) + + !$omp atomic write + !ERROR: Atomic variable x should be a scalar + x = v + + !$omp atomic write + !ERROR: Atomic variable y(2_8:4_8:1_8) should be a scalar + y(2:4) = v +end + +subroutine f04 + integer :: x, y(3), v + + !$omp atomic write + !ERROR: Within atomic operation x and x+1_4 access the same storage + x = x + 1 + + ! Accessing same array, but not the same storage. Expect no diagnostics. + !$omp atomic write + y(1) = y(2) +end + +subroutine f06 + character :: x, v + + !$omp atomic write + !ERROR: Atomic variable x cannot have CHARACTER type + x = v +end + +subroutine f07 + integer, allocatable :: x + integer :: v + + allocate(x) + + !$omp atomic write + !ERROR: Atomic variable x cannot be ALLOCATABLE + x = v +end + diff --git a/flang/test/Semantics/OpenMP/atomic.f90 b/flang/test/Semantics/OpenMP/atomic.f90 index 0e100871ea9b4..10b33a3ade22d 100644 --- a/flang/test/Semantics/OpenMP/atomic.f90 +++ b/flang/test/Semantics/OpenMP/atomic.f90 @@ -1,4 +1,6 @@ -! RUN: %python %S/../test_errors.py %s %flang -fopenmp +! REQUIRES: openmp_runtime + +! RUN: %python %S/../test_errors.py %s %flang -fopenmp %openmp_flags use omp_lib ! Check OpenMP 2.13.6 atomic Construct @@ -11,9 +13,13 @@ a = b !$omp end atomic + !ERROR: ACQUIRE clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 + !ERROR: HINT clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 !$omp atomic read acquire hint(OMP_LOCK_HINT_CONTENDED) a = b + !ERROR: RELEASE clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 + !ERROR: HINT clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 !$omp atomic release hint(OMP_LOCK_HINT_UNCONTENDED) write a = b @@ -22,39 +28,32 @@ a = a + 1 !$omp end atomic + !ERROR: HINT clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 + !ERROR: ACQ_REL clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 !$omp atomic hint(1) acq_rel capture b = a a = a + 1 !$omp end atomic - !ERROR: expected end of line + !ERROR: At most one clause from the 'atomic' group is allowed on ATOMIC construct !$omp atomic read write + !ERROR: Atomic expression a+1._4 should be a variable a = a + 1 !$omp atomic a = a + 1 - !ERROR: expected 'UPDATE' - !ERROR: expected 'WRITE' - !ERROR: expected 'COMPARE' - !ERROR: expected 'CAPTURE' - !ERROR: expected 'READ' + !ERROR: NUM_THREADS clause is not allowed on the ATOMIC directive !$omp atomic num_threads(4) a = a + 1 - !ERROR: expected end of line + !ERROR: ATOMIC UPDATE operation with CAPTURE should contain two statements + !ERROR: NUM_THREADS clause is not allowed on the ATOMIC directive !$omp atomic capture num_threads(4) a = a + 1 + !ERROR: RELAXED clause is not allowed on directive ATOMIC in OpenMP v3.1, try -fopenmp-version=50 !$omp atomic relaxed a = a + 1 - !ERROR: expected 'UPDATE' - !ERROR: expected 'WRITE' - !ERROR: expected 'COMPARE' - !ERROR: expected 'CAPTURE' - !ERROR: expected 'READ' - !$omp atomic num_threads write - a = a + 1 - !$omp end parallel end diff --git a/flang/test/Semantics/OpenMP/atomic01.f90 b/flang/test/Semantics/OpenMP/atomic01.f90 index 173effe86b69c..f700c381cadd0 100644 --- a/flang/test/Semantics/OpenMP/atomic01.f90 +++ b/flang/test/Semantics/OpenMP/atomic01.f90 @@ -14,322 +14,277 @@ ! At most one memory-order-clause may appear on the construct. !READ - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the READ directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst read i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the READ directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic read seq_cst seq_cst i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the READ directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst read seq_cst i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the READ directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire acquire read i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the READ directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic read acquire acquire i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the READ directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire read acquire i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the READ directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed read i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the READ directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic read relaxed relaxed i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the READ directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed read relaxed i = j !UPDATE - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic update seq_cst seq_cst - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst update seq_cst - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release release update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic update release release - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release update release - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic update relaxed relaxed - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed update relaxed - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j !CAPTURE - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst capture i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic capture seq_cst seq_cst i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst capture seq_cst i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release release capture i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic capture release release i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release capture release i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed capture i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic capture relaxed relaxed i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed capture relaxed i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !ERROR: At most one ACQ_REL clause can appear on the ATOMIC directive !$omp atomic acq_rel acq_rel capture i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !ERROR: At most one ACQ_REL clause can appear on the ATOMIC directive !$omp atomic capture acq_rel acq_rel i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !ERROR: At most one ACQ_REL clause can appear on the ATOMIC directive !$omp atomic acq_rel capture acq_rel i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire acquire capture i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic capture acquire acquire i = j j = k !$omp end atomic - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive !$omp atomic acquire capture acquire i = j j = k !$omp end atomic !WRITE - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst write i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic write seq_cst seq_cst i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst write seq_cst i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the WRITE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release release write i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the WRITE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic write release release i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELEASE clause can appear on the WRITE directive + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release write release i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the WRITE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed write i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the WRITE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic write relaxed relaxed i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct - !ERROR: At most one RELAXED clause can appear on the WRITE directive + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed write relaxed i = j !No atomic-clause - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release release - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j ! 2.17.7.3 ! At most one hint clause may appear on the construct. - !ERROR: At most one HINT clause can appear on the READ directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_speculative) hint(omp_sync_hint_speculative) read i = j - !ERROR: At most one HINT clause can appear on the READ directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_nonspeculative) read hint(omp_sync_hint_nonspeculative) i = j - !ERROR: At most one HINT clause can appear on the READ directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic read hint(omp_sync_hint_uncontended) hint (omp_sync_hint_uncontended) i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative) i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative) i = j - !ERROR: At most one HINT clause can appear on the WRITE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) i = j - !ERROR: At most one HINT clause can appear on the UPDATE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: At most one HINT clause can appear on the UPDATE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_nonspeculative) update hint(omp_sync_hint_nonspeculative) - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: At most one HINT clause can appear on the UPDATE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic update hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_none) hint(omp_sync_hint_nonspeculative) - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: At most one HINT clause can appear on the CAPTURE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) capture i = j j = k !$omp end atomic - !ERROR: At most one HINT clause can appear on the CAPTURE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic hint(omp_sync_hint_nonspeculative) capture hint(omp_sync_hint_nonspeculative) i = j j = k !$omp end atomic - !ERROR: At most one HINT clause can appear on the CAPTURE directive + !ERROR: At most one HINT clause can appear on the ATOMIC directive !$omp atomic capture hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) i = j j = k @@ -337,34 +292,26 @@ ! 2.17.7.4 ! If atomic-clause is read then memory-order-clause must not be acq_rel or release. - !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive !$omp atomic acq_rel read i = j - !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive !$omp atomic read acq_rel i = j - !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive !$omp atomic release read i = j - !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive !$omp atomic read release i = j ! 2.17.7.5 ! If atomic-clause is write then memory-order-clause must not be acq_rel or acquire. - !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive !$omp atomic acq_rel write i = j - !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive !$omp atomic write acq_rel i = j - !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive !$omp atomic acquire write i = j - !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive !$omp atomic write acquire i = j @@ -372,33 +319,27 @@ ! 2.17.7.6 ! If atomic-clause is update or not present then memory-order-clause must not be acq_rel or acquire. - !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive !$omp atomic acq_rel update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive !$omp atomic update acq_rel - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive !$omp atomic acquire update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive !$omp atomic update acquire - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: Clause ACQ_REL is not allowed on the ATOMIC directive !$omp atomic acq_rel - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j - !ERROR: Clause ACQUIRE is not allowed on the ATOMIC directive !$omp atomic acquire - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable i should appear as an argument in the update operation i = j end program diff --git a/flang/test/Semantics/OpenMP/atomic02.f90 b/flang/test/Semantics/OpenMP/atomic02.f90 index c66085d00f157..45e41f2552965 100644 --- a/flang/test/Semantics/OpenMP/atomic02.f90 +++ b/flang/test/Semantics/OpenMP/atomic02.f90 @@ -28,36 +28,29 @@ program OmpAtomic !$omp atomic a = a/(b + 1) !$omp atomic - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The ** operator is not a valid ATOMIC UPDATE operation a = a**4 !$omp atomic - !ERROR: Expected scalar variable on the LHS of atomic update assignment statement - !ERROR: Invalid or missing operator in atomic update statement - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement + !ERROR: Atomic variable c cannot have CHARACTER type + !ERROR: The atomic variable c should appear as an argument in the update operation c = d !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The < operator is not a valid ATOMIC UPDATE operation l = a .LT. b !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The <= operator is not a valid ATOMIC UPDATE operation l = a .LE. b !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The == operator is not a valid ATOMIC UPDATE operation l = a .EQ. b !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The /= operator is not a valid ATOMIC UPDATE operation l = a .NE. b !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The >= operator is not a valid ATOMIC UPDATE operation l = a .GE. b !$omp atomic - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The > operator is not a valid ATOMIC UPDATE operation l = a .GT. b !$omp atomic m = m .AND. n @@ -76,32 +69,26 @@ program OmpAtomic !$omp atomic update a = a/(b + 1) !$omp atomic update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The ** operator is not a valid ATOMIC UPDATE operation a = a**4 !$omp atomic update - !ERROR: Expected scalar variable on the LHS of atomic update assignment statement - !ERROR: Invalid or missing operator in atomic update statement - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement + !ERROR: Atomic variable c cannot have CHARACTER type + !ERROR: This is not a valid ATOMIC UPDATE operation c = c//d !$omp atomic update - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The < operator is not a valid ATOMIC UPDATE operation l = a .LT. b !$omp atomic update - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The <= operator is not a valid ATOMIC UPDATE operation l = a .LE. b !$omp atomic update - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The == operator is not a valid ATOMIC UPDATE operation l = a .EQ. b !$omp atomic update - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The >= operator is not a valid ATOMIC UPDATE operation l = a .GE. b !$omp atomic update - !ERROR: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The > operator is not a valid ATOMIC UPDATE operation l = a .GT. b !$omp atomic update m = m .AND. n diff --git a/flang/test/Semantics/OpenMP/atomic03.f90 b/flang/test/Semantics/OpenMP/atomic03.f90 index 76367495b9861..b3a3c0d5e7a14 100644 --- a/flang/test/Semantics/OpenMP/atomic03.f90 +++ b/flang/test/Semantics/OpenMP/atomic03.f90 @@ -25,28 +25,26 @@ program OmpAtomic y = MIN(y, 8) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator z = IAND(y, 4) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator z = IOR(y, 5) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator z = IEOR(y, 6) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator z = MAX(y, 7, b, c) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator z = MIN(y, 8, a, d) !$omp atomic - !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'y' + !ERROR: This intrinsic function is not a valid ATOMIC UPDATE operation y = FRACTION(x) !$omp atomic - !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'y' + !ERROR: The atomic variable y should appear as an argument in the update operation y = REAL(x) !$omp atomic update y = IAND(y, 4) @@ -60,26 +58,26 @@ program OmpAtomic y = MIN(y, 8) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator z = IAND(y, 4) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator z = IOR(y, 5) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator z = IEOR(y, 6) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator z = MAX(y, 7) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator z = MIN(y, 8) !$omp atomic update - !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement + !ERROR: This intrinsic function is not a valid ATOMIC UPDATE operation y = MOD(y, 9) !$omp atomic update - !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement + !ERROR: This intrinsic function is not a valid ATOMIC UPDATE operation x = ABS(x) end program OmpAtomic @@ -92,7 +90,7 @@ subroutine conflicting_types() type(simple) ::s z = 1 !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'z' + !ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator z = IAND(s%z, 4) end subroutine @@ -105,40 +103,37 @@ subroutine more_invalid_atomic_update_stmts() type(some_type) :: s !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'a' + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MIN operator a = min(a, a, b) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'a' + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator a = max(b, a, b, a) !$omp atomic - !ERROR: Atomic update statement should be of the form `a = intrinsic_procedure(a, expr_list)` OR `a = intrinsic_procedure(expr_list, a)` a = min(b, a, b) !$omp atomic - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'a' + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator a = max(b, a, b, a, b) !$omp atomic update - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'y' + !ERROR: The atomic variable y should occur exactly once among the arguments of the top-level MIN operator y = min(z, x) !$omp atomic z = max(z, y) !$omp atomic update - !ERROR: Expected scalar variable on the LHS of atomic update assignment statement - !ERROR: Intrinsic procedure arguments in atomic update statement must have exactly one occurence of 'k' + !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 k = max(x, y) - + !$omp atomic !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement x = min(x, k) !$omp atomic !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement - z =z + s%m + z = z + s%m end subroutine diff --git a/flang/test/Semantics/OpenMP/atomic04.f90 b/flang/test/Semantics/OpenMP/atomic04.f90 index a9644ad95aa30..0f69befed1414 100644 --- a/flang/test/Semantics/OpenMP/atomic04.f90 +++ b/flang/test/Semantics/OpenMP/atomic04.f90 @@ -1,5 +1,3 @@ -! REQUIRES: openmp_runtime - ! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags ! OpenMP Atomic construct @@ -7,7 +5,6 @@ ! Update assignment must be 'var = var op expr' or 'var = expr op var' program OmpAtomic - use omp_lib real x integer y logical m, n, l @@ -20,12 +17,10 @@ program OmpAtomic !$omp atomic x = 1 + x !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator x = y + 1 !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator x = 1 + y !$omp atomic @@ -33,12 +28,10 @@ program OmpAtomic !$omp atomic x = 1 - x !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator x = y - 1 !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator x = 1 - y !$omp atomic @@ -46,12 +39,10 @@ program OmpAtomic !$omp atomic x = 1*x !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = y*1 !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = 1*y !$omp atomic @@ -59,12 +50,10 @@ program OmpAtomic !$omp atomic x = 1/x !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator x = y/1 !$omp atomic - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator x = 1/y !$omp atomic @@ -72,8 +61,7 @@ program OmpAtomic !$omp atomic m = n .AND. m !$omp atomic - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator m = n .AND. l !$omp atomic @@ -81,8 +69,7 @@ program OmpAtomic !$omp atomic m = n .OR. m !$omp atomic - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator m = n .OR. l !$omp atomic @@ -90,8 +77,7 @@ program OmpAtomic !$omp atomic m = n .EQV. m !$omp atomic - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator m = n .EQV. l !$omp atomic @@ -99,8 +85,7 @@ program OmpAtomic !$omp atomic m = n .NEQV. m !$omp atomic - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator m = n .NEQV. l !$omp atomic update @@ -108,12 +93,10 @@ program OmpAtomic !$omp atomic update x = 1 + x !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator x = y + 1 !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator x = 1 + y !$omp atomic update @@ -121,12 +104,10 @@ program OmpAtomic !$omp atomic update x = 1 - x !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator x = y - 1 !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator x = 1 - y !$omp atomic update @@ -134,12 +115,10 @@ program OmpAtomic !$omp atomic update x = 1*x !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = y*1 !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = 1*y !$omp atomic update @@ -147,12 +126,10 @@ program OmpAtomic !$omp atomic update x = 1/x !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator x = y/1 !$omp atomic update - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Exactly one occurence of 'x' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator x = 1/y !$omp atomic update @@ -160,8 +137,7 @@ program OmpAtomic !$omp atomic update m = n .AND. m !$omp atomic update - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator m = n .AND. l !$omp atomic update @@ -169,8 +145,7 @@ program OmpAtomic !$omp atomic update m = n .OR. m !$omp atomic update - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator m = n .OR. l !$omp atomic update @@ -178,8 +153,7 @@ program OmpAtomic !$omp atomic update m = n .EQV. m !$omp atomic update - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator m = n .EQV. l !$omp atomic update @@ -187,8 +161,7 @@ program OmpAtomic !$omp atomic update m = n .NEQV. m !$omp atomic update - !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` - !ERROR: Exactly one occurence of 'm' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator m = n .NEQV. l end program OmpAtomic @@ -204,35 +177,34 @@ subroutine more_invalid_atomic_update_stmts() type(some_type) p !$omp atomic - !ERROR: Invalid or missing operator in atomic update statement x = x !$omp atomic update - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = 1 !$omp atomic update - !ERROR: Exactly one occurence of 'a' expected on the RHS of atomic update assignment statement + !ERROR: Within atomic operation a and a*b access the same storage a = a * b + a !$omp atomic - !ERROR: Atomic update statement should be of form `a = a operator expr` OR `a = expr operator a` + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level * operator a = b * (a + 9) !$omp atomic update - !ERROR: Exactly one occurence of 'a' expected on the RHS of atomic update assignment statement + !ERROR: Within atomic operation a and (a+b) access the same storage a = a * (a + b) !$omp atomic - !ERROR: Exactly one occurence of 'a' expected on the RHS of atomic update assignment statement + !ERROR: Within atomic operation a and (b+a) access the same storage a = (b + a) * a !$omp atomic - !ERROR: Atomic update statement should be of form `a = a operator expr` OR `a = expr operator a` + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator a = a * b + c !$omp atomic update - !ERROR: Atomic update statement should be of form `a = a operator expr` OR `a = expr operator a` + !ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator a = a + b + c !$omp atomic @@ -243,23 +215,18 @@ subroutine more_invalid_atomic_update_stmts() !$omp atomic !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement a = a + d !$omp atomic update !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement + !ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator x = x * y / z !$omp atomic - !ERROR: Atomic update statement should be of form `p%m = p%m operator expr` OR `p%m = expr operator p%m` - !ERROR: Exactly one occurence of 'p%m' expected on the RHS of atomic update assignment statement + !ERROR: The atomic variable p%m should occur exactly once among the arguments of the top-level + operator p%m = x + y !$omp atomic update !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4) - !ERROR: Expected scalar expression on the RHS of atomic update assignment statement - !ERROR: Exactly one occurence of 'p%m' expected on the RHS of atomic update assignment statement p%m = p%m + p%n end subroutine diff --git a/flang/test/Semantics/OpenMP/atomic05.f90 b/flang/test/Semantics/OpenMP/atomic05.f90 index 266268a212440..77ffc6e57f1a3 100644 --- a/flang/test/Semantics/OpenMP/atomic05.f90 +++ b/flang/test/Semantics/OpenMP/atomic05.f90 @@ -8,20 +8,20 @@ program OmpAtomic use omp_lib integer :: g, x - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct !$omp atomic relaxed, seq_cst x = x + 1 - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct !$omp atomic read seq_cst, relaxed x = g - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct !$omp atomic write relaxed, release x = 2 * 4 - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct !$omp atomic update release, seq_cst - !ERROR: Invalid or missing operator in atomic update statement + !ERROR: The atomic variable x should appear as an argument in the update operation x = 10 - !ERROR: More than one memory order clause not allowed on OpenMP ATOMIC construct + !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct !$omp atomic capture release, seq_cst x = g g = x * 10 diff --git a/flang/test/Semantics/OpenMP/critical-hint-clause.f90 b/flang/test/Semantics/OpenMP/critical-hint-clause.f90 index 7ca8c858239f7..e9cfa49bf934e 100644 --- a/flang/test/Semantics/OpenMP/critical-hint-clause.f90 +++ b/flang/test/Semantics/OpenMP/critical-hint-clause.f90 @@ -18,7 +18,7 @@ program sample y = 2 !$omp end critical (name) - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp critical (name) hint(3) y = 2 !$omp end critical (name) @@ -27,12 +27,12 @@ program sample y = 2 !$omp end critical (name) - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp critical (name) hint(7) y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp critical (name) hint(x) y = 2 @@ -54,7 +54,7 @@ program sample y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint) y = 2 @@ -84,35 +84,35 @@ program sample y = 2 !$omp end critical (name) - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint_contended) y = 2 !$omp end critical (name) - !ERROR: Hint clause value is not a valid OpenMP synchronization value + !ERROR: The synchronization hint is not valid !$omp critical (name) hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative) y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must have INTEGER type, but is REAL(4) !$omp critical (name) hint(1.0) y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4) !$omp critical (name) hint(z + omp_sync_hint_nonspeculative) y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp critical (name) hint(k + omp_sync_hint_speculative) y = 2 !$omp end critical (name) - !ERROR: Hint clause must have non-negative constant integer expression + !ERROR: Synchronization hint must be a constant integer value !ERROR: Must be a constant value !$omp critical (name) hint(p(1) + omp_sync_hint_uncontended) y = 2 diff --git a/flang/test/Semantics/OpenMP/depend-substring.f90 b/flang/test/Semantics/OpenMP/depend-substring.f90 new file mode 100644 index 0000000000000..23d6bb4c0b7b3 --- /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/implicit-dsa.f90 b/flang/test/Semantics/OpenMP/implicit-dsa.f90 index 3e9348575597b..1ee777d6b9723 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 @@ -244,3 +244,25 @@ subroutine implicit_dsa_test_12 !REF: /implicit_dsa_test_12/tm3a print *,tm3a end subroutine + +! Test static duration variables with DSA set in the enclosing scope do not default to shared DSA +!DEF: /implicit_dsa_test_13_mod Module +module implicit_dsa_test_13_mod + !DEF: /implicit_dsa_test_13_mod/a PUBLIC ObjectEntity INTEGER(4) + integer::a=5 +contains + !DEF: /implicit_dsa_test_13_mod/implicit_dsa_test_13 PUBLIC (Subroutine) Subprogram + subroutine implicit_dsa_test_13 + !DEF: /implicit_dsa_test_13_mod/implicit_dsa_test_13/i ObjectEntity INTEGER(4) + integer i + !$omp do private(a) + !DEF: /implicit_dsa_test_13_mod/implicit_dsa_test_13/OtherConstruct1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=0,10 + !$omp task + !DEF: /implicit_dsa_test_13_mod/implicit_dsa_test_13/OtherConstruct1/OtherConstruct1/a (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4) + !DEF: /implicit_dsa_test_13_mod/implicit_dsa_test_13/OtherConstruct1/OtherConstruct1/i (OmpFirstPrivate, OmpImplicit) HostAssoc INTEGER(4) + a=a+i + !$omp end task + end do + end subroutine implicit_dsa_test_13 +end module implicit_dsa_test_13_mod diff --git a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 index 505cbc48fef90..8fdd2aed3ec1f 100644 --- a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 +++ b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 @@ -20,70 +20,64 @@ program sample !$omp atomic read !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) - !ERROR: Expected scalar expression on the RHS of atomic assignment statement + !ERROR: Atomic variable y(1_8:3_8:1_8) should be a scalar v = y(1:3) !$omp atomic read - !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement + !ERROR: Atomic expression x*(10_4+x) should be a variable v = x * (10 + x) !$omp atomic read - !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement + !ERROR: Atomic expression 4_4 should be a variable v = 4 !$omp atomic read - !ERROR: k must not have ALLOCATABLE attribute + !ERROR: Atomic variable k cannot be ALLOCATABLE v = k !$omp atomic write - !ERROR: k must not have ALLOCATABLE attribute + !ERROR: Atomic variable k cannot be ALLOCATABLE k = x !$omp atomic update - !ERROR: k must not have ALLOCATABLE attribute + !ERROR: Atomic variable k cannot be ALLOCATABLE k = k + x * (v * x) !$omp atomic - !ERROR: k must not have ALLOCATABLE attribute + !ERROR: Atomic variable k cannot be ALLOCATABLE k = v * k !$omp atomic write - !ERROR: RHS expression on atomic assignment statement cannot access 'z%y' + !ERROR: Within atomic operation z%y and x+z%y access the same storage z%y = x + z%y !$omp atomic write - !ERROR: RHS expression on atomic assignment statement cannot access 'x' + !ERROR: Within atomic operation x and x access the same storage x = x !$omp atomic write - !ERROR: RHS expression on atomic assignment statement cannot access 'm' + !ERROR: Within atomic operation m and min(m,x,z%m)+k access the same storage m = min(m, x, z%m) + k !$omp atomic read - !ERROR: RHS expression on atomic assignment statement cannot access 'x' + !ERROR: Within atomic operation x and x access the same storage x = x !$omp atomic read - !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement - !ERROR: RHS expression on atomic assignment statement cannot access 'm' + !ERROR: Atomic expression min(m,x,z%m)+k should be a variable m = min(m, x, z%m) + k !$omp atomic read !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) - !ERROR: Expected scalar expression on the RHS of atomic assignment statement + !ERROR: Atomic variable a should be a scalar x = a - !$omp atomic read - !ERROR: Expected scalar variable on the LHS of atomic assignment statement - a = x - !$omp atomic write !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) - !ERROR: Expected scalar expression on the RHS of atomic assignment statement x = a !$omp atomic write - !ERROR: Expected scalar variable on the LHS of atomic assignment statement + !ERROR: Atomic variable a should be a scalar a = x !$omp atomic capture @@ -93,7 +87,7 @@ program sample !$omp atomic release capture v = x - !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + ! This ends up being "x = b + x". x = b + (x*1) !$omp end atomic @@ -103,60 +97,58 @@ program sample !$omp end atomic !$omp atomic capture - !ERROR: Captured variable/array element/derived-type component x expected to be assigned in the second statement of ATOMIC CAPTURE construct + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read b v = x b = b + 1 !$omp end atomic !$omp atomic capture - !ERROR: Captured variable/array element/derived-type component x expected to be assigned in the second statement of ATOMIC CAPTURE construct + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read b v = x b = 10 !$omp end atomic !$omp atomic capture - !ERROR: Updated variable/array element/derived-type component x expected to be captured in the second statement of ATOMIC CAPTURE construct x = x + 10 + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read x v = b !$omp end atomic + !ERROR: In ATOMIC UPDATE operation with CAPTURE neither statement could be the update or the capture !$omp atomic capture - !ERROR: Invalid ATOMIC CAPTURE construct statements. Expected one of [update-stmt, capture-stmt], [capture-stmt, update-stmt], or [capture-stmt, write-stmt] v = 1 x = 4 !$omp end atomic !$omp atomic capture - !ERROR: Captured variable/array element/derived-type component z%y expected to be assigned in the second statement of ATOMIC CAPTURE construct + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read z%m x = z%y z%m = z%m + 1.0 !$omp end atomic !$omp atomic capture - !ERROR: Updated variable/array element/derived-type component z%m expected to be captured in the second statement of ATOMIC CAPTURE construct z%m = z%m + 1.0 + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read z%m x = z%y !$omp end atomic !$omp atomic capture - !ERROR: Captured variable/array element/derived-type component y(2) expected to be assigned in the second statement of ATOMIC CAPTURE construct + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read y(1_8) x = y(2) y(1) = y(1) + 1 !$omp end atomic !$omp atomic capture - !ERROR: Updated variable/array element/derived-type component y(1) expected to be captured in the second statement of ATOMIC CAPTURE construct y(1) = y(1) + 1 + !ERROR: In ATOMIC UPDATE operation with CAPTURE the right-hand side of the capture assignment should read y(1_8) x = y(2) !$omp end atomic !$omp atomic read - !ERROR: Expected scalar variable on the LHS of atomic assignment statement - !ERROR: Expected scalar expression on the RHS of atomic assignment statement + !ERROR: Atomic variable r cannot have CHARACTER type l = r !$omp atomic write - !ERROR: Expected scalar variable on the LHS of atomic assignment statement - !ERROR: Expected scalar expression on the RHS of atomic assignment statement + !ERROR: Atomic variable l cannot have CHARACTER type l = r end program 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 0000000000000..72c8002ab4c59 --- /dev/null +++ b/flang/test/Semantics/OpenMP/parallel-master-goto.f90 @@ -0,0 +1,15 @@ +! 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 +!WARNING: OpenMP directive MASTER has been deprecated, please use MASKED instead. +!$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 6c5a053bf49c9..19448258af766 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 index ae9fd086015dd..e8817c3f5ef61 100644 --- a/flang/test/Semantics/OpenMP/requires-atomic01.f90 +++ b/flang/test/Semantics/OpenMP/requires-atomic01.f90 @@ -10,20 +10,23 @@ program requires ! READ ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Read + ! CHECK: OmpClause -> SeqCst !$omp atomic read i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Read !$omp atomic relaxed read i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Read + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed !$omp atomic read relaxed i = j @@ -31,20 +34,23 @@ program requires ! WRITE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Write + ! CHECK: OmpClause -> SeqCst !$omp atomic write i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Write !$omp atomic relaxed write i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Write + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed !$omp atomic write relaxed i = j @@ -52,31 +58,34 @@ program requires ! UPDATE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Update + ! CHECK: OmpClause -> SeqCst !$omp atomic update i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Update !$omp atomic relaxed update i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Update + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed !$omp atomic update relaxed i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomic - ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> SeqCst !$omp atomic i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomic - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed !$omp atomic relaxed i = i + j @@ -84,24 +93,27 @@ program requires ! CAPTURE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture - ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Capture + ! CHECK: OmpClause -> SeqCst !$omp atomic capture i = j j = j + 1 !$omp end atomic - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! 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 -> OmpAtomicCapture - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> SeqCst - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Capture + ! CHECK-NOT: OmpClause -> SeqCst + ! CHECK: OmpClause -> Relaxed !$omp atomic capture relaxed i = j j = j + 1 diff --git a/flang/test/Semantics/OpenMP/requires-atomic02.f90 b/flang/test/Semantics/OpenMP/requires-atomic02.f90 index 4976a9667eb78..04a9b7a09aa98 100644 --- a/flang/test/Semantics/OpenMP/requires-atomic02.f90 +++ b/flang/test/Semantics/OpenMP/requires-atomic02.f90 @@ -10,20 +10,23 @@ program requires ! READ ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Acquire + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Read + ! CHECK: OmpClause -> Acquire !$omp atomic read i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Acquire - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Read !$omp atomic relaxed read i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicRead - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Acquire - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Read + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed !$omp atomic read relaxed i = j @@ -31,20 +34,23 @@ program requires ! WRITE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Release + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Write + ! CHECK: OmpClause -> Release !$omp atomic write i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Release - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Write !$omp atomic relaxed write i = j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicWrite - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Release - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Write + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed !$omp atomic write relaxed i = j @@ -52,31 +58,34 @@ program requires ! UPDATE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Release + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Update + ! CHECK: OmpClause -> Release !$omp atomic update i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Release - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed + ! CHECK: OmpClause -> Update !$omp atomic relaxed update i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicUpdate - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Release - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Update + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed !$omp atomic update relaxed i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomic - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Release + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Release !$omp atomic i = i + j - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomic - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> Release - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Relaxed !$omp atomic relaxed i = i + j @@ -84,24 +93,27 @@ program requires ! CAPTURE ! ---------------------------------------------------------------------------- - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture - ! CHECK: OmpMemoryOrderClause -> OmpClause -> AcqRel + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK: OmpClause -> Capture + ! CHECK: OmpClause -> AcqRel !$omp atomic capture i = j j = j + 1 !$omp end atomic - ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> AcqRel - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! 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 -> OmpAtomicCapture - ! CHECK-NOT: OmpMemoryOrderClause -> OmpClause -> AcqRel - ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed + ! CHECK-LABEL: OpenMPAtomicConstruct + ! CHECK-NOT: OmpClause -> AcqRel + ! CHECK: OmpClause -> Capture + ! CHECK: OmpClause -> Relaxed !$omp atomic capture relaxed i = j j = j + 1 diff --git a/flang/test/Semantics/OpenMP/sections-goto.f90 b/flang/test/Semantics/OpenMP/sections-goto.f90 new file mode 100644 index 0000000000000..9fa9df9f50b9c --- /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 ee29922a72c08..8144b491071d8 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 1b7495e9fc07d..8aeb069df09f2 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 b8b99a8d1d9be..db32f1dbd0e7b 100644 --- a/flang/test/Semantics/cuf21.cuf +++ b/flang/test/Semantics/cuf21.cuf @@ -9,19 +9,25 @@ module mlocModule end interface maxlocUpdate contains - attributes(global) subroutine maxlocPartialMaskR_32F1D() + attributes(global) subroutine maxlocPartialMaskR_32F1D(back) implicit none + logical, intent(in), value :: back real(4) :: mval - - call maxlocUpdate(mval) - + block + integer(8) :: xloc + call maxlocUpdate(mval, xloc, back) + end block end subroutine maxlocPartialMaskR_32F1D - attributes(device) subroutine maxlocUpdateR_32F(mval) + 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) + 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/cuf22.cuf b/flang/test/Semantics/cuf22.cuf new file mode 100644 index 0000000000000..36e0f0b2502df --- /dev/null +++ b/flang/test/Semantics/cuf22.cuf @@ -0,0 +1,8 @@ +! RUN: not bbc -fcuda -fcuda-disable-warp-function %s -o - 2>&1 | FileCheck %s + +attributes(device) subroutine testMatch() + integer :: a, ipred, mask, v32 + a = match_all_sync(mask, v32, ipred) +end subroutine + +! CHECK: warp match function disabled diff --git a/flang/test/Semantics/indirect01.f90 b/flang/test/Semantics/indirect01.f90 new file mode 100644 index 0000000000000..59850662275d9 --- /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 0000000000000..273f8856626b7 --- /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 7c3c7f5b48958..7f32eb18c6f8f 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 aba00ffac848a..8f7adafe7204d 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 0000000000000..c7ae91bd42bed --- /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 0000000000000..9ad615c16c43c --- /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 0000000000000..19b9ac39de934 --- /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 0000000000000..ae156527b3bf3 --- /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 d228cd2a84ca4..bb20c546e0261 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 @@ subroutine s2(x, y) 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 @@ subroutine s2(x, y) 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 @@ impure elemental subroutine s1(x, y) 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 @@ impure elemental subroutine s3(x) 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 @@ subroutine wu(x,u,iostat,iomsg) 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 @@ subroutine wu(x,u,iostat,iomsg) 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 f0c0a817da4a4..e2552d0a21d6f 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 de8464321a409..94dd2199db35a 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 2a7f12a153eb8..df1aecf3821de 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 2385709a8eb44..22f37b1a4369d 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 e8766d9811db8..ab20d6f601106 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 689cf469dee3b..391a66f3d6664 100644 --- a/flang/test/Semantics/typeinfo08.f90 +++ b/flang/test/Semantics/typeinfo08.f90 @@ -13,7 +13,7 @@ module m !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 92efc8f9ea54b..08e0b95abb763 100644 --- a/flang/test/Semantics/typeinfo11.f90 +++ b/flang/test/Semantics/typeinfo11.f90 @@ -14,4 +14,4 @@ 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 0000000000000..6b23b63d28b1d --- /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 new file mode 100644 index 0000000000000..ad824ad3590a2 --- /dev/null +++ b/flang/test/Semantics/typeinfo13.f90 @@ -0,0 +1,26 @@ +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s +!Ensure ASSIGNMENT(=) overrides are applied to the special procedures table. +module m + type base + contains + procedure :: baseAssign + generic :: assignment(=) => baseAssign + end type + type, extends(base) :: child + contains + procedure :: override + generic :: assignment(=) => override + end type + contains + impure elemental subroutine baseAssign(to, from) + class(base), intent(out) :: to + type(base), intent(in) :: from + end + impure elemental subroutine override(to, from) + class(child), intent(out) :: to + type(child), intent(in) :: from + 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=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/DoConcurrent/locality_specifiers_init_dealloc.mlir b/flang/test/Transforms/DoConcurrent/locality_specifiers_init_dealloc.mlir new file mode 100644 index 0000000000000..1659c7bdf6d3e --- /dev/null +++ b/flang/test/Transforms/DoConcurrent/locality_specifiers_init_dealloc.mlir @@ -0,0 +1,51 @@ +// Tests mapping `local` locality specifier to `private` clauses for non-empty +// `init` and `dealloc` regions. + +// RUN: fir-opt --omp-do-concurrent-conversion="map-to=host" %s | FileCheck %s + +func.func @my_allocator(%arg0: !fir.ref>>, %arg1: !fir.ref>>) { + return +} + +func.func @my_deallocator(%arg0: !fir.ref>>) { + return +} + +fir.local {type = local} @_QFlocal_assocEaa_private_box_10xf32 : !fir.box> init { +^bb0(%arg0: !fir.ref>>, %arg1: !fir.ref>>): + fir.call @my_allocator(%arg0, %arg1) : (!fir.ref>>, !fir.ref>>) -> () + fir.yield(%arg1 : !fir.ref>>) +} dealloc { +^bb0(%arg0: !fir.ref>>): + fir.call @my_deallocator(%arg0) : (!fir.ref>>) -> () + fir.yield +} + +func.func @_QPlocal_assoc() { + %0 = fir.alloca !fir.box> + %c1 = arith.constant 1 : index + + fir.do_concurrent { + %9 = fir.alloca i32 {bindc_name = "i"} + %10:2 = hlfir.declare %9 {uniq_name = "_QFlocal_assocEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + fir.do_concurrent.loop (%arg0) = (%c1) to (%c1) step (%c1) local(@_QFlocal_assocEaa_private_box_10xf32 %0 -> %arg1 : !fir.ref>>) { + %11 = fir.convert %arg0 : (index) -> i32 + fir.store %11 to %10#0 : !fir.ref + } + } + + return +} + +// CHECK: omp.private {type = private} @[[PRIVATIZER:.*]] : !fir.box> init { +// CHECK-NEXT: ^bb0(%[[ORIG_ARG:.*]]: !{{.*}}, %[[PRIV_ARG:.*]]: !{{.*}}): +// CHECK-NEXT: fir.call @my_allocator(%[[ORIG_ARG]], %[[PRIV_ARG]]) : ({{.*}}) -> () +// CHECK-NEXT: omp.yield(%[[PRIV_ARG]] : {{.*}}) +// CHECK-NEXT: } dealloc { +// CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: !{{.*}}): +// CHECK-NEXT: fir.call @my_deallocator(%[[PRIV_ARG]]) : ({{.*}}) -> () +// CHECK-NEXT: omp.yield +// CHECK-NEXT: } + +// CHECK: %[[LOCAL_ALLOC:.*]] = fir.alloca !fir.box> +// CHECK: omp.wsloop private(@[[PRIVATIZER]] %[[LOCAL_ALLOC]] -> %{{.*}} : !{{.*}}) diff --git a/flang/test/Transforms/DoConcurrent/locality_specifiers_simple.mlir b/flang/test/Transforms/DoConcurrent/locality_specifiers_simple.mlir new file mode 100644 index 0000000000000..160c1df040680 --- /dev/null +++ b/flang/test/Transforms/DoConcurrent/locality_specifiers_simple.mlir @@ -0,0 +1,48 @@ +// Tests mapping `local` locality specifier to `private` clauses for a simple +// case (not `init` or `copy` regions). + +// RUN: fir-opt --omp-do-concurrent-conversion="map-to=host" %s | FileCheck %s + +fir.local {type = local} @_QFlocal_spec_translationElocal_var_private_f32 : f32 + +func.func @_QPlocal_spec_translation() { + %3 = fir.alloca f32 {bindc_name = "local_var", uniq_name = "_QFlocal_spec_translationElocal_var"} + %4:2 = hlfir.declare %3 {uniq_name = "_QFlocal_spec_translationElocal_var"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + %c4_i32 = arith.constant 4 : index + %c11_i32 = arith.constant 11 : index + %c1 = arith.constant 1 : index + + fir.do_concurrent { + %7 = fir.alloca i32 {bindc_name = "i"} + %8:2 = hlfir.declare %7 {uniq_name = "_QFlocal_spec_translationEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + fir.do_concurrent.loop (%arg0) = (%c4_i32) to (%c11_i32) step (%c1) + local(@_QFlocal_spec_translationElocal_var_private_f32 %4#0 -> %arg1 : !fir.ref) { + %9 = fir.convert %arg0 : (index) -> i32 + fir.store %9 to %8#0 : !fir.ref + + %10:2 = hlfir.declare %arg1 {uniq_name = "_QFlocal_spec_translationElocal_var"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %cst = arith.constant 4.200000e+01 : f32 + hlfir.assign %cst to %10#0 : f32, !fir.ref + } + } + return +} + +// CHECK: omp.private {type = private} @[[PRIVATIZER:.*local_spec_translationElocal_var.*.omp]] : f32 + +// CHECK: func.func @_QPlocal_spec_translation +// CHECK: %[[LOCAL_VAR:.*]] = fir.alloca f32 {bindc_name = "local_var", {{.*}}} +// CHECK: %[[LOCAL_VAR_DECL:.*]]:2 = hlfir.declare %[[LOCAL_VAR]] +// CHECK: omp.parallel { +// CHECK: omp.wsloop private(@[[PRIVATIZER]] %[[LOCAL_VAR_DECL]]#0 -> %[[LOCAL_ARG:.*]] : !fir.ref) { +// CHECK: omp.loop_nest {{.*}} { +// CHECK: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[LOCAL_ARG]] +// CHECK: %[[C42:.*]] = arith.constant +// CHECK: hlfir.assign %[[C42]] to %[[PRIV_DECL]]#0 +// CHECK: omp.yield +// CHECK: } +// CHECK: } +// CHECK: omp.terminator +// CHECK: } 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 0000000000000..b59ffdfb34adf --- /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 0000000000000..ebb56aec278f6 --- /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/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index c544008a24d56..015c86604a1fd 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -223,6 +223,11 @@ static llvm::cl::opt enableCUDA("fcuda", llvm::cl::desc("enable CUDA Fortran"), llvm::cl::init(false)); +static llvm::cl::opt + disableCUDAWarpFunction("fcuda-disable-warp-function", + llvm::cl::desc("Disable CUDA Warp Function"), + llvm::cl::init(false)); + static llvm::cl::opt enableGPUMode("gpu", llvm::cl::desc("Enable GPU Mode managed|unified"), llvm::cl::init("")); @@ -429,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; @@ -600,6 +607,11 @@ int main(int argc, char **argv) { options.features.Enable(Fortran::common::LanguageFeature::CUDA); } + if (disableCUDAWarpFunction) { + options.features.Enable( + Fortran::common::LanguageFeature::CudaWarpMatchFunction, false); + } + if (enableGPUMode == "managed") { options.features.Enable(Fortran::common::LanguageFeature::CudaManaged); } else if (enableGPUMode == "unified") { diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index f21fc2fba7305..9907adfc55a5f 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 0facb0b9be0c1..a98e7276bef80 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) + set(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 99f90244e0134..01c288f0b9198 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 bfe956855cb52..d53b2936edb07 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/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 520046f768b5d..9e042cd4a8acb 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 7432a7e912e81..1161ae260be2e 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 0b645a2d2fb8b..db8f8a7cf0b74 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 959bdbf08dbea..aa2079faed409 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 diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst index 8d53390ae19bf..109412225634f 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 0bd3a69ae3ffe..86247966552f9 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 8f89baa702000..401785a30469c 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 209fcb965242f..052a773a4fcec 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 0000000000000..935d436273465 --- /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 5f6197c93d445..c88c357009072 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -1,3 +1,25 @@ +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( div_t HDRS diff --git a/libc/hdr/types/char32_t.h b/libc/hdr/types/char32_t.h new file mode 100644 index 0000000000000..94fe5747d3415 --- /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 0000000000000..4d71e3dd89098 --- /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/uchar_overlay.h b/libc/hdr/uchar_overlay.h new file mode 100644 index 0000000000000..44ed3d48c6c1d --- /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 7209e10c68b8f..55268d19529c7 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 5eb779aeeca56..41226080084c3 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 ddadab1afa219..a343be77d810b 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/size_t.h b/libc/include/llvm-libc-types/size_t.h index 3b31b0820f237..26ae68abe0ee7 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 41e4b6d2c500a..8f579e2749bac 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 6c71b70e59f0b..4566984ad83af 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 466c08ade6fc4..11bead0745954 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 2619984cca264..2a0c563709984 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 f7155ba27a162..3b2ff13c684b1 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 1bd2687db2bea..339d005e43a4f 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 9f72b8db6c1eb..736deceb453de 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 7bb25dbe85ac4..3b9d77c0aaae2 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 877be48b6a10f..84db73d8f01ea 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 @@ -107,24 +109,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 +147,13 @@ 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: 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 2898c508b7772..e6bb1e17b80c9 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 0000000000000..c4560bbb02763 --- /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 0000000000000..4ddc29c7ae834 --- /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 0000000000000..a4e8b0751bb42 --- /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 5509094b944ad..46e35f13f0eac 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 b133a28e26efc..dcc6027d6c77f 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 15bee698d5a6b..6ed38c932662e 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 f92499fdbf451..7e85136c08851 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 4c8f34a435bdf..50a101f833c55 100644 --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -12,10 +12,10 @@ #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/properties/architectures.h" -#include "src/errno/libc_errno.h" #if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP) #if defined(__APPLE__) diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp index 21b0106f70106..aea8862c15f7f 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 528542cccf324..303852dbbb717 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 824c1f200e8c5..4594dadf1ccdf 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 a034913d9f6ec..300e5c5dd55bf 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 135ced3df704c..66ab155e5c299 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 @@ template struct GuardPtr { 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 @@ template struct GuardPtr { 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 @@ template struct GuardPtr { 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 @@ template struct GuardPtr { 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 @@ template struct GuardPtr { }; // 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 3c487e4f29264..a1de0680cc7d5 100644 --- a/libc/src/__support/HashTable/CMakeLists.txt +++ b/libc/src/__support/HashTable/CMakeLists.txt @@ -32,9 +32,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 244dd41be3eec..6b58a4125f785 100644 --- a/libc/src/__support/HashTable/randomness.h +++ b/libc/src/__support/HashTable/randomness.h @@ -14,7 +14,7 @@ #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/__support/libc_errno.h" #include "src/sys/random/getrandom.h" #endif diff --git a/libc/src/__support/HashTable/table.h b/libc/src/__support/HashTable/table.h index 13badb90dbfde..10dd9711afbf6 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 @@ struct HashTable { 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 @@ struct HashTable { 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 @@ struct HashTable { 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 46f7d28132396..3983d78f7f89c 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 b9704d42cd33b..4681d8c2bb73c 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 diff --git a/libc/src/__support/OSUtil/linux/fcntl.cpp b/libc/src/__support/OSUtil/linux/fcntl.cpp index 4742b2a00220b..bb76eee90efd2 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/vdso.cpp b/libc/src/__support/OSUtil/linux/vdso.cpp index 8c9bd3e1bcc72..e4e53c3c2a0f2 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 425590f6e91c9..de637d60bea97 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 0000000000000..ab5f6a9c4b9d9 --- /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/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt new file mode 100644 index 0000000000000..66c1d19a1cab0 --- /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 0000000000000..cabb227a034b5 --- /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 0000000000000..88c151492a041 --- /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 c531d74c53355..baad26aed6851 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 0000000000000..6715e354e23e5 --- /dev/null +++ b/libc/src/__support/wchar/CMakeLists.txt @@ -0,0 +1,21 @@ +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 +) diff --git a/libc/src/__support/wchar/character_converter.cpp b/libc/src/__support/wchar/character_converter.cpp new file mode 100644 index 0000000000000..5ab0447bb08b2 --- /dev/null +++ b/libc/src/__support/wchar/character_converter.cpp @@ -0,0 +1,149 @@ +//===-- 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_processed = 0; + state->total_bytes = 0; +} + +bool CharacterConverter::isComplete() { + return state->bytes_processed == state->total_bytes; +} + +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 (state->bytes_processed == 0) { + // 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_processed and total_bytes will always be 0 here + state->partial = static_cast(0); + return -1; + } + state->partial = static_cast(utf8_byte); + state->bytes_processed++; + return 0; + } + // Any subsequent push + // Adding 6 more bits so need to left shift + if (num_ones == 1 && !isComplete()) { + char32_t byte = utf8_byte & MASK_ENCODED_BITS; + state->partial = state->partial << ENCODED_BITS_PER_UTF8; + state->partial |= byte; + state->bytes_processed++; + 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 (!isComplete()) + return -1; + + state->partial = utf32; + state->bytes_processed = 0; + + // 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; + 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 (!isComplete() || state->bytes_processed == 0) + return Error(-1); + char32_t utf32 = state->partial; + // reset if successful pop + clear(); + return utf32; +} + +ErrorOr CharacterConverter::pop_utf8() { + if (isComplete()) + 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->total_bytes - state->bytes_processed - 1) * ENCODED_BITS_PER_UTF8; + if (state->bytes_processed == 0) { + /* + 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_processed++; + 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 0000000000000..c4ba7cf6b689f --- /dev/null +++ b/libc/src/__support/wchar/character_converter.h @@ -0,0 +1,41 @@ +//===-- 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 isComplete(); + + 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/mbstate.h b/libc/src/__support/wchar/mbstate.h new file mode 100644 index 0000000000000..fb08fb4eaa188 --- /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; + + /* + Progress towards a conversion + For utf8 -> utf32, increases with each CharacterConverter::push(utf8_byte) + For utf32 -> utf8, increases with each CharacterConverter::pop_utf8() + */ + uint8_t bytes_processed; + + // Total number of bytes that will be needed to represent this character + uint8_t total_bytes; +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MBSTATE_H diff --git a/libc/src/dirent/closedir.cpp b/libc/src/dirent/closedir.cpp index 1249ef94cf411..2f8f6f0c044db 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 fee14ef0f558d..bf47d0edac180 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 ad460b5e80b8b..f95f7c1ae8646 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 1d78a5eedff96..2852044e94164 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 d1600d1b050e3..8ff1eec1b1035 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 44ee2714843ba..0000000000000 --- 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 580db16cd4132..c31eb3f438c10 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 23abae243aed9..71412a8e68c53 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 a0c8459ced342..fd9c48eb562f7 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 8b699ecdd2043..3a56d10554198 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 6063d9c00ad6c..b47ad1fb3bb0f 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 85f197c75d90c..6e55a4b56aac7 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 2e9cbc9acba75..ce5a0a782d979 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 db3ef8886b52b..fd1e6c0d648aa 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 e973b2921c2e4..27729104e038d 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 4913a5e4277e4..127c6eaa494d4 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 fa507d4d9322c..de11f51ac64a0 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/nan.cpp b/libc/src/math/generic/nan.cpp index f92cd3ff5eb50..829a2ea435ac0 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 7287182406acd..1cb66160e736e 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 3d8581afa0371..4155c5333a9c2 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 27d9d165f4a85..7b166400601bc 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 4f698cb3c88d0..58d638c4b531d 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 f82fcbcc6577c..4cac75b9687c8 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 b2c67c78e5d94..4cad16a02de70 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 872f694e01f3a..c482d25610c28 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 fa4375e915ab4..c996210a61d8a 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 1154055a63a7e..767f959b14003 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 0a5d1af661abf..38c77ca761d69 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 5e825d5ecea69..2f63d5e9d1942 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 433b2dc1d2d93..9c117499a5592 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 e1b1f3b325d1c..45be2807fa832 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 383762f273e7a..7253de14cc0d5 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 b54db821ab05a..2b14d874fe31c 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 deeae15be2303..a87a08259c4bb 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 9fd46f4c928d7..fd7a8d7ce1d17 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 c7e78271f9c38..5a65f031045d6 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 112ff5c9cdad3..fcddfed224906 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 a63dc893e7169..660c15a87b36c 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 e61290179bd62..5496bea929c51 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 80d34a35c717a..e6800311b8587 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 5a7191aefd3d0..4fbd095ac2b46 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 70c29c1670841..b147a66d2fad7 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 77a82c77405f3..fb30b1e319e7b 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 fca66a15edb55..54f67e915fc17 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 7b1fd8c5aa2af..e005819e2a978 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 75756a65f0ede..b0576c3ac65b8 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 545cda8e7484b..d8e02967a633d 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 1f0ef69dfc893..5668d596bce1f 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 cad48c26bf938..93e930dcf2e3e 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 e78e78a707e05..7875d9e2f19bc 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 b6b6f667b3f9e..232e5a59b1858 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 3de9d0ba35717..c1e9168f34d0e 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 ac816a902e221..68bdb29e51dfb 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 17acd808c19a6..c89be803b4e16 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 7eff5bb6fff9d..ba5476098be29 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 c18b5d3d7f547..034333d170579 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 f93e608a190b1..323001e1b103d 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/signal/linux/kill.cpp b/libc/src/signal/linux/kill.cpp index ed117858f51ef..0f5e88757acb8 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 65ec36741683c..43a3e195474e5 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 628883e13b887..2091e8b51453f 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 c19394cd17912..990b841c6d904 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 2e964051ebde7..6fce0d7a6e147 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 d347477695e6c..034a9e2cbe15e 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 3e9897a03bb73..f0b499093b319 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 8838379ae5d30..af3c424c5f34e 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 bb8504f655c4a..9a575bd591632 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 710063d52e74d..1ad45ed942bb9 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 028d6e895f3c4..9977fc2d0a218 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 168118da249d1..affd338005cf4 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 63f6ed8a11f1d..b0a6ef1e291b5 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 c94698ec02953..7253c6549a4e4 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 0ba46a5ade6c9..ac21e6e783b01 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 5062efda1c0dc..fcd3aa086b2bf 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 3e8631abd90d9..ab02533f14911 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 9f5694e8e0581..da8a132a4db6e 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 e1f4ed5c19497..6361822b61999 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 388407a58d414..902b4cf972373 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 5bdf71ad35940..d0271d9154c87 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 aa6660ca180cf..e65ce2fda49bd 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 34a27f1d1c420..5c07d4feb513e 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 de6474087a140..e0ad9b6e2f564 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 d6e418bacf37e..57c85c2e54e16 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 54a38aeb2f1e2..6639f0687c87a 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 8aef7683b3ce3..621b40f63c912 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 3a04094ea8b4b..1b576ec34688f 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 151f43c6bbeba..257f1a212add4 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 21820da18542a..99191e7c41949 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 7456b4a219079..afcfc71c7c09a 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 ec15ca4e96caf..b55a806007aff 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 e3d0726ec4843..91031cb7fad70 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 66eb9a3c71855..b44ecb2838118 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 a0d9014cd68de..2f9ec26f2f80c 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 e988468898c53..0ac010ebc5994 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 92d5092623ac5..eee23a18d05df 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 371fc70eb214f..87d24a2b1f09e 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 b898f5cb25963..f321969483e35 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 0000000000000..68b4ad644caab --- /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 b5f008fdce44a..83bc3d4131e76 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 e86df23d6716b..2b3509e5e414c 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 7dbe2c79f920d..4267dd546c4dc 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 5b8f01d7d5346..9877817d92099 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 53fe69d5e2ebe..8a9174d7397ae 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 7d72fdc88e9fb..5623f06b7cff0 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 dbb4491d0e6cc..ac755db0bc781 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 fbcb29be48f4e..426c8698e557d 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 0000000000000..bf8d0af1df5d7 --- /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 89556f1a9e5f2..cef9b1ae58fa0 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 f3db97de58371..fcc6df12ddb08 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 0a6b8cacb59c8..9fc6cb040233b 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 18a65c67705d3..d0d8d211dea8c 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 9e46b53b1aa0b..420bbc8143d55 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 7f3414a4afdd2..e1110ffa449b0 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 4f1a02ad8315b..063e817f9b790 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 2c6819163aa46..deb2390c7fcde 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 247314398315b..ad333b32d2406 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 351bf64ad4f70..fc52dc85ffc50 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 d54efa66e0846..c6e03ff51fa2f 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 77f8712d7c136..42db36b2052b4 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 f94aff1a0d7b2..497a4403eff4b 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 88d29c9f36278..44046c2c6f613 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 d0c57f50246b5..c3af30a1b9ecc 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 8d1b3efdcf87d..c1dca13112e0f 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 e82971d59c48d..6f30d7794c5ca 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 1d832318c4489..d26ca5e5a10a1 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 74fce00a0ac3c..9a875ddee9029 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 dba22611cfb09..8f929f577311e 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 2ea8a43a40ef2..9eb056b0e59b4 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 c3b414d872858..8784bc3750cb1 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 979edd72c1f1d..48c0db950ace0 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 6a6f068bd4759..7dce6d15a65c1 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 4cf4173a27bf3..dab0ab4288c9e 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 dcbfc7584a30e..4f56263fce8ec 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 4926b7d244d12..6d8bb69607486 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 9a73b80d35d2f..0fa11e9eee696 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 236fd25698f65..b50c5845bcc2b 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 @@ class AuxvMMapGuard { 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 @@ class AuxvMMapGuard { 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 7196ac7410c30..2e44e883ddf0a 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 efff282e2714d..3c60090fb7b41 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 5f7dbb77b1e5b..079bd60403b09 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 d7836549928c4..24fd1dbdc467d 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 14b419399fe9b..219984528efdd 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 1a63be5e260fb..7fae7b55992fa 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 0000000000000..099a1b96389fc --- /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 0000000000000..62323ba7dd4dc --- /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 0000000000000..876f35aaee66c --- /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 0000000000000..9bb669c6a6f66 --- /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 332d6c2db4acb..1bb284f62b892 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 b5436fda3853a..d583f1ef85f3d 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 be7eb28e29c4f..8582eb7c00632 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 7bc557f9bf58f..955cfe128de74 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 eae3a9ea0a183..c3502fbb3af39 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 ee9a0a32e8f55..33f9fe8ff3709 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 e2351028e2c7f..6b14915b60c94 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 38bcfce833d3d..6cdda9435bb69 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 e2b4f81d616ad..650678bcb36e0 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 93c25f844c6e8..9638949f5fcb3 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 f5911cb01bc28..f47eaece178e3 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 9c01b15ac8dc2..61b1f1549dd18 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 f616e1915ecc5..58ae4017f6285 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 ce75c2b5b6991..29d1401821e49 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 11de482272d00..3099062eace98 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 6a76301512201..4c61c7cd16bad 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 5d4e9046b8777..c726b0a539591 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 9a8869a2d6d38..0b8471ed8b374 100644 --- a/libc/src/sys/random/linux/getrandom.cpp +++ b/libc/src/sys/random/linux/getrandom.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/resource/linux/getrlimit.cpp b/libc/src/sys/resource/linux/getrlimit.cpp index 30c2e91b036d1..d272134194949 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 85f07900aaef4..300bad75baa63 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 9ccb1e95f275c..6c434eb584596 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 9d4174cb8c916..ec892323def50 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 72a3307a91ddd..83a3d06f5380b 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 5e9f2d3233fcf..baf4de1b5eb54 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 574e65f64a54b..3d8397b478cc4 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 e42b6346f330a..bc6d072dbf9a1 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 cb3b4d5a9ece7..43b01e7e6e0f6 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 b4d9c9deda028..b04783ebfe7e7 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 2fada192b0865..9dda127f872d5 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 3e6df4d487a53..69eb6cfa01ced 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 60612ac04d613..7ea8ca46cee58 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 1b787e47e7c68..2bd0788ec1dfd 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 0d6fd359169aa..3dadfdd1d943c 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 e76db4d160fb8..add2192a558a4 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 35cf8f08f782d..dea002c5e12a5 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 354c5b6e029a4..5601dd5d78a98 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 b319b5c8393de..0829ff4f94322 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 097fc158010d1..8f4194dc32752 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 de9cdb197d687..5553eaf00be2a 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 1e5be51531012..8ee4de288ef61 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 fec06aa4086e9..b874066796940 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 def04a4740118..1de0d43297760 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 76b69937a5f48..ed37b42aedf6c 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 f1393a9749be9..c9d8d87ddc72b 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 8992bed95c982..b0b9e15207922 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 7bb227e801e3a..b47ba964faf0b 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 f2bdeb02f8668..77ed3ad22f148 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 9656b714a8ed2..47b19974d21be 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 6130d266dbff0..d2f138257a47a 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 116e3f0e0cbc5..570b15c24fe7f 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 d229230b5d138..714ef6aa71298 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 028a5414b1960..4c7b9fadc446d 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 63c096ff88eba..2e768269c874d 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 c283d0e4fda9a..7487816cf2741 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 30bc91cf3de0a..1d546c1d5953e 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 8aa1e5c57b34e..8a2c7290217ba 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 4680944c2eee0..67e22e72fd0e4 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 ee4fa82b4f894..c38697cd0668e 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 743c644d65d02..b3fcd2b22f9da 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 e8ddf482fc984..237b05903c70f 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 7a856376ffb20..6b9704126a0a5 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 cf5174523aa4f..a4d4372332732 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 860909af7488c..2a81f0182c313 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 bbbb1c08a4759..0541c24ece82b 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 b8c0c82aa6419..969bb66be2d25 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 2f7ebbcdf9e81..55cd6adca779d 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 a30d1dc883be8..04ba509b49a56 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 58d42a9673fbe..6ef3a3c6d63f0 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 c1710a37f6119..81d30c6cdbc4c 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 7ffc151a053c9..0a0e86573b34e 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 c096ba73c96bd..770fb73515b21 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 a3f2525ed7ca1..d4f2bd9a51653 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 37162c4121782..2214b6df493bd 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 8196dc63ab1e1..f7a7422363e6e 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 8aa0477a15d58..75a76fdea50b2 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 ae3895bab15f3..fe08aed61e250 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 ccbb0634664aa..f6aa6f8b48cc9 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 1bb11a7c8e7ba..c0e475dd3e8ff 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 168a1197734ed..65bcbf27601da 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 5977c5bf10e94..025b8d1691ac3 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 e6ea22a714c78..a4d17912b57b0 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 477806a70df74..205cf8a84a5cb 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 40f68cc90c480..ea5bc48cbedc5 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 0e957498da746..26a08269fd8de 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 ca1c10bb9f7f6..7dde857c1cfd8 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 035e628dff253..9a62e31fd1880 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 dfcd5bfdaf537..b9943c8338056 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 ebe7e0114ae99..d30f3b37a1adc 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 3e27857f9a2b4..2f86e397feeff 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 1b81b2a059494..f4cf8e16d766f 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 4419900f2330e..55676f3f7010a 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 2055e6b3400f2..b297a41ca37bd 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 e5e4d0d39bc9c..cd0dcb8e0ff02 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 075af12af64c5..eca6e954ef898 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 9e1b2886ea0f5..3f43de19d2f46 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 bcf2d0f8cc055..8cee172f39dfa 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 5394bff46adfa..0f7b3da88d627 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 f785ff321c7d7..03f224b150273 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 8236edb480d10..6103d4b51350b 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 72d8e2398e3d7..5fde2600937b2 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 4ed20f542f170..b2012c52b8854 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 99d5ab7e480b0..eecb74429182a 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 bfaec723ac63d..e25a7a8fed406 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 759f708c2247a..491dd5b34340a 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -43,7 +43,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 +53,6 @@ add_entrypoint_object( wcschr.h DEPENDS libc.hdr.wchar_macros - libc.src.__support.wctype_utils ) add_entrypoint_object( @@ -75,7 +73,6 @@ add_entrypoint_object( wcspbrk.h DEPENDS libc.hdr.wchar_macros - libc.src.__support.wctype_utils libc.src.__support.macros.null_check ) @@ -109,7 +106,6 @@ add_entrypoint_object( DEPENDS libc.hdr.wchar_macros libc.hdr.types.size_t - libc.src.__support.wctype_utils ) add_entrypoint_object( @@ -121,7 +117,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 +129,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 +211,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 +222,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/wcscpy.cpp b/libc/src/wchar/wcscpy.cpp index dc46b972c59f7..01ba994cecbb2 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 e7ae9a4a0da79..7ad6730cd776b 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 56708d6cee496..bf92309b20944 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 0000000000000..3282077003bd7 --- /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 0000000000000..b4c31ac7b397c --- /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 d8b89c0a88d05..21e16210a757a 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 5be66d9edff02..24c007d2e12e6 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 b0a3a7431c222..c32809da577d4 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 3d3b72f80544f..4b7ff452f409c 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 c6eadd25858ea..212b7a8f83e74 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 @@ template class ErrnoSetterMatcher : public Matcher { 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 21b8a45b0726f..da15cf2907f7c 100644 --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -279,8 +279,8 @@ struct ModifyMXCSR { #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 @@ struct ModifyMXCSR { #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 95d48f40914ed..a5a2a3c7cf58e 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 29da4d5c3c8d7..aecbad6514aaa 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 994fa57a6b337..5d0bcd8e23658 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 37ceceee880de..35dd3b165e0ee 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 551768187bf01..1b321b01e9315 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 ef9fd9fcb7ff4..de3bd06c39cf6 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/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index c1736c8fe59e2..9f626ed31cc07 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 a579bfabb2d7b..ba9849b6b5af9 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 ccfa44f12d8ef..dc503aa16f08c 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 66f7db742eb45..03ae80fc2ee38 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 c7bc57b845fe0..9b4844d410db2 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 34b645b4b38c8..40cb76a8bd6a2 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 0000000000000..5176bfd4b024b --- /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 0000000000000..f4c5cb863ff38 --- /dev/null +++ b/libc/test/src/__support/wchar/utf32_to_8_test.cpp @@ -0,0 +1,180 @@ +//===-- 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); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 'A'); + ASSERT_TRUE(cr.isComplete()); + + char32_t utf32_B = 0x42; // 'B' + cr.push(utf32_B); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 'B'); + ASSERT_TRUE(cr.isComplete()); + + // 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); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xc3); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xbf); + ASSERT_TRUE(cr.isComplete()); + + // testing utf32: 0x58e -> utf8: 0xd6 0x8e + utf32 = 0x58e; + cr.push(utf32); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xd6); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x8e); + ASSERT_TRUE(cr.isComplete()); + + // 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); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xea); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xb0); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x95); + ASSERT_TRUE(cr.isComplete()); + + // testing utf32: 0x267b -> utf8: 0xe2 0x99 0xbb + utf32 = 0x267b; + cr.push(utf32); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xe2); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x99); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xbb); + ASSERT_TRUE(cr.isComplete()); + + // 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); + auto popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xf0); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x9f); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa4); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa1); + ASSERT_TRUE(cr.isComplete()); + + // testing utf32: 0x12121 -> utf8: 0xf0 0x92 0x84 0xa1 + utf32 = 0x12121; + cr.push(utf32); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xf0); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x92); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0x84); + ASSERT_TRUE(!cr.isComplete()); + popped = cr.pop_utf8(); + ASSERT_TRUE(popped.has_value()); + ASSERT_EQ(static_cast(popped.value()), 0xa1); + ASSERT_TRUE(cr.isComplete()); + + // 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 0000000000000..9cb059faa9374 --- /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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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_processed = 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 41f522a6a75fb..3f0095ca5ebe8 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 b0db22a85f3bc..de82b0077f177 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 4c9d2cbc33f47..d60c984934703 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 1a21afe51085b..082c42481777b 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 213b074799c8d..1997476f16a60 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 77b465a3a0e63..6af9cfea0e0a5 100644 --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -55,7 +55,7 @@ class RoundToIntegerTestTemplate 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 2e4c8eb2ab961..aa0128fee999b 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 7348018396bd7..2eb95215e4e8b 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 18ed5a11d50a7..3d3b827411a4a 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 385e341318aea..03ae963e9f924 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 5197810d8bd58..1eaa6b8a51359 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 ac125c3520c44..8c78f939cabf7 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 331f4281af839..50ab38208089a 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 7f52578b9efed..7fa0dffd607e2 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 575ec89bd493c..a4bdf1867c39c 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 8b9db1dfdd976..32272ef482ab2 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 2143c36f3d30b..90dc8ff6a0ea4 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 0d1c322b8e622..bdaba50f1f148 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 37ec2516f6a35..cb88bfcade0dc 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 6fb1d2d9d925e..6126e5f211fff 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 001b37809d930..89915961c9b90 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 aee273384f1a2..01802bd68f7e4 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 adfceceeef4b7..4cd95dd5486ed 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 0c4c821534392..aeecb3e74b07a 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 793cf0cc2cbb4..0c87657abc085 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 0ab3a4e543464..83addaeb943d8 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 26a0bca4ce253..3c10812ff5bc2 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 9720773d9f960..0cf07e2e49734 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 274fe3bb7afb0..cf3fe9c26ae18 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 01aa1f82ae5d8..e9529d87c3885 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 107e965a0d3ae..e5747b7e5ec0b 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 bb181dc5e43b0..ffe2dd2c33dd6 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 8a07991a68886..fc440c09b42bd 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 83691fb75300e..92226c763f458 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 969a469b2e1c6..54afaa33d1350 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 448dcc0035e9b..4d189d813e584 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 d4c6bd416a409..4d5d9ddf464b1 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 2823110331f30..ad2155f329cd9 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 8fd3ed1577cee..e0357e6157fdc 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 6867c7aec57df..74f906ebaa983 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 d00fd77d288c6..986c676761f0e 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 8fbcc2a276542..04cbc659ece5d 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 6ae97ce35a0d6..745ccbc748ecd 100644 --- a/libc/test/src/math/smoke/RoundToIntegerTest.h +++ b/libc/test/src/math/smoke/RoundToIntegerTest.h @@ -40,7 +40,7 @@ class RoundToIntegerTestTemplate 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 3a59bce264077..fe2caefb52ab8 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 c4274b8245092..7103dc33fec3a 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 74f68e00011aa..257c6a3d1d22c 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 7681c2a4e7fbc..6b9c995cf9921 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 c5ba88055ac57..b6abfab999293 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 66b94706eab94..4b2f6de3f7e37 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 9f675b08319c0..b03f0a420a499 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 d817d2b366192..2615a8ddd16bd 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 dcaab217331c7..7f612ce3c4674 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 4a8743c50075f..d812a2dffe8aa 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 1fbcfbe96b2d7..7f8cfb9830d2a 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 af50287d9b22a..ba1e3b2fc8bef 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 7d09a28beaa38..b56b9d0162b97 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 81df6da8cee26..c2a520f7638fe 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 73a5b81b0240b..038cb30d89a4e 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 2638551fb1d1b..4362a5a3a4bd1 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 99773583dcb10..470a876c63a75 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 08d05ecce86ba..7bf62afa24c43 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 1611ea1b92926..ee8f0199df3b0 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 edd8ed97b30f6..fcde0cc79e356 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 20153897dc459..3d48909cca93e 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 baf8a76810970..50d3de0c7fe75 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 1c4ef2aa08a70..bda40348f8832 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 bf39e2cc12d0c..fcd334bb9e364 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 dfa7fa477d3d1..ed2d5a48b3165 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 2c2cfdbb08a3f..19369a897aaa9 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 9ab9129416dad..aebf808350727 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 f69b33a3cf37f..1eb7343dcd22f 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 a928389cc41b4..c5243273d9ed4 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 f423196a70360..635b7a6e187d7 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 99bdf0035df0c..63852e11655ad 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 f86243092f1fb..c3b2ae70e1d99 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 ab745a3cf6f56..863f694ffc41a 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 eee8304999275..d34151735afa7 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 bc71c53abc7ac..c842fe3c45fe1 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 f297c5dfc3c7e..4d19a9bac5eb1 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 dfb474d70fb6a..214bfe8abd4d2 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 ff73850c52101..49cfda85111a5 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 471e198933326..53f5ac46aa60f 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 631c24b8abcf9..61c56cd2c6ddd 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 bd828ad58c4c9..dc3489fddf99f 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 9993d442967cb..0534d00b1f408 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 6d98482aa4499..fd20652d2f008 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 8648b75b88b83..53d54ac367639 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 d31eb0c1db734..09e9ab0a9a4d8 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 c7232aa1c1e32..2784f3d5fa54d 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 5f66868f12a1c..8ba0d04347bba 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 a0e7a7ba321fd..6b168ac040db9 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 de504b4f5335c..8173969fb2569 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 4f21d33ba78e0..d52739a9adb35 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 e22cfc7ea14d8..ea6a4474a7806 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 b2db6fb9f8626..9edf2cc663d4b 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 1ba5c1d2b720a..b840f3980eda2 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 f65b9fced72c4..95d200cf5591d 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 178e9065f430f..12deca5cf9417 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 fa6328e9ef0a6..eb90f02a8d7c3 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 c09761ef531f2..b12a331b31906 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 74797d1649b1a..ea896d7bb3e57 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 9061cf6fb30b8..ecc70194b6491 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 389abe4d85897..966ce649e2b38 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 30f5e41c61ecf..97b7b02718172 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 b5085203e5ce0..b77f22f8e60d2 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 5250368a26162..919f1475e1d4d 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 59205c51e4a16..bb41dc0be2019 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 747c7e3409e41..4f2b6e412a4b7 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 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { // 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 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { 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 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { 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 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { // 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 @@ class SchedTest : public LIBC_NAMESPACE::testing::Test { // 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 c22a2c76d743c..a0fe5edbe014e 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 f1627a71fa9ad..4d13d50e25eb2 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 cc392da8f4731..ce4dfddae2481 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 bac9c3b8b68bb..62b86bf440291 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 12403f68b5930..891eac0f5bf75 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 c1edf56bdbd87..01ccb8218ee20 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 01904a30504ed..4aa8b95880018 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 ef36cff2ffbd5..b53184c30be36 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 2cc8436bd66f2..be2e50271b510 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 @@ class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::Test { 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 46cf12c2c253b..bef9dafd3d87c 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 @@ class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::Test { 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 a8a2c62f07b5e..8fc38b0659181 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 a0368d701a676..e097785832d56 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 61ce2a207fa19..bcf5e674141a7 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 0000000000000..9a97be2eff210 --- /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 96a00ae598ec2..bf088937e4104 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 72875600903a6..296bff1f5dc15 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 a5dd734c63616..135fb98c07fbb 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 a1e1fee25db31..a0936ba79ef73 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 f6af6ad3e364b..f1b545ba546f9 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 67f1b0ff513bc..e99b382d12112 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 302971a078c17..45fd49b6d3526 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 ed302f14d03ef..03f0a6539c785 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 1e4259b792d7e..92b904ecad94e 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 92d14640e6533..db3c1d73bd22e 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 @@ class LlvmLibcStrToDTest : public LIBC_NAMESPACE::testing::Test, 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 6a716c956291c..6df1ddda93bfa 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 @@ class LlvmLibcStrToFTest : public LIBC_NAMESPACE::testing::Test, 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 17df432fc8e68..e6da692714d28 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 b5fe69dfaa701..2c5d948f5fae2 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 b209c85b88e36..eb4056dc7ba64 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 @@ class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::Test { 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 a675373938e99..ced60750a45c7 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 20b85c37637dd..4b18fc7f1bdee 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 224cc7905ad31..13bf91eef04be 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 0000000000000..b4bbe81c92ff2 --- /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 0000000000000..2df67e9d9cbde --- /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 0000000000000..b76dc14824c95 --- /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 88abacad554e0..6b81411ca604a 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/prctl/linux/CMakeLists.txt b/libc/test/src/sys/prctl/linux/CMakeLists.txt index b06e1c8087008..d02900e1857a0 100644 --- a/libc/test/src/sys/prctl/linux/CMakeLists.txt +++ b/libc/test/src/sys/prctl/linux/CMakeLists.txt @@ -1,5 +1,10 @@ add_custom_target(libc_sys_prctl_unittests) +# Temporarily disable this test while setting up arm and riscv buildbots +# using qemu, since PR_GET_THP_DISABLE is not supported on qemu. +if (NOT (LIBC_TARGET_ARCHITECTURE_IS_ARM OR + LIBC_TARGET_ARCHITECTURE_IS_RISCV32 OR + LIBC_TARGET_ARCHITECTURE_IS_RISCV64)) add_libc_unittest( prctl_test SUITE @@ -13,3 +18,4 @@ add_libc_unittest( libc.test.UnitTest.ErrnoCheckingTest libc.test.UnitTest.ErrnoSetterMatcher ) +endif() diff --git a/libc/test/src/sys/prctl/linux/prctl_test.cpp b/libc/test/src/sys/prctl/linux/prctl_test.cpp index 374c905e0ef8a..76b829c82d1be 100644 --- a/libc/test/src/sys/prctl/linux/prctl_test.cpp +++ b/libc/test/src/sys/prctl/linux/prctl_test.cpp @@ -34,6 +34,7 @@ TEST_F(LlvmLibcSysPrctlTest, GetSetName) { TEST_F(LlvmLibcSysPrctlTest, GetTHPDisable) { // Manually check errno since the return value logic here is not // covered in ErrnoSetterMatcher. + // Note that PR_GET_THP_DISABLE is not supported by QEMU. int ret = LIBC_NAMESPACE::prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0); ASSERT_ERRNO_SUCCESS(); // PR_GET_THP_DISABLE return (as the function result) the current diff --git a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp index 455a82678e18f..ba0ee4f09109e 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 f356bb3d277b6..327dec07a1b79 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 16d33fdf1e4f9..115f9e662ed46 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 f8fc09a8bbf0e..5ec169a886b1e 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 b595cfe024866..d840248b7df42 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 169a7463a3037..cad25fffc65af 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 27011b7e0fbd6..fe43877aa499d 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 6f1168f0b6685..5ff69f6619b4f 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 6af5a18d36996..41236665d2eaa 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 d4f98e29bd980..e0200ff3aaa26 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 6293e8e3d55cf..4990b6953348b 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -145,6 +145,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/wmemmove_test.cpp b/libc/test/src/wchar/wmemmove_test.cpp new file mode 100644 index 0000000000000..d23aa0f0b3af1 --- /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 298518781e9b7..1a04b7fbb217d 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 c25aaa8e42330..e6ac4f2b5b230 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. @@ -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 a89d4038785cd..3e6fd643f620c 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -420,6 +420,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_constexpr_algorithms`` ``202306L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_forward_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 6cbc0baf29487..2a5b90750eafc 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -99,6 +99,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/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 3809446a57896..8a0417e120d75 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","" "","","","","","" diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index 9c957e9d20cb7..ae9cc87c797f8 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 52611e43968bc..8931a1b35f6d3 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -800,6 +800,7 @@ set(files __type_traits/extent.h __type_traits/has_unique_object_representation.h __type_traits/has_virtual_destructor.h + __type_traits/integer_traits.h __type_traits/integral_constant.h __type_traits/invoke.h __type_traits/is_abstract.h @@ -850,7 +851,6 @@ set(files __type_traits/is_same.h __type_traits/is_scalar.h __type_traits/is_signed.h - __type_traits/is_signed_integer.h __type_traits/is_specialization.h __type_traits/is_standard_layout.h __type_traits/is_swappable.h @@ -864,7 +864,6 @@ set(files __type_traits/is_unbounded_array.h __type_traits/is_union.h __type_traits/is_unsigned.h - __type_traits/is_unsigned_integer.h __type_traits/is_valid_expansion.h __type_traits/is_void.h __type_traits/is_volatile.h diff --git a/libcxx/include/__bit/bit_ceil.h b/libcxx/include/__bit/bit_ceil.h index cfd792dc2e2ad..99881a8538290 100644 --- a/libcxx/include/__bit/bit_ceil.h +++ b/libcxx/include/__bit/bit_ceil.h @@ -11,8 +11,8 @@ #include <__assert> #include <__bit/countl.h> -#include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/integer_traits.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -41,7 +41,7 @@ template # if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_ceil(_Tp __t) noexcept { return std::__bit_ceil(__t); } diff --git a/libcxx/include/__bit/bit_floor.h b/libcxx/include/__bit/bit_floor.h index 6bcbc53fb4972..799a064130b4b 100644 --- a/libcxx/include/__bit/bit_floor.h +++ b/libcxx/include/__bit/bit_floor.h @@ -10,8 +10,8 @@ #define _LIBCPP___BIT_BIT_FLOOR_H #include <__bit/bit_log2.h> -#include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/integer_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_floor(_Tp __t) noexcept { return __t == 0 ? 0 : _Tp{1} << std::__bit_log2(__t); } diff --git a/libcxx/include/__bit/bit_log2.h b/libcxx/include/__bit/bit_log2.h index b22e1ce1f84e6..8077cd91d6fd7 100644 --- a/libcxx/include/__bit/bit_log2.h +++ b/libcxx/include/__bit/bit_log2.h @@ -11,7 +11,7 @@ #include <__bit/countl.h> #include <__config> -#include <__type_traits/is_unsigned_integer.h> +#include <__type_traits/integer_traits.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __bit_log2(_Tp __t) _NOEXCEPT { - static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__bit_log2 requires an unsigned integer type"); + static_assert(__is_unsigned_integer_v<_Tp>, "__bit_log2 requires an unsigned integer type"); return numeric_limits<_Tp>::digits - 1 - std::__countl_zero(__t); } diff --git a/libcxx/include/__bit/bit_width.h b/libcxx/include/__bit/bit_width.h index 853e481776f7d..75050acabbe88 100644 --- a/libcxx/include/__bit/bit_width.h +++ b/libcxx/include/__bit/bit_width.h @@ -10,8 +10,8 @@ #define _LIBCPP___BIT_BIT_WIDTH_H #include <__bit/bit_log2.h> -#include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/integer_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int bit_width(_Tp __t) noexcept { return __t == 0 ? 0 : std::__bit_log2(__t) + 1; } diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h index 9499bf9b458ee..075914020879a 100644 --- a/libcxx/include/__bit/countl.h +++ b/libcxx/include/__bit/countl.h @@ -9,9 +9,8 @@ #ifndef _LIBCPP___BIT_COUNTL_H #define _LIBCPP___BIT_COUNTL_H -#include <__concepts/arithmetic.h> #include <__config> -#include <__type_traits/is_unsigned_integer.h> +#include <__type_traits/integer_traits.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -25,18 +24,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT { - static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type"); + static_assert(__is_unsigned_integer_v<_Tp>, "__countl_zero requires an unsigned integer type"); return __builtin_clzg(__t, numeric_limits<_Tp>::digits); } #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countl_zero(_Tp __t) noexcept { return std::__countl_zero(__t); } -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countl_one(_Tp __t) noexcept { return __t != numeric_limits<_Tp>::max() ? std::countl_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; } diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 7b311b83853c5..f6c98695d3d06 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -9,9 +9,8 @@ #ifndef _LIBCPP___BIT_COUNTR_H #define _LIBCPP___BIT_COUNTR_H -#include <__concepts/arithmetic.h> #include <__config> -#include <__type_traits/is_unsigned.h> +#include <__type_traits/integer_traits.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -25,18 +24,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { - static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); + static_assert(__is_unsigned_integer_v<_Tp>, "__countr_zero only works with unsigned types"); return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); } #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { return std::__countr_zero(__t); } -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; } diff --git a/libcxx/include/__bit/has_single_bit.h b/libcxx/include/__bit/has_single_bit.h index 52f5853a1bc8a..b43e69323e77b 100644 --- a/libcxx/include/__bit/has_single_bit.h +++ b/libcxx/include/__bit/has_single_bit.h @@ -9,8 +9,8 @@ #ifndef _LIBCPP___BIT_HAS_SINGLE_BIT_H #define _LIBCPP___BIT_HAS_SINGLE_BIT_H -#include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/integer_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,7 +23,7 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_single_bit(_Tp __t) noexcept { return __t != 0 && (((__t & (__t - 1)) == 0)); } diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 9ae572d466ba7..8d9ba09938482 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -9,9 +9,8 @@ #ifndef _LIBCPP___BIT_POPCOUNT_H #define _LIBCPP___BIT_POPCOUNT_H -#include <__concepts/arithmetic.h> #include <__config> -#include <__type_traits/is_unsigned.h> +#include <__type_traits/integer_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -24,13 +23,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { - static_assert(is_unsigned<_Tp>::value, "__popcount only works with unsigned types"); + static_assert(__is_unsigned_integer_v<_Tp>, "__popcount only works with unsigned types"); return __builtin_popcountg(__t); } #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { return std::__popcount(__t); } diff --git a/libcxx/include/__bit/rotate.h b/libcxx/include/__bit/rotate.h index d79d98de296aa..c6f34bdaf6e63 100644 --- a/libcxx/include/__bit/rotate.h +++ b/libcxx/include/__bit/rotate.h @@ -9,9 +9,8 @@ #ifndef _LIBCPP___BIT_ROTATE_H #define _LIBCPP___BIT_ROTATE_H -#include <__concepts/arithmetic.h> #include <__config> -#include <__type_traits/is_unsigned_integer.h> +#include <__type_traits/integer_traits.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -25,7 +24,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD // the rotr function becomes the ROR instruction. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) _NOEXCEPT { - static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotl requires an unsigned integer type"); + static_assert(__is_unsigned_integer_v<_Tp>, "__rotl requires an unsigned integer type"); const int __n = numeric_limits<_Tp>::digits; int __r = __s % __n; @@ -40,7 +39,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) _NOEXCEPT { - static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type"); + static_assert(__is_unsigned_integer_v<_Tp>, "__rotr requires an unsigned integer type"); const int __n = numeric_limits<_Tp>::digits; int __r = __s % __n; @@ -55,12 +54,12 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) #if _LIBCPP_STD_VER >= 20 -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, int __cnt) noexcept { return std::__rotl(__t, __cnt); } -template <__libcpp_unsigned_integer _Tp> +template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, int __cnt) noexcept { return std::__rotr(__t, __cnt); } diff --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h index 6b866b882f89a..fc4408d23dbf1 100644 --- a/libcxx/include/__chrono/time_point.h +++ b/libcxx/include/__chrono/time_point.h @@ -58,6 +58,19 @@ class time_point { // arithmetic +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr time_point& operator++() { + ++__d_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr time_point operator++(int) { return time_point{__d_++}; } + _LIBCPP_HIDE_FROM_ABI constexpr time_point& operator--() { + --__d_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr time_point operator--(int) { return time_point{__d_--}; } +#endif // _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 time_point& operator+=(const duration& __d) { __d_ += __d; return *this; diff --git a/libcxx/include/__concepts/arithmetic.h b/libcxx/include/__concepts/arithmetic.h index 0c44f117805f3..64c0200783df7 100644 --- a/libcxx/include/__concepts/arithmetic.h +++ b/libcxx/include/__concepts/arithmetic.h @@ -13,8 +13,6 @@ #include <__type_traits/is_floating_point.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_signed.h> -#include <__type_traits/is_signed_integer.h> -#include <__type_traits/is_unsigned_integer.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -38,17 +36,6 @@ concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>; template concept floating_point = is_floating_point_v<_Tp>; -// Concept helpers for the internal type traits for the fundamental types. - -template -concept __libcpp_unsigned_integer = __libcpp_is_unsigned_integer<_Tp>::value; - -template -concept __libcpp_signed_integer = __libcpp_is_signed_integer<_Tp>::value; - -template -concept __libcpp_integer = __libcpp_unsigned_integer<_Tp> || __libcpp_signed_integer<_Tp>; - #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__config b/libcxx/include/__config index 38c47e8d45c81..af8a297fdf3fd 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/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h index 87557aa4da7bb..fbb4cad21b232 100644 --- a/libcxx/include/__format/format_arg_store.h +++ b/libcxx/include/__format/format_arg_store.h @@ -14,7 +14,6 @@ # pragma GCC system_header #endif -#include <__concepts/arithmetic.h> #include <__concepts/same_as.h> #include <__config> #include <__cstddef/size_t.h> @@ -22,6 +21,7 @@ #include <__format/format_arg.h> #include <__type_traits/conditional.h> #include <__type_traits/extent.h> +#include <__type_traits/integer_traits.h> #include <__type_traits/remove_const.h> #include #include @@ -65,7 +65,7 @@ consteval __arg_t __determine_arg_t() { # endif // Signed integers -template +template consteval __arg_t __determine_arg_t() { if constexpr (sizeof(_Tp) <= sizeof(int)) return __arg_t::__int; @@ -80,7 +80,7 @@ consteval __arg_t __determine_arg_t() { } // Unsigned integers -template +template consteval __arg_t __determine_arg_t() { if constexpr (sizeof(_Tp) <= sizeof(unsigned)) return __arg_t::__unsigned; diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h index 733f321925a43..e71c778386fd2 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,71 +125,9 @@ _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_; @@ -215,20 +145,9 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> { 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 __default_alloc_func* __clone() const { return new __default_alloc_func(__f_); } _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. @@ -257,84 +176,38 @@ class __base<_Rp(_ArgTypes...)> { // __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(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {} + _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, _Alloc&& __a) : __f_(__f, std::move(__a)) {} + _LIBCPP_HIDE_FROM_ABI_VIRTUAL __base<_Rp(_ArgTypes...)>* __clone() const override { return new __func(__func_); } - _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f, _Alloc&& __a) : __f_(std::move(__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_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 +227,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; @@ -544,7 +407,7 @@ struct __policy { 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 @@ -583,7 +446,7 @@ struct __policy { template using __fast_forward _LIBCPP_NODEBUG = __conditional_t::value, _Tp, _Tp&&>; -// __policy_invoker calls an instance of __alloc_func held in __policy_storage. +// __policy_invoker calls an instance of __default_alloc_func held in __policy_storage. template struct __policy_invoker; @@ -641,28 +504,6 @@ class __policy_func<_Rp(_ArgTypes...)> { 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(); - } - } - } - 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; @@ -673,9 +514,7 @@ class __policy_func<_Rp(_ArgTypes...)> { if (__use_small_storage<_Fun>()) { ::new ((void*)&__buf_.__small) _Fun(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 _Fun(std::move(__f)); } } } @@ -750,8 +589,8 @@ class __policy_func<_Rp(_ArgTypes...)> { 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 +606,6 @@ class __func<_Rp1 (^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> : public __base // [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 +784,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 b409ad7511f6c..c46203a4ca9a4 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 @@ class reference_wrapper : public __weak_result_type<_Tp> { _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 @@ class reference_wrapper : public __weak_result_type<_Tp> { _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 @@ class reference_wrapper : public __weak_result_type<_Tp> { _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/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h index 00454004851d5..99b54badf893c 100644 --- a/libcxx/include/__mdspan/extents.h +++ b/libcxx/include/__mdspan/extents.h @@ -21,11 +21,10 @@ #include <__config> #include <__concepts/arithmetic.h> -#include <__cstddef/byte.h> #include <__type_traits/common_type.h> +#include <__type_traits/integer_traits.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_nothrow_constructible.h> -#include <__type_traits/is_same.h> #include <__type_traits/make_unsigned.h> #include <__utility/integer_sequence.h> #include <__utility/unreachable.h> @@ -283,7 +282,8 @@ class extents { using size_type = make_unsigned_t; using rank_type = size_t; - static_assert(__libcpp_integer, "extents::index_type must be a signed or unsigned integer type"); + static_assert(__signed_or_unsigned_integer, + "extents::index_type must be a signed or unsigned integer type"); static_assert(((__mdspan_detail::__is_representable_as(_Extents) || (_Extents == dynamic_extent)) && ...), "extents ctor: arguments must be representable as index_type and nonnegative"); diff --git a/libcxx/include/__memory/allocation_guard.h b/libcxx/include/__memory/allocation_guard.h index 66edcd92ed618..016e1a3a429b8 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 4ba50898fb37d..879b387b9ad1f 100644 --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -245,8 +245,8 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept { } template -inline _LIBCPP_HIDE_FROM_ABI constexpr auto -to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { +inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(const _Pointer& __p) noexcept + -> decltype(std::__to_address(__p)) { return std::__to_address(__p); } #endif @@ -302,6 +302,18 @@ concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p #endif +// This function ensures safe conversions between fancy pointers at compile-time, where we avoid casts from/to +// `__void_pointer` by obtaining the underlying raw pointer from the fancy pointer using `std::to_address`, +// then dereferencing it to retrieve the pointed-to object, and finally constructing the target fancy pointer +// to that object using the `std::pointer_traits<>::pinter_to` function. +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _PtrTo __static_fancy_pointer_cast(const _PtrFrom& __p) { + using __ptr_traits = pointer_traits<_PtrTo>; + using __element_type = typename __ptr_traits::element_type; + return __p ? __ptr_traits::pointer_to(*static_cast<__element_type*>(std::addressof(*__p))) + : static_cast<_PtrTo>(nullptr); +} + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/__numeric/saturation_arithmetic.h b/libcxx/include/__numeric/saturation_arithmetic.h index 4110a8cb142a5..9bd3af12c9572 100644 --- a/libcxx/include/__numeric/saturation_arithmetic.h +++ b/libcxx/include/__numeric/saturation_arithmetic.h @@ -11,9 +11,9 @@ #define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H #include <__assert> -#include <__concepts/arithmetic.h> #include <__config> #include <__memory/addressof.h> +#include <__type_traits/integer_traits.h> #include <__utility/cmp.h> #include @@ -28,12 +28,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { if (_Tp __sum; !__builtin_add_overflow(__x, __y, std::addressof(__sum))) return __sum; // Handle overflow - if constexpr (__libcpp_unsigned_integer<_Tp>) { + if constexpr (__unsigned_integer<_Tp>) { return std::numeric_limits<_Tp>::max(); } else { // Signed addition overflow @@ -46,12 +46,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { } } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { if (_Tp __sub; !__builtin_sub_overflow(__x, __y, std::addressof(__sub))) return __sub; // Handle overflow - if constexpr (__libcpp_unsigned_integer<_Tp>) { + if constexpr (__unsigned_integer<_Tp>) { // Overflows if (x < y) return std::numeric_limits<_Tp>::min(); } else { @@ -65,12 +65,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { } } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { if (_Tp __mul; !__builtin_mul_overflow(__x, __y, std::addressof(__mul))) return __mul; // Handle overflow - if constexpr (__libcpp_unsigned_integer<_Tp>) { + if constexpr (__unsigned_integer<_Tp>) { return std::numeric_limits<_Tp>::max(); } else { // Signed multiplication overflow @@ -81,10 +81,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { } } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined"); - if constexpr (__libcpp_unsigned_integer<_Tp>) { + if constexpr (__unsigned_integer<_Tp>) { return __x / __y; } else { // Handle signed division overflow @@ -94,7 +94,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { } } -template <__libcpp_integer _Rp, __libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be // optimized out by the compiler. @@ -112,27 +112,27 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { #if _LIBCPP_STD_VER >= 26 -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { return std::__add_sat(__x, __y); } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { return std::__sub_sat(__x, __y); } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { return std::__mul_sat(__x, __y); } -template <__libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { return std::__div_sat(__x, __y); } -template <__libcpp_integer _Rp, __libcpp_integer _Tp> +template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { return std::__saturate_cast<_Rp>(__x); } diff --git a/libcxx/include/__type_traits/integer_traits.h b/libcxx/include/__type_traits/integer_traits.h new file mode 100644 index 0000000000000..fad502c44e301 --- /dev/null +++ b/libcxx/include/__type_traits/integer_traits.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___TYPE_TRAITS_INTEGER_TRAITS_H +#define _LIBCPP___TYPE_TRAITS_INTEGER_TRAITS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// This trait is to determine whether a type is a /signed integer type/ +// See [basic.fundamental]/p1 +template +inline const bool __is_signed_integer_v = false; +template <> +inline const bool __is_signed_integer_v = true; +template <> +inline const bool __is_signed_integer_v = true; +template <> +inline const bool __is_signed_integer_v = true; +template <> +inline const bool __is_signed_integer_v = true; +template <> +inline const bool __is_signed_integer_v = true; +#if _LIBCPP_HAS_INT128 +template <> +inline const bool __is_signed_integer_v<__int128_t> = true; +#endif + +// This trait is to determine whether a type is an /unsigned integer type/ +// See [basic.fundamental]/p2 +template +inline const bool __is_unsigned_integer_v = false; +template <> +inline const bool __is_unsigned_integer_v = true; +template <> +inline const bool __is_unsigned_integer_v = true; +template <> +inline const bool __is_unsigned_integer_v = true; +template <> +inline const bool __is_unsigned_integer_v = true; +template <> +inline const bool __is_unsigned_integer_v = true; +#if _LIBCPP_HAS_INT128 +template <> +inline const bool __is_unsigned_integer_v<__uint128_t> = true; +#endif + +#if _LIBCPP_STD_VER >= 20 +template +concept __signed_integer = __is_signed_integer_v<_Tp>; + +template +concept __unsigned_integer = __is_unsigned_integer_v<_Tp>; + +// This isn't called __integer, because an integer type according to [basic.fundamental]/p11 is the same as an integral +// type. An integral type is _not_ the same set of types as signed and unsigned integer types combined. +template +concept __signed_or_unsigned_integer = __signed_integer<_Tp> || __unsigned_integer<_Tp>; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_INTEGER_TRAITS_H diff --git a/libcxx/include/__type_traits/is_integral.h b/libcxx/include/__type_traits/is_integral.h index 7f7ac26beb770..5a340965f0384 100644 --- a/libcxx/include/__type_traits/is_integral.h +++ b/libcxx/include/__type_traits/is_integral.h @@ -19,6 +19,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if __has_builtin(__is_integral) + +template +struct _LIBCPP_NO_SPECIALIZATIONS is_integral : _BoolConstant<__is_integral(_Tp)> {}; + +# if _LIBCPP_STD_VER >= 17 +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_integral_v = __is_integral(_Tp); +# endif + +#else + // clang-format off template struct __libcpp_is_integral { enum { value = 0 }; }; template <> struct __libcpp_is_integral { enum { value = 1 }; }; @@ -47,18 +59,6 @@ template <> struct __libcpp_is_integral<__uint128_t> { enum { va #endif // clang-format on -#if __has_builtin(__is_integral) - -template -struct _LIBCPP_NO_SPECIALIZATIONS is_integral : _BoolConstant<__is_integral(_Tp)> {}; - -# if _LIBCPP_STD_VER >= 17 -template -_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_integral_v = __is_integral(_Tp); -# endif - -#else - template struct is_integral : public _BoolConstant<__libcpp_is_integral<__remove_cv_t<_Tp> >::value> {}; diff --git a/libcxx/include/__type_traits/is_signed_integer.h b/libcxx/include/__type_traits/is_signed_integer.h deleted file mode 100644 index 62943902a1834..0000000000000 --- a/libcxx/include/__type_traits/is_signed_integer.h +++ /dev/null @@ -1,35 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP___TYPE_TRAITS_IS_SIGNED_INTEGER_H -#define _LIBCPP___TYPE_TRAITS_IS_SIGNED_INTEGER_H - -#include <__config> -#include <__type_traits/integral_constant.h> - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -// clang-format off -template struct __libcpp_is_signed_integer : false_type {}; -template <> struct __libcpp_is_signed_integer : true_type {}; -template <> struct __libcpp_is_signed_integer : true_type {}; -template <> struct __libcpp_is_signed_integer : true_type {}; -template <> struct __libcpp_is_signed_integer : true_type {}; -template <> struct __libcpp_is_signed_integer : true_type {}; -#if _LIBCPP_HAS_INT128 -template <> struct __libcpp_is_signed_integer<__int128_t> : true_type {}; -#endif -// clang-format on - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP___TYPE_TRAITS_IS_SIGNED_INTEGER_H diff --git a/libcxx/include/__type_traits/is_unsigned_integer.h b/libcxx/include/__type_traits/is_unsigned_integer.h deleted file mode 100644 index 74414a831e79a..0000000000000 --- a/libcxx/include/__type_traits/is_unsigned_integer.h +++ /dev/null @@ -1,35 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H -#define _LIBCPP___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H - -#include <__config> -#include <__type_traits/integral_constant.h> - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -// clang-format off -template struct __libcpp_is_unsigned_integer : false_type {}; -template <> struct __libcpp_is_unsigned_integer : true_type {}; -template <> struct __libcpp_is_unsigned_integer : true_type {}; -template <> struct __libcpp_is_unsigned_integer : true_type {}; -template <> struct __libcpp_is_unsigned_integer : true_type {}; -template <> struct __libcpp_is_unsigned_integer : true_type {}; -#if _LIBCPP_HAS_INT128 -template <> struct __libcpp_is_unsigned_integer<__uint128_t> : true_type {}; -#endif -// clang-format on - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP___TYPE_TRAITS_IS_UNSIGNED_INTEGER_H diff --git a/libcxx/include/__utility/cmp.h b/libcxx/include/__utility/cmp.h index b7c1ed614dfcb..14dc0c154c040 100644 --- a/libcxx/include/__utility/cmp.h +++ b/libcxx/include/__utility/cmp.h @@ -9,8 +9,8 @@ #ifndef _LIBCPP___UTILITY_CMP_H #define _LIBCPP___UTILITY_CMP_H -#include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/integer_traits.h> #include <__type_traits/is_signed.h> #include <__type_traits/make_unsigned.h> #include @@ -26,7 +26,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) return __t == __u; @@ -36,12 +36,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { return __u < 0 ? false : __t == make_unsigned_t<_Up>(__u); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_equal(__t, __u); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept { if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) return __t < __u; @@ -51,22 +51,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept { return __u < 0 ? false : __t < make_unsigned_t<_Up>(__u); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater(_Tp __t, _Up __u) noexcept { return std::cmp_less(__u, __t); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_greater(__t, __u); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_less(__t, __u); } -template <__libcpp_integer _Tp, __libcpp_integer _Up> +template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> _LIBCPP_HIDE_FROM_ABI constexpr bool in_range(_Up __u) noexcept { return std::cmp_less_equal(__u, numeric_limits<_Tp>::max()) && std::cmp_greater_equal(__u, numeric_limits<_Tp>::min()); diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index ab390aafa0d9d..dbacbce044766 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -209,21 +209,12 @@ struct pair # endif # if _LIBCPP_STD_VER >= 23 - // TODO: Remove this workaround in LLVM 20. The bug got fixed in Clang 18. - // This is a workaround for http://llvm.org/PR60710. We should be able to remove it once Clang is fixed. - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __pair_like_explicit_wknd() { - if constexpr (__pair_like_no_subrange<_PairLike>) { - return !is_convertible_v(std::declval<_PairLike&&>())), first_type> || - !is_convertible_v(std::declval<_PairLike&&>())), second_type>; - } - return false; - } - template <__pair_like_no_subrange _PairLike> requires(is_constructible_v(std::declval<_PairLike &&>()))> && is_constructible_v(std::declval<_PairLike &&>()))>) - _LIBCPP_HIDE_FROM_ABI constexpr explicit(__pair_like_explicit_wknd<_PairLike>()) pair(_PairLike&& __p) + _LIBCPP_HIDE_FROM_ABI constexpr explicit( + !is_convertible_v(std::declval<_PairLike&&>())), first_type> || + !is_convertible_v(std::declval<_PairLike&&>())), second_type>) pair(_PairLike&& __p) : first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {} # endif diff --git a/libcxx/include/bitset b/libcxx/include/bitset index 88dc0e08c995d..6be476e2b69d8 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -645,16 +645,13 @@ public: template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit bitset( const _CharT* __str, -# if _LIBCPP_STD_VER >= 26 - typename basic_string_view<_CharT>::size_type __n = basic_string_view<_CharT>::npos, -# else - typename basic_string<_CharT>::size_type __n = basic_string<_CharT>::npos, -# endif + size_t __n = basic_string<_CharT>::npos, _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) { - - size_t __rlen = std::min(__n, char_traits<_CharT>::length(__str)); - __init_from_string_view(basic_string_view<_CharT>(__str, __rlen), __zero, __one); + if (__n == basic_string<_CharT>::npos) + __init_from_string_view(basic_string_view<_CharT>(__str), __zero, __one); + else + __init_from_string_view(basic_string_view<_CharT>(__str, __n), __zero, __one); } # if _LIBCPP_STD_VER >= 26 template diff --git a/libcxx/include/chrono b/libcxx/include/chrono index cd9b98872083e..82e99a31bcc9f 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -132,6 +132,11 @@ public: // arithmetic + constexpr time_point& operator++(); // C++20 + constexpr time_point operator++(int); // C++20 + constexpr time_point& operator--(); // C++20 + constexpr time_point operator--(int); // C++20 + time_point& operator+=(const duration& d); // constexpr in C++17 time_point& operator-=(const duration& d); // constexpr in C++17 diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list index 5046de27a9da1..e9b2c860b89c4 100644 --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -295,8 +295,8 @@ struct __forward_node_traits { "the _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB macro to silence this diagnostic."); # endif - _LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__node_pointer __p) { - return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__p)); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__node_pointer __p) { + return std::__static_fancy_pointer_cast<__begin_node_pointer>(__p); } }; @@ -307,11 +307,11 @@ struct __forward_begin_node { pointer __next_; - _LIBCPP_HIDE_FROM_ABI __forward_begin_node() : __next_(nullptr) {} - _LIBCPP_HIDE_FROM_ABI explicit __forward_begin_node(pointer __n) : __next_(__n) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_begin_node() : __next_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_begin_node(pointer __n) : __next_(__n) {} - _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __next_as_begin() const { - return static_cast<__begin_node_pointer>(__next_); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __next_as_begin() const { + return std::__static_fancy_pointer_cast<__begin_node_pointer>(__next_); } }; @@ -335,7 +335,7 @@ private: }; public: - _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; } # else private: @@ -345,8 +345,8 @@ public: _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return *std::__launder(reinterpret_cast<_Tp*>(&__buffer_)); } # endif - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_node(_NodePtr __next) : _Base(__next) {} - _LIBCPP_HIDE_FROM_ABI ~__forward_list_node() {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_node(_NodePtr __next) : _Base(__next) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI ~__forward_list_node() {} }; template > @@ -357,24 +357,26 @@ class __forward_list_const_iterator; template class __forward_list_iterator { typedef __forward_node_traits<_NodePtr> __traits; + typedef typename __traits::__node_type __node_type; + typedef typename __traits::__begin_node __begin_node_type; typedef typename __traits::__node_pointer __node_pointer; typedef typename __traits::__begin_node_pointer __begin_node_pointer; typedef typename __traits::__void_pointer __void_pointer; __begin_node_pointer __ptr_; - _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const { - return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_)); - } - _LIBCPP_HIDE_FROM_ABI __node_pointer __get_unsafe_node_pointer() const { - return static_cast<__node_pointer>(static_cast<__void_pointer>(__ptr_)); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const { return __ptr_; } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __node_pointer __get_unsafe_node_pointer() const { + return std::__static_fancy_pointer_cast<__node_pointer>(__ptr_); } - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_iterator(nullptr_t) _NOEXCEPT : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_iterator(nullptr_t) _NOEXCEPT + : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_iterator(__begin_node_pointer __p) _NOEXCEPT : __ptr_(__p) {} - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_iterator(__node_pointer __p) _NOEXCEPT + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_iterator(__node_pointer __p) _NOEXCEPT : __ptr_(__traits::__as_iter_node(__p)) {} template @@ -389,27 +391,31 @@ public: typedef typename pointer_traits<__node_pointer>::difference_type difference_type; typedef __rebind_pointer_t<__node_pointer, value_type> pointer; - _LIBCPP_HIDE_FROM_ABI __forward_list_iterator() _NOEXCEPT : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_iterator() _NOEXCEPT : __ptr_(nullptr) {} - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_unsafe_node_pointer()->__get_value(); } - _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference operator*() const { + return __get_unsafe_node_pointer()->__get_value(); + } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits::pointer_to(__get_unsafe_node_pointer()->__get_value()); } - _LIBCPP_HIDE_FROM_ABI __forward_list_iterator& operator++() { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_iterator& operator++() { __ptr_ = __traits::__as_iter_node(__ptr_->__next_); return *this; } - _LIBCPP_HIDE_FROM_ABI __forward_list_iterator operator++(int) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_iterator operator++(int) { __forward_list_iterator __t(*this); ++(*this); return __t; } - friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __forward_list_iterator& __x, const __forward_list_iterator& __y) { + friend _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool + operator==(const __forward_list_iterator& __x, const __forward_list_iterator& __y) { return __x.__ptr_ == __y.__ptr_; } - friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __forward_list_iterator& __x, const __forward_list_iterator& __y) { + friend _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool + operator!=(const __forward_list_iterator& __x, const __forward_list_iterator& __y) { return !(__x == __y); } }; @@ -421,23 +427,25 @@ class __forward_list_const_iterator { typedef __forward_node_traits<_NodePtr> __traits; typedef typename __traits::__node_type __node_type; + typedef typename __traits::__begin_node __begin_node_type; typedef typename __traits::__node_pointer __node_pointer; typedef typename __traits::__begin_node_pointer __begin_node_pointer; typedef typename __traits::__void_pointer __void_pointer; __begin_node_pointer __ptr_; - _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const { - return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_)); - } - _LIBCPP_HIDE_FROM_ABI __node_pointer __get_unsafe_node_pointer() const { - return static_cast<__node_pointer>(static_cast<__void_pointer>(__ptr_)); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const { return __ptr_; } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __node_pointer __get_unsafe_node_pointer() const { + return std::__static_fancy_pointer_cast<__node_pointer>(__ptr_); } - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_const_iterator(nullptr_t) _NOEXCEPT : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_const_iterator(nullptr_t) _NOEXCEPT + : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_const_iterator(__begin_node_pointer __p) _NOEXCEPT : __ptr_(__p) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_const_iterator(__node_pointer __p) _NOEXCEPT : __ptr_(__traits::__as_iter_node(__p)) {} @@ -451,30 +459,32 @@ public: typedef typename pointer_traits<__node_pointer>::difference_type difference_type; typedef __rebind_pointer_t<__node_pointer, const value_type> pointer; - _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator() _NOEXCEPT : __ptr_(nullptr) {} - _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator(__forward_list_iterator<__node_pointer> __p) _NOEXCEPT - : __ptr_(__p.__ptr_) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator() _NOEXCEPT : __ptr_(nullptr) {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + __forward_list_const_iterator(__forward_list_iterator<__node_pointer> __p) _NOEXCEPT : __ptr_(__p.__ptr_) {} - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_unsafe_node_pointer()->__get_value(); } - _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference operator*() const { + return __get_unsafe_node_pointer()->__get_value(); + } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits::pointer_to(__get_unsafe_node_pointer()->__get_value()); } - _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator& operator++() { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator& operator++() { __ptr_ = __traits::__as_iter_node(__ptr_->__next_); return *this; } - _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator operator++(int) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_const_iterator operator++(int) { __forward_list_const_iterator __t(*this); ++(*this); return __t; } - friend _LIBCPP_HIDE_FROM_ABI bool + friend _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool operator==(const __forward_list_const_iterator& __x, const __forward_list_const_iterator& __y) { return __x.__ptr_ == __y.__ptr_; } - friend _LIBCPP_HIDE_FROM_ABI bool + friend _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool operator!=(const __forward_list_const_iterator& __x, const __forward_list_const_iterator& __y) { return !(__x == __y); } @@ -498,48 +508,53 @@ protected: _LIBCPP_COMPRESSED_PAIR(__begin_node, __before_begin_, __node_allocator, __alloc_); - _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() _NOEXCEPT { return pointer_traits<__begin_node_pointer>::pointer_to(__before_begin_); } - _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() const _NOEXCEPT { - return pointer_traits<__begin_node_pointer>::pointer_to(const_cast<__begin_node&>(__before_begin_)); + + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() const _NOEXCEPT { + return pointer_traits<__begin_node_pointer>::pointer_to( + *const_cast<__begin_node*>(std::addressof(__before_begin_))); } typedef __forward_list_iterator<__node_pointer> iterator; typedef __forward_list_const_iterator<__node_pointer> const_iterator; - _LIBCPP_HIDE_FROM_ABI __forward_list_base() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_base() + _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) : __before_begin_(__begin_node()) {} - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const allocator_type& __a) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const allocator_type& __a) : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) {} - _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const __node_allocator& __a) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const __node_allocator& __a) : __before_begin_(__begin_node()), __alloc_(__a) {} public: # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __forward_list_base(__forward_list_base&& __x) noexcept(is_nothrow_move_constructible<__node_allocator>::value); - _LIBCPP_HIDE_FROM_ABI __forward_list_base(__forward_list_base&& __x, const allocator_type& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + __forward_list_base(__forward_list_base&& __x, const allocator_type& __a); # endif // _LIBCPP_CXX03_LANG __forward_list_base(const __forward_list_base&) = delete; __forward_list_base& operator=(const __forward_list_base&) = delete; - _LIBCPP_HIDE_FROM_ABI ~__forward_list_base(); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI ~__forward_list_base(); protected: - _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __forward_list_base& __x) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __forward_list_base& __x) { __copy_assign_alloc(__x, integral_constant()); } - _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__forward_list_base& __x) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__forward_list_base& __x) _NOEXCEPT_(!__node_traits::propagate_on_container_move_assignment::value || is_nothrow_move_assignable<__node_allocator>::value) { __move_assign_alloc(__x, integral_constant()); } template - _LIBCPP_HIDE_FROM_ABI __node_pointer __create_node(__node_pointer __next, _Args&&... __args) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __node_pointer + __create_node(__node_pointer __next, _Args&&... __args) { __allocation_guard<__node_allocator> __guard(__alloc_, 1); // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value // held inside the node, since we need to use the allocator's construct() method for that. @@ -554,7 +569,7 @@ protected: return __guard.__release_ptr(); } - _LIBCPP_HIDE_FROM_ABI void __delete_node(__node_pointer __node) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __delete_node(__node_pointer __node) { // For the same reason as above, we use the allocator's destroy() method for the value_type, // but not for the node itself. __node_traits::destroy(__alloc_, std::addressof(__node->__get_value())); @@ -563,7 +578,7 @@ protected: } public: - _LIBCPP_HIDE_FROM_ABI void swap(__forward_list_base& __x) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void swap(__forward_list_base& __x) # if _LIBCPP_STD_VER >= 14 _NOEXCEPT; # else @@ -571,18 +586,21 @@ public: # endif protected: - _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT; + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT; private: - _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __forward_list_base&, false_type) {} - _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __forward_list_base& __x, true_type) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __forward_list_base&, false_type) { + } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void + __copy_assign_alloc(const __forward_list_base& __x, true_type) { if (__alloc_ != __x.__alloc_) clear(); __alloc_ = __x.__alloc_; } - _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__forward_list_base&, false_type) _NOEXCEPT {} - _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__forward_list_base& __x, true_type) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void + __move_assign_alloc(__forward_list_base&, false_type) _NOEXCEPT {} + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__forward_list_base& __x, true_type) _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value) { __alloc_ = std::move(__x.__alloc_); } @@ -591,14 +609,15 @@ private: # ifndef _LIBCPP_CXX03_LANG template -inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x) noexcept( - is_nothrow_move_constructible<__node_allocator>::value) +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline __forward_list_base<_Tp, _Alloc>::__forward_list_base( + __forward_list_base&& __x) noexcept(is_nothrow_move_constructible<__node_allocator>::value) : __before_begin_(std::move(__x.__before_begin_)), __alloc_(std::move(__x.__alloc_)) { __x.__before_begin()->__next_ = nullptr; } template -inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x, const allocator_type& __a) +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline __forward_list_base<_Tp, _Alloc>::__forward_list_base( + __forward_list_base&& __x, const allocator_type& __a) : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) { if (__alloc_ == __x.__alloc_) { __before_begin()->__next_ = __x.__before_begin()->__next_; @@ -609,12 +628,12 @@ inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base # endif // _LIBCPP_CXX03_LANG template -__forward_list_base<_Tp, _Alloc>::~__forward_list_base() { +_LIBCPP_CONSTEXPR_SINCE_CXX26 __forward_list_base<_Tp, _Alloc>::~__forward_list_base() { clear(); } template -inline void __forward_list_base<_Tp, _Alloc>::swap(__forward_list_base& __x) +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline void __forward_list_base<_Tp, _Alloc>::swap(__forward_list_base& __x) # if _LIBCPP_STD_VER >= 14 _NOEXCEPT # else @@ -627,7 +646,7 @@ inline void __forward_list_base<_Tp, _Alloc>::swap(__forward_list_base& __x) } template -void __forward_list_base<_Tp, _Alloc>::clear() _NOEXCEPT { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void __forward_list_base<_Tp, _Alloc>::clear() _NOEXCEPT { for (__node_pointer __p = __before_begin()->__next_; __p != nullptr;) { __node_pointer __next = __p->__next_; __delete_node(__p); @@ -672,105 +691,123 @@ public: typedef void __remove_return_type; # endif - _LIBCPP_HIDE_FROM_ABI forward_list() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) { - } // = default; - _LIBCPP_HIDE_FROM_ABI explicit forward_list(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list() + _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) {} // = default; + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(const allocator_type& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n); # if _LIBCPP_STD_VER >= 14 - _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n, const allocator_type& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n, const allocator_type& __a); # endif - _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v); template <__enable_if_t<__is_allocator<_Alloc>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v, const allocator_type& __a) : __base(__a) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(size_type __n, const value_type& __v, const allocator_type& __a) + : __base(__a) { insert_after(cbefore_begin(), __n, __v); } template ::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI forward_list(_InputIterator __f, _InputIterator __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(_InputIterator __f, _InputIterator __l); template ::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI forward_list(_InputIterator __f, _InputIterator __l, const allocator_type& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(_InputIterator __f, _InputIterator __l, const allocator_type& __a); # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_Tp> _Range> - _LIBCPP_HIDE_FROM_ABI forward_list(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type()) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type()) : __base(__a) { prepend_range(std::forward<_Range>(__range)); } # endif - _LIBCPP_HIDE_FROM_ABI forward_list(const forward_list& __x); - _LIBCPP_HIDE_FROM_ABI forward_list(const forward_list& __x, const __type_identity_t& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(const forward_list& __x); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(const forward_list& __x, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI forward_list& operator=(const forward_list& __x); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list& operator=(const forward_list& __x); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI forward_list(forward_list&& __x) noexcept(is_nothrow_move_constructible<__base>::value) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(forward_list&& __x) noexcept(is_nothrow_move_constructible<__base>::value) : __base(std::move(__x)) {} - _LIBCPP_HIDE_FROM_ABI forward_list(forward_list&& __x, const __type_identity_t& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(forward_list&& __x, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list __il); - _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list __il, const allocator_type& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list __il); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI + forward_list(initializer_list __il, const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept( + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept( (__node_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable::value) || allocator_traits::is_always_equal::value); - _LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list __il); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list __il); - _LIBCPP_HIDE_FROM_ABI void assign(initializer_list __il); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void assign(initializer_list __il); # endif // _LIBCPP_CXX03_LANG // ~forward_list() = default; template ::value, int> = 0> - void _LIBCPP_HIDE_FROM_ABI assign(_InputIterator __f, _InputIterator __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 void _LIBCPP_HIDE_FROM_ABI assign(_InputIterator __f, _InputIterator __l); # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_Tp> _Range> - _LIBCPP_HIDE_FROM_ABI void assign_range(_Range&& __range) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void assign_range(_Range&& __range) { __assign_with_sentinel(ranges::begin(__range), ranges::end(__range)); } # endif - _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v); - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(this->__alloc_); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + return allocator_type(this->__alloc_); + } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__base::__before_begin()->__next_); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { + return iterator(__base::__before_begin()->__next_); + } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()->__next_); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return iterator(nullptr); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return const_iterator(nullptr); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return iterator(nullptr); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { + return const_iterator(nullptr); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return const_iterator(__base::__before_begin()->__next_); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return const_iterator(nullptr); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { + return const_iterator(nullptr); + } - _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { return iterator(__base::__before_begin()); } - _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { + return iterator(__base::__before_begin()); + } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbefore_begin() const _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbefore_begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()); } - [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __base::__before_begin()->__next_ == nullptr; } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return std::min(__node_traits::max_size(this->__alloc_), numeric_limits::max()); } - _LIBCPP_HIDE_FROM_ABI reference front() { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference front() { _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list"); return __base::__before_begin()->__next_->__get_value(); } - _LIBCPP_HIDE_FROM_ABI const_reference front() const { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference front() const { _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list"); return __base::__before_begin()->__next_->__get_value(); } @@ -778,54 +815,59 @@ public: # ifndef _LIBCPP_CXX03_LANG # if _LIBCPP_STD_VER >= 17 template - _LIBCPP_HIDE_FROM_ABI reference emplace_front(_Args&&... __args); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference emplace_front(_Args&&... __args); # else template - _LIBCPP_HIDE_FROM_ABI void emplace_front(_Args&&... __args); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void emplace_front(_Args&&... __args); # endif - _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __v); # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI void push_front(const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void push_front(const value_type& __v); # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_Tp> _Range> - _LIBCPP_HIDE_FROM_ABI void prepend_range(_Range&& __range) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void prepend_range(_Range&& __range) { insert_range_after(cbefore_begin(), std::forward<_Range>(__range)); } # endif - _LIBCPP_HIDE_FROM_ABI void pop_front(); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void pop_front(); # ifndef _LIBCPP_CXX03_LANG template - _LIBCPP_HIDE_FROM_ABI iterator emplace_after(const_iterator __p, _Args&&... __args); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator emplace_after(const_iterator __p, _Args&&... __args); - _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, value_type&& __v); - _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, initializer_list __il) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, value_type&& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + insert_after(const_iterator __p, initializer_list __il) { return insert_after(__p, __il.begin(), __il.end()); } # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, const value_type& __v); - _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, size_type __n, const value_type& __v) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + insert_after(const_iterator __p, size_type __n, const value_type& __v) { return __insert_after(__p, __n, __v); } template ::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator insert_after(const_iterator __p, _InputIterator __f, _InputIterator __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + insert_after(const_iterator __p, _InputIterator __f, _InputIterator __l); # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_Tp> _Range> - _LIBCPP_HIDE_FROM_ABI iterator insert_range_after(const_iterator __position, _Range&& __range) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + insert_range_after(const_iterator __position, _Range&& __range) { return __insert_after_with_sentinel(__position, ranges::begin(__range), ranges::end(__range)); } # endif template - _LIBCPP_HIDE_FROM_ABI iterator __insert_after_with_sentinel(const_iterator __p, _InputIterator __f, _Sentinel __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + __insert_after_with_sentinel(const_iterator __p, _InputIterator __f, _Sentinel __l); - _LIBCPP_HIDE_FROM_ABI iterator erase_after(const_iterator __p); - _LIBCPP_HIDE_FROM_ABI iterator erase_after(const_iterator __f, const_iterator __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator erase_after(const_iterator __p); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator erase_after(const_iterator __f, const_iterator __l); - _LIBCPP_HIDE_FROM_ABI void swap(forward_list& __x) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void swap(forward_list& __x) # if _LIBCPP_STD_VER >= 14 _NOEXCEPT # else @@ -835,58 +877,63 @@ public: __base::swap(__x); } - _LIBCPP_HIDE_FROM_ABI void resize(size_type __n); - _LIBCPP_HIDE_FROM_ABI void resize(size_type __n, const value_type& __v); - _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __base::clear(); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void resize(size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void resize(size_type __n, const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __base::clear(); } - _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x); - _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x, const_iterator __i); - _LIBCPP_HIDE_FROM_ABI void + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void + splice_after(const_iterator __p, forward_list&& __x, const_iterator __i); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x, const_iterator __f, const_iterator __l); - _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list& __x); - _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list& __x, const_iterator __i); - _LIBCPP_HIDE_FROM_ABI void + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list& __x); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void + splice_after(const_iterator __p, forward_list& __x, const_iterator __i); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list& __x, const_iterator __f, const_iterator __l); - _LIBCPP_HIDE_FROM_ABI __remove_return_type remove(const value_type& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __remove_return_type remove(const value_type& __v); template - _LIBCPP_HIDE_FROM_ABI __remove_return_type remove_if(_Predicate __pred); - _LIBCPP_HIDE_FROM_ABI __remove_return_type unique() { return unique(__equal_to()); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __remove_return_type remove_if(_Predicate __pred); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __remove_return_type unique() { return unique(__equal_to()); } template - _LIBCPP_HIDE_FROM_ABI __remove_return_type unique(_BinaryPredicate __binary_pred); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __remove_return_type unique(_BinaryPredicate __binary_pred); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI void merge(forward_list&& __x) { merge(__x, __less<>()); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void merge(forward_list&& __x) { merge(__x, __less<>()); } template - _LIBCPP_HIDE_FROM_ABI void merge(forward_list&& __x, _Compare __comp) { + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void merge(forward_list&& __x, _Compare __comp) { merge(__x, std::move(__comp)); } # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI void merge(forward_list& __x) { merge(__x, __less<>()); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void merge(forward_list& __x) { merge(__x, __less<>()); } template - _LIBCPP_HIDE_FROM_ABI void merge(forward_list& __x, _Compare __comp); - _LIBCPP_HIDE_FROM_ABI void sort() { sort(__less<>()); } + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void merge(forward_list& __x, _Compare __comp); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void sort() { sort(__less<>()); } template - _LIBCPP_HIDE_FROM_ABI void sort(_Compare __comp); - _LIBCPP_HIDE_FROM_ABI void reverse() _NOEXCEPT; + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void sort(_Compare __comp); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void reverse() _NOEXCEPT; private: # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI void __move_assign(forward_list& __x, true_type) + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __move_assign(forward_list& __x, true_type) _NOEXCEPT_(is_nothrow_move_assignable::value); - _LIBCPP_HIDE_FROM_ABI void __move_assign(forward_list& __x, false_type); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __move_assign(forward_list& __x, false_type); # endif // _LIBCPP_CXX03_LANG template - _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iter __f, _Sent __l); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iter __f, _Sent __l); template - _LIBCPP_HIDE_FROM_ABI iterator __insert_after(const_iterator __p, size_type __n, _Args&&... __args); + _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator + __insert_after(const_iterator __p, size_type __n, _Args&&... __args); template - static _LIBCPP_HIDE_FROM_ABI __node_pointer __merge(__node_pointer __f1, __node_pointer __f2, _Compare& __comp); + _LIBCPP_CONSTEXPR_SINCE_CXX26 static _LIBCPP_HIDE_FROM_ABI __node_pointer + __merge(__node_pointer __f1, __node_pointer __f2, _Compare& __comp); // TODO: Make this _LIBCPP_HIDE_FROM_ABI template - static _LIBCPP_HIDDEN __node_pointer __sort(__node_pointer __f, difference_type __sz, _Compare& __comp); + _LIBCPP_CONSTEXPR_SINCE_CXX26 static _LIBCPP_HIDDEN __node_pointer + __sort(__node_pointer __f, difference_type __sz, _Compare& __comp); }; # if _LIBCPP_STD_VER >= 17 @@ -911,10 +958,10 @@ forward_list(from_range_t, _Range&&, _Alloc = _Alloc()) -> forward_list -inline forward_list<_Tp, _Alloc>::forward_list(const allocator_type& __a) : __base(__a) {} +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline forward_list<_Tp, _Alloc>::forward_list(const allocator_type& __a) : __base(__a) {} template -forward_list<_Tp, _Alloc>::forward_list(size_type __n) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type __n) { if (__n > 0) { for (__begin_node_pointer __p = __base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) { __p->__next_ = this->__create_node(/* next = */ nullptr); @@ -924,7 +971,8 @@ forward_list<_Tp, _Alloc>::forward_list(size_type __n) { # if _LIBCPP_STD_VER >= 14 template -forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __base_alloc) : __base(__base_alloc) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __base_alloc) + : __base(__base_alloc) { if (__n > 0) { for (__begin_node_pointer __p = __base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) { __p->__next_ = this->__create_node(/* next = */ nullptr); @@ -934,37 +982,39 @@ forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __b # endif template -forward_list<_Tp, _Alloc>::forward_list(size_type __n, const value_type& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type __n, const value_type& __v) { insert_after(cbefore_begin(), __n, __v); } template template ::value, int> > -forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l) { insert_after(cbefore_begin(), __f, __l); } template template ::value, int> > +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l, const allocator_type& __a) : __base(__a) { insert_after(cbefore_begin(), __f, __l); } template -forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x) +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x) : __base(__node_traits::select_on_container_copy_construction(__x.__alloc_)) { insert_after(cbefore_begin(), __x.begin(), __x.end()); } template +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x, const __type_identity_t& __a) : __base(__a) { insert_after(cbefore_begin(), __x.begin(), __x.end()); } template -forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(const forward_list& __x) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(const forward_list& __x) { if (this != std::addressof(__x)) { __base::__copy_assign_alloc(__x); assign(__x.begin(), __x.end()); @@ -974,6 +1024,7 @@ forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(const forward_li # ifndef _LIBCPP_CXX03_LANG template +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x, const __type_identity_t& __a) : __base(std::move(__x), __a) { if (this->__alloc_ != __x.__alloc_) { @@ -983,17 +1034,19 @@ forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x, const __type_identit } template -forward_list<_Tp, _Alloc>::forward_list(initializer_list __il) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(initializer_list __il) { insert_after(cbefore_begin(), __il.begin(), __il.end()); } template -forward_list<_Tp, _Alloc>::forward_list(initializer_list __il, const allocator_type& __a) : __base(__a) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 +forward_list<_Tp, _Alloc>::forward_list(initializer_list __il, const allocator_type& __a) + : __base(__a) { insert_after(cbefore_begin(), __il.begin(), __il.end()); } template -void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, true_type) +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, true_type) _NOEXCEPT_(is_nothrow_move_assignable::value) { clear(); __base::__move_assign_alloc(__x); @@ -1002,7 +1055,7 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, true_type) } template -void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) { if (this->__alloc_ == __x.__alloc_) __move_assign(__x, true_type()); else { @@ -1012,7 +1065,8 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) { } template -inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept( +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline forward_list<_Tp, _Alloc>& +forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept( (__node_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable::value) || allocator_traits::is_always_equal::value) { @@ -1021,7 +1075,8 @@ inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_l } template -inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(initializer_list __il) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline forward_list<_Tp, _Alloc>& +forward_list<_Tp, _Alloc>::operator=(initializer_list __il) { assign(__il.begin(), __il.end()); return *this; } @@ -1030,13 +1085,14 @@ inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(initializ template template ::value, int> > -void forward_list<_Tp, _Alloc>::assign(_InputIterator __f, _InputIterator __l) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::assign(_InputIterator __f, _InputIterator __l) { __assign_with_sentinel(__f, __l); } template template -_LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::__assign_with_sentinel(_Iter __f, _Sent __l) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void +forward_list<_Tp, _Alloc>::__assign_with_sentinel(_Iter __f, _Sent __l) { iterator __i = before_begin(); iterator __j = std::next(__i); iterator __e = end(); @@ -1049,7 +1105,7 @@ _LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::__assign_with_sentinel(_It } template -void forward_list<_Tp, _Alloc>::assign(size_type __n, const value_type& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::assign(size_type __n, const value_type& __v) { iterator __i = before_begin(); iterator __j = std::next(__i); iterator __e = end(); @@ -1064,18 +1120,19 @@ void forward_list<_Tp, _Alloc>::assign(size_type __n, const value_type& __v) { # ifndef _LIBCPP_CXX03_LANG template -inline void forward_list<_Tp, _Alloc>::assign(initializer_list __il) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline void forward_list<_Tp, _Alloc>::assign(initializer_list __il) { assign(__il.begin(), __il.end()); } template template +_LIBCPP_CONSTEXPR_SINCE_CXX26 # if _LIBCPP_STD_VER >= 17 -typename forward_list<_Tp, _Alloc>::reference + typename forward_list<_Tp, _Alloc>::reference # else -void + void # endif -forward_list<_Tp, _Alloc>::emplace_front(_Args&&... __args) { + forward_list<_Tp, _Alloc>::emplace_front(_Args&&... __args) { __base::__before_begin()->__next_ = this->__create_node(/* next = */ __base::__before_begin()->__next_, std::forward<_Args>(__args)...); # if _LIBCPP_STD_VER >= 17 @@ -1084,7 +1141,7 @@ forward_list<_Tp, _Alloc>::emplace_front(_Args&&... __args) { } template -void forward_list<_Tp, _Alloc>::push_front(value_type&& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::push_front(value_type&& __v) { __base::__before_begin()->__next_ = this->__create_node(/* next = */ __base::__before_begin()->__next_, std::move(__v)); } @@ -1092,12 +1149,12 @@ void forward_list<_Tp, _Alloc>::push_front(value_type&& __v) { # endif // _LIBCPP_CXX03_LANG template -void forward_list<_Tp, _Alloc>::push_front(const value_type& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::push_front(const value_type& __v) { __base::__before_begin()->__next_ = this->__create_node(/* next = */ __base::__before_begin()->__next_, __v); } template -void forward_list<_Tp, _Alloc>::pop_front() { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::pop_front() { _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::pop_front called on an empty list"); __node_pointer __p = __base::__before_begin()->__next_; __base::__before_begin()->__next_ = __p->__next_; @@ -1108,7 +1165,7 @@ void forward_list<_Tp, _Alloc>::pop_front() { template template -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::emplace_after(const_iterator __p, _Args&&... __args) { __begin_node_pointer const __r = __p.__get_begin(); __r->__next_ = this->__create_node(/* next = */ __r->__next_, std::forward<_Args>(__args)...); @@ -1116,7 +1173,7 @@ forward_list<_Tp, _Alloc>::emplace_after(const_iterator __p, _Args&&... __args) } template -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, value_type&& __v) { __begin_node_pointer const __r = __p.__get_begin(); __r->__next_ = this->__create_node(/* next = */ __r->__next_, std::move(__v)); @@ -1126,7 +1183,7 @@ forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, value_type&& __v) { # endif // _LIBCPP_CXX03_LANG template -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, const value_type& __v) { __begin_node_pointer const __r = __p.__get_begin(); __r->__next_ = this->__create_node(/* next = */ __r->__next_, __v); @@ -1135,7 +1192,7 @@ forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, const value_type& __ template template -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::__insert_after(const_iterator __p, size_type __n, _Args&&... __args) { __begin_node_pointer __r = __p.__get_begin(); if (__n > 0) { @@ -1159,21 +1216,21 @@ forward_list<_Tp, _Alloc>::__insert_after(const_iterator __p, size_type __n, _Ar # endif // _LIBCPP_HAS_EXCEPTIONS __last->__next_ = __r->__next_; __r->__next_ = __first; - __r = static_cast<__begin_node_pointer>(__last); + __r = __forward_node_traits<__node_pointer>::__as_iter_node(__last); } return iterator(__r); } template template ::value, int> > -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, _InputIterator __f, _InputIterator __l) { return __insert_after_with_sentinel(__p, std::move(__f), std::move(__l)); } template template -_LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::__insert_after_with_sentinel(const_iterator __p, _InputIterator __f, _Sentinel __l) { __begin_node_pointer __r = __p.__get_begin(); @@ -1200,14 +1257,15 @@ forward_list<_Tp, _Alloc>::__insert_after_with_sentinel(const_iterator __p, _Inp __last->__next_ = __r->__next_; __r->__next_ = __first; - __r = static_cast<__begin_node_pointer>(__last); + __r = __forward_node_traits<__node_pointer>::__as_iter_node(__last); } return iterator(__r); } template -typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::erase_after(const_iterator __f) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator +forward_list<_Tp, _Alloc>::erase_after(const_iterator __f) { __begin_node_pointer __p = __f.__get_begin(); __node_pointer __n = __p->__next_; __p->__next_ = __n->__next_; @@ -1216,7 +1274,7 @@ typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::erase_af } template -typename forward_list<_Tp, _Alloc>::iterator +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>::erase_after(const_iterator __f, const_iterator __l) { __node_pointer __e = __l.__get_unsafe_node_pointer(); if (__f != __l) { @@ -1236,7 +1294,7 @@ forward_list<_Tp, _Alloc>::erase_after(const_iterator __f, const_iterator __l) { } template -void forward_list<_Tp, _Alloc>::resize(size_type __n) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::resize(size_type __n) { size_type __sz = 0; iterator __p = before_begin(); iterator __i = begin(); @@ -1250,7 +1308,7 @@ void forward_list<_Tp, _Alloc>::resize(size_type __n) { } template -void forward_list<_Tp, _Alloc>::resize(size_type __n, const value_type& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::resize(size_type __n, const value_type& __v) { size_type __sz = 0; iterator __p = before_begin(); iterator __i = begin(); @@ -1264,7 +1322,7 @@ void forward_list<_Tp, _Alloc>::resize(size_type __n, const value_type& __v) { } template -void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& __x) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& __x) { if (!__x.empty()) { if (__p.__get_begin()->__next_ != nullptr) { const_iterator __lm1 = __x.before_begin(); @@ -1278,7 +1336,8 @@ void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& _ } template -void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& /*__other*/, const_iterator __i) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void +forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& /*__other*/, const_iterator __i) { const_iterator __lm1 = std::next(__i); if (__p != __i && __p != __lm1) { __i.__get_begin()->__next_ = __lm1.__get_begin()->__next_; @@ -1288,7 +1347,7 @@ void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list& / } template -void forward_list<_Tp, _Alloc>::splice_after( +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::splice_after( const_iterator __p, forward_list& /*__other*/, const_iterator __f, const_iterator __l) { if (__f != __l && __p != __f) { const_iterator __lm1 = __f; @@ -1303,24 +1362,26 @@ void forward_list<_Tp, _Alloc>::splice_after( } template -inline _LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list&& __x) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI void +forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list&& __x) { splice_after(__p, __x); } template -inline _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::splice_after(const_iterator __p, forward_list&& __x, const_iterator __i) { splice_after(__p, __x, __i); } template -inline _LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::splice_after( +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI void forward_list<_Tp, _Alloc>::splice_after( const_iterator __p, forward_list&& __x, const_iterator __f, const_iterator __l) { splice_after(__p, __x, __f, __l); } template -typename forward_list<_Tp, _Alloc>::__remove_return_type forward_list<_Tp, _Alloc>::remove(const value_type& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::__remove_return_type +forward_list<_Tp, _Alloc>::remove(const value_type& __v) { forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing typename forward_list<_Tp, _Alloc>::size_type __count_removed = 0; const iterator __e = end(); @@ -1343,7 +1404,8 @@ typename forward_list<_Tp, _Alloc>::__remove_return_type forward_list<_Tp, _Allo template template -typename forward_list<_Tp, _Alloc>::__remove_return_type forward_list<_Tp, _Alloc>::remove_if(_Predicate __pred) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::__remove_return_type +forward_list<_Tp, _Alloc>::remove_if(_Predicate __pred) { forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing typename forward_list<_Tp, _Alloc>::size_type __count_removed = 0; const iterator __e = end(); @@ -1366,7 +1428,7 @@ typename forward_list<_Tp, _Alloc>::__remove_return_type forward_list<_Tp, _Allo template template -typename forward_list<_Tp, _Alloc>::__remove_return_type +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::__remove_return_type forward_list<_Tp, _Alloc>::unique(_BinaryPredicate __binary_pred) { forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing typename forward_list<_Tp, _Alloc>::size_type __count_removed = 0; @@ -1384,7 +1446,7 @@ forward_list<_Tp, _Alloc>::unique(_BinaryPredicate __binary_pred) { template template -void forward_list<_Tp, _Alloc>::merge(forward_list& __x, _Compare __comp) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::merge(forward_list& __x, _Compare __comp) { if (this != std::addressof(__x)) { __base::__before_begin()->__next_ = __merge(__base::__before_begin()->__next_, __x.__before_begin()->__next_, __comp); @@ -1394,7 +1456,7 @@ void forward_list<_Tp, _Alloc>::merge(forward_list& __x, _Compare __comp) { template template -typename forward_list<_Tp, _Alloc>::__node_pointer +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::__node_pointer forward_list<_Tp, _Alloc>::__merge(__node_pointer __f1, __node_pointer __f2, _Compare& __comp) { if (__f1 == nullptr) return __f2; @@ -1431,13 +1493,13 @@ forward_list<_Tp, _Alloc>::__merge(__node_pointer __f1, __node_pointer __f2, _Co template template -inline void forward_list<_Tp, _Alloc>::sort(_Compare __comp) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline void forward_list<_Tp, _Alloc>::sort(_Compare __comp) { __base::__before_begin()->__next_ = __sort(__base::__before_begin()->__next_, std::distance(begin(), end()), __comp); } template template -typename forward_list<_Tp, _Alloc>::__node_pointer +_LIBCPP_CONSTEXPR_SINCE_CXX26 typename forward_list<_Tp, _Alloc>::__node_pointer forward_list<_Tp, _Alloc>::__sort(__node_pointer __f1, difference_type __sz, _Compare& __comp) { switch (__sz) { case 0: @@ -1461,7 +1523,7 @@ forward_list<_Tp, _Alloc>::__sort(__node_pointer __f1, difference_type __sz, _Co } template -void forward_list<_Tp, _Alloc>::reverse() _NOEXCEPT { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void forward_list<_Tp, _Alloc>::reverse() _NOEXCEPT { __node_pointer __p = __base::__before_begin()->__next_; if (__p != nullptr) { __node_pointer __f = __p->__next_; @@ -1477,7 +1539,8 @@ void forward_list<_Tp, _Alloc>::reverse() _NOEXCEPT { } template -_LIBCPP_HIDE_FROM_ABI bool operator==(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool +operator==(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { typedef forward_list<_Tp, _Alloc> _Cp; typedef typename _Cp::const_iterator _Ip; _Ip __ix = __x.begin(); @@ -1493,31 +1556,31 @@ _LIBCPP_HIDE_FROM_ABI bool operator==(const forward_list<_Tp, _Alloc>& __x, cons # if _LIBCPP_STD_VER <= 17 template -inline _LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { return !(__x == __y); } template -inline _LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI bool operator<(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { return std::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end()); } template -inline _LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI bool operator>(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { return __y < __x; } template -inline _LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { return !(__x < __y); } template -inline _LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc>& __y) { return !(__y < __x); } @@ -1525,7 +1588,7 @@ operator<=(const forward_list<_Tp, _Alloc>& __x, const forward_list<_Tp, _Alloc> # else // #if _LIBCPP_STD_VER <= 17 template -_LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp> +_LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp> operator<=>(const forward_list<_Tp, _Allocator>& __x, const forward_list<_Tp, _Allocator>& __y) { return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } @@ -1533,20 +1596,20 @@ operator<=>(const forward_list<_Tp, _Allocator>& __x, const forward_list<_Tp, _A # endif // #if _LIBCPP_STD_VER <= 17 template -inline _LIBCPP_HIDE_FROM_ABI void swap(forward_list<_Tp, _Alloc>& __x, forward_list<_Tp, _Alloc>& __y) - _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI void +swap(forward_list<_Tp, _Alloc>& __x, forward_list<_Tp, _Alloc>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } # if _LIBCPP_STD_VER >= 20 template -inline _LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Allocator>::size_type +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Allocator>::size_type erase_if(forward_list<_Tp, _Allocator>& __c, _Predicate __pred) { return __c.remove_if(__pred); } template -inline _LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Allocator>::size_type +_LIBCPP_CONSTEXPR_SINCE_CXX26 inline _LIBCPP_HIDE_FROM_ABI typename forward_list<_Tp, _Allocator>::size_type erase(forward_list<_Tp, _Allocator>& __c, const _Up& __v) { return std::erase_if(__c, [&](const auto& __elem) -> bool { return __elem == __v; }); } diff --git a/libcxx/include/fstream b/libcxx/include/fstream index 71c4957b691a6..00aa00ff7e9cd 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -696,7 +696,7 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char* if (!__mdstr) return nullptr; - return __do_open(fopen(__s, __mdstr), __mode); + return __do_open(std::fopen(__s, __mdstr), __mode); } template @@ -761,7 +761,7 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> std::memmove(this->eback(), this->egptr() - __unget_sz, __unget_sz * sizeof(char_type)); if (__always_noconv_) { size_t __nmemb = static_cast(this->egptr() - this->eback() - __unget_sz); - __nmemb = ::fread(this->eback() + __unget_sz, 1, __nmemb, __file_); + __nmemb = std::fread(this->eback() + __unget_sz, 1, __nmemb, __file_); if (__nmemb != 0) { this->setg(this->eback(), this->eback() + __unget_sz, this->eback() + __unget_sz + __nmemb); __c = traits_type::to_int_type(*this->gptr()); @@ -778,7 +778,7 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> std::min(static_cast(__ibs_ - __unget_sz), static_cast(__extbufend_ - __extbufnext_)); codecvt_base::result __r; __st_last_ = __st_; - size_t __nr = fread((void*)const_cast(__extbufnext_), 1, __nmemb, __file_); + size_t __nr = std::fread((void*)const_cast(__extbufnext_), 1, __nmemb, __file_); if (__nr != 0) { if (!__cv_) std::__throw_bad_cast(); @@ -855,7 +855,7 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> return traits_type::eof(); } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) { size_t __nmemb = static_cast(__extbe - __extbuf_); - if (fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb) + if (std::fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb) return traits_type::eof(); if (__r == codecvt_base::partial) { this->setp(const_cast(__e), this->pptr()); @@ -990,12 +990,12 @@ int basic_filebuf<_CharT, _Traits>::sync() { char* __extbe; __r = __cv_->unshift(__st_, __extbuf_, __extbuf_ + __ebs_, __extbe); size_t __nmemb = static_cast(__extbe - __extbuf_); - if (fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb) + if (std::fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb) return -1; } while (__r == codecvt_base::partial); if (__r == codecvt_base::error) return -1; - if (fflush(__file_)) + if (std::fflush(__file_)) return -1; } else if (__cm_ & ios_base::in) { off_type __c; diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 7f625cefed1c2..f5fd970934e9b 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -94,6 +94,7 @@ module std_core [system] { module extent { header "__type_traits/extent.h" } module has_unique_object_representation { header "__type_traits/has_unique_object_representation.h" } module has_virtual_destructor { header "__type_traits/has_virtual_destructor.h" } + module integer_traits { header "__type_traits/integer_traits.h" } module integral_constant { header "__type_traits/integral_constant.h" } module invoke { header "__type_traits/invoke.h" } module is_abstract { @@ -284,10 +285,6 @@ module std_core [system] { header "__type_traits/is_scalar.h" export std_core.type_traits.integral_constant } - module is_signed_integer { - header "__type_traits/is_signed_integer.h" - export std_core.type_traits.integral_constant - } module is_signed { header "__type_traits/is_signed.h" export std_core.type_traits.integral_constant @@ -340,10 +337,6 @@ module std_core [system] { header "__type_traits/is_union.h" export std_core.type_traits.integral_constant } - module is_unsigned_integer { - header "__type_traits/is_unsigned_integer.h" - export std_core.type_traits.integral_constant - } module is_unsigned { header "__type_traits/is_unsigned.h" export std_core.type_traits.integral_constant diff --git a/libcxx/include/streambuf b/libcxx/include/streambuf index e25647909378e..585ae7af65aa8 100644 --- a/libcxx/include/streambuf +++ b/libcxx/include/streambuf @@ -178,8 +178,8 @@ public: // Get and put areas: // 27.6.2.2.3 Get area: inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() { - if (__ninp_ < __einp_) - return static_cast(__einp_ - __ninp_); + if (gptr() < egptr()) + return static_cast(egptr() - gptr()); return showmanyc(); } @@ -190,37 +190,42 @@ public: } inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() { - if (__ninp_ == __einp_) + if (gptr() == egptr()) return uflow(); - return traits_type::to_int_type(*__ninp_++); + int_type __c = traits_type::to_int_type(*gptr()); + this->gbump(1); + return __c; } inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() { - if (__ninp_ == __einp_) + if (gptr() == egptr()) return underflow(); - return traits_type::to_int_type(*__ninp_); + return traits_type::to_int_type(*gptr()); } inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); } // 27.6.2.2.4 Putback: inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) { - if (__binp_ == __ninp_ || !traits_type::eq(__c, __ninp_[-1])) + if (eback() == gptr() || !traits_type::eq(__c, *(gptr() - 1))) return pbackfail(traits_type::to_int_type(__c)); - return traits_type::to_int_type(*--__ninp_); + this->gbump(-1); + return traits_type::to_int_type(*gptr()); } inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() { - if (__binp_ == __ninp_) + if (eback() == gptr()) return pbackfail(); - return traits_type::to_int_type(*--__ninp_); + this->gbump(-1); + return traits_type::to_int_type(*gptr()); } // 27.6.2.2.5 Put area: inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) { - if (__nout_ == __eout_) + if (pptr() == epptr()) return overflow(traits_type::to_int_type(__c)); - *__nout_++ = __c; + *pptr() = __c; + this->pbump(1); return traits_type::to_int_type(__c); } @@ -312,17 +317,16 @@ protected: virtual streamsize showmanyc() { return 0; } virtual streamsize xsgetn(char_type* __s, streamsize __n) { - const int_type __eof = traits_type::eof(); int_type __c; streamsize __i = 0; while (__i < __n) { - if (__ninp_ < __einp_) { - const streamsize __len = std::min(static_cast(INT_MAX), std::min(__einp_ - __ninp_, __n - __i)); - traits_type::copy(__s, __ninp_, __len); + if (gptr() < egptr()) { + const streamsize __len = std::min(static_cast(INT_MAX), std::min(egptr() - gptr(), __n - __i)); + traits_type::copy(__s, gptr(), __len); __s += __len; __i += __len; this->gbump(__len); - } else if ((__c = uflow()) != __eof) { + } else if ((__c = uflow()) != traits_type::eof()) { *__s = traits_type::to_char_type(__c); ++__s; ++__i; @@ -336,7 +340,9 @@ protected: virtual int_type uflow() { if (underflow() == traits_type::eof()) return traits_type::eof(); - return traits_type::to_int_type(*__ninp_++); + int_type __c = traits_type::to_int_type(*gptr()); + this->gbump(1); + return __c; } // 27.6.2.4.4 Putback: @@ -345,17 +351,16 @@ protected: // 27.6.2.4.5 Put area: virtual streamsize xsputn(const char_type* __s, streamsize __n) { streamsize __i = 0; - int_type __eof = traits_type::eof(); while (__i < __n) { - if (__nout_ >= __eout_) { - if (overflow(traits_type::to_int_type(*__s)) == __eof) + if (pptr() >= epptr()) { + if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof()) break; ++__s; ++__i; } else { - streamsize __chunk_size = std::min(__eout_ - __nout_, __n - __i); - traits_type::copy(__nout_, __s, __chunk_size); - __nout_ += __chunk_size; + streamsize __chunk_size = std::min(epptr() - pptr(), __n - __i); + traits_type::copy(pptr(), __s, __chunk_size); + __pbump(__chunk_size); __s += __chunk_size; __i += __chunk_size; } diff --git a/libcxx/include/version b/libcxx/include/version index 65fae111dc8ed..87c4ede9a7e59 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -68,6 +68,7 @@ __cpp_lib_constexpr_charconv 202207L __cpp_lib_constexpr_cmath 202202L __cpp_lib_constexpr_complex 201711L __cpp_lib_constexpr_dynamic_alloc 201907L +__cpp_lib_constexpr_forward_list 202502L __cpp_lib_constexpr_functional 201907L __cpp_lib_constexpr_iterator 201811L __cpp_lib_constexpr_memory 202202L @@ -543,6 +544,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_bitset 202306L # undef __cpp_lib_constexpr_algorithms # define __cpp_lib_constexpr_algorithms 202306L +# define __cpp_lib_constexpr_forward_list 202502L # if !defined(_LIBCPP_ABI_VCRUNTIME) # define __cpp_lib_constexpr_new 202406L # endif diff --git a/libcxx/src/experimental/time_zone.cpp b/libcxx/src/experimental/time_zone.cpp index 289164ab12036..a735800b60317 100644 --- a/libcxx/src/experimental/time_zone.cpp +++ b/libcxx/src/experimental/time_zone.cpp @@ -29,6 +29,15 @@ // These quirks often use a 12h interval; this is the scan interval of zdump, // which implies there are no sys_info objects with a duration of less than 12h. +// Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120502 + +#include <__config> + +// TODO(LLVM 23): When upgrading to GCC 16 this can be removed +#ifdef _LIBCPP_COMPILER_GCC +# pragma GCC optimize("-O0") +#endif + #include #include #include diff --git a/libcxx/src/hash.cpp b/libcxx/src/hash.cpp index 41c4eb480a5fc..e1e6d2b4c2bdb 100644 --- a/libcxx/src/hash.cpp +++ b/libcxx/src/hash.cpp @@ -9,7 +9,6 @@ #include <__hash_table> #include #include -#include _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wtautological-constant-out-of-range-compare") @@ -52,16 +51,14 @@ const unsigned indices[] = { // are fewer potential primes to search, and fewer potential primes to divide // against. -template -inline _LIBCPP_HIDE_FROM_ABI typename enable_if<_Sz == 4, void>::type __check_for_overflow(size_t N) { - if (N > 0xFFFFFFFB) - std::__throw_overflow_error("__next_prime overflow"); -} - -template -inline _LIBCPP_HIDE_FROM_ABI typename enable_if<_Sz == 8, void>::type __check_for_overflow(size_t N) { - if (N > 0xFFFFFFFFFFFFFFC5ull) - std::__throw_overflow_error("__next_prime overflow"); +inline void __check_for_overflow(size_t N) { + if constexpr (sizeof(size_t) == 4) { + if (N > 0xFFFFFFFB) + std::__throw_overflow_error("__next_prime overflow"); + } else { + if (N > 0xFFFFFFFFFFFFFFC5ull) + std::__throw_overflow_error("__next_prime overflow"); + } } size_t __next_prime(size_t n) { diff --git a/libcxx/test/configs/llvm-libc++-android-ndk.cfg.in b/libcxx/test/configs/llvm-libc++-android.cfg.in similarity index 83% rename from libcxx/test/configs/llvm-libc++-android-ndk.cfg.in rename to libcxx/test/configs/llvm-libc++-android.cfg.in index 31a07f6471651..9362c68e8f7a8 100644 --- a/libcxx/test/configs/llvm-libc++-android-ndk.cfg.in +++ b/libcxx/test/configs/llvm-libc++-android.cfg.in @@ -1,5 +1,5 @@ # This testing configuration handles running the test suite against LLVM's -# libc++ using adb and a libc++_shared.so library on Android. +# libc++ using adb on Android. lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg') @@ -27,11 +27,11 @@ if re.match(r'i686-linux-android(21|22|23)$', config.target_triple): compile_flags += ' -mstackrealign' config.substitutions.append(('%{compile_flags}', compile_flags)) -# The NDK library is called "libc++_shared.so". Use LD_LIBRARY_PATH to find -# libc++_shared.so because older Bionic dynamic loaders don't support rpath -# lookup. +# The platform library is called "libc++.so" and the NDK library is called "libc++_shared.so". +# Use LD_LIBRARY_PATH to find the libcxx shared object because older Bionic dynamic loaders +# don't support rpath lookup. config.substitutions.append(('%{link_flags}', - '-nostdlib++ -L %{lib-dir} -lc++_shared' + '-nostdlib++ -L %{lib-dir} -l@LIBCXX_SHARED_OUTPUT_NAME@' )) config.substitutions.append(('%{exec}', '%{executor}' + diff --git a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_integer.compile.pass.cpp b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_integer.compile.pass.cpp index 563580b687955..4958a258137a1 100644 --- a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_integer.compile.pass.cpp +++ b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_integer.compile.pass.cpp @@ -11,9 +11,9 @@ // Concept helpers for the internal type traits for the fundamental types. // template -// concept __libcpp_integer; +// concept __signed_or_unsigned_integer; -#include +#include <__type_traits/integer_traits.h> #include "test_macros.h" @@ -24,40 +24,40 @@ enum SomeEnum {}; enum class SomeScopedEnum {}; // Unsigned -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); #if _LIBCPP_HAS_INT128 -static_assert(std::__libcpp_integer<__uint128_t>); +static_assert(std::__signed_or_unsigned_integer<__uint128_t>); #endif // Signed -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); -static_assert(std::__libcpp_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); +static_assert(std::__signed_or_unsigned_integer); #if _LIBCPP_HAS_INT128 -static_assert(std::__libcpp_integer<__int128_t>); +static_assert(std::__signed_or_unsigned_integer<__int128_t>); #endif // Non-integer -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); #ifndef TEST_HAS_NO_WIDE_CHARACTERS -static_assert(!std::__libcpp_integer); +static_assert(!std::__signed_or_unsigned_integer); #endif -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); -static_assert(!std::__libcpp_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); +static_assert(!std::__signed_or_unsigned_integer); diff --git a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp index d1e21ee96b073..3fa342685770c 100644 --- a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp +++ b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp @@ -11,9 +11,9 @@ // Concept helpers for the internal type traits for the fundamental types. // template -// concept __libcpp_signed_integer; +// concept __signed_integer; -#include +#include <__type_traits/integer_traits.h> #include "test_macros.h" @@ -24,40 +24,40 @@ enum SomeEnum {}; enum class SomeScopedEnum {}; // Unsigned -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); #if _LIBCPP_HAS_INT128 -static_assert(!std::__libcpp_signed_integer<__uint128_t>); +static_assert(!std::__signed_integer<__uint128_t>); #endif // Signed -static_assert(std::__libcpp_signed_integer); -static_assert(std::__libcpp_signed_integer); -static_assert(std::__libcpp_signed_integer); -static_assert(std::__libcpp_signed_integer); -static_assert(std::__libcpp_signed_integer); -static_assert(std::__libcpp_signed_integer); +static_assert(std::__signed_integer); +static_assert(std::__signed_integer); +static_assert(std::__signed_integer); +static_assert(std::__signed_integer); +static_assert(std::__signed_integer); +static_assert(std::__signed_integer); #if _LIBCPP_HAS_INT128 -static_assert(std::__libcpp_signed_integer<__int128_t>); +static_assert(std::__signed_integer<__int128_t>); #endif // Non-integer -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); #ifndef TEST_HAS_NO_WIDE_CHARACTERS -static_assert(!std::__libcpp_signed_integer); +static_assert(!std::__signed_integer); #endif -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); -static_assert(!std::__libcpp_signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); +static_assert(!std::__signed_integer); diff --git a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp index c671f03cbfce4..ff60f32319171 100644 --- a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp +++ b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp @@ -11,9 +11,9 @@ // Concept helpers for the internal type traits for the fundamental types. // template -// concept __libcpp_unsigned_integer; +// concept __unsigned_integer; -#include +#include <__type_traits/integer_traits.h> #include "test_macros.h" @@ -24,40 +24,40 @@ enum SomeEnum {}; enum class SomeScopedEnum {}; // Unsigned -static_assert(std::__libcpp_unsigned_integer); -static_assert(std::__libcpp_unsigned_integer); -static_assert(std::__libcpp_unsigned_integer); -static_assert(std::__libcpp_unsigned_integer); -static_assert(std::__libcpp_unsigned_integer); -static_assert(std::__libcpp_unsigned_integer); +static_assert(std::__unsigned_integer); +static_assert(std::__unsigned_integer); +static_assert(std::__unsigned_integer); +static_assert(std::__unsigned_integer); +static_assert(std::__unsigned_integer); +static_assert(std::__unsigned_integer); #if _LIBCPP_HAS_INT128 -static_assert(std::__libcpp_unsigned_integer<__uint128_t>); +static_assert(std::__unsigned_integer<__uint128_t>); #endif // Signed -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); #if _LIBCPP_HAS_INT128 -static_assert(!std::__libcpp_unsigned_integer<__int128_t>); +static_assert(!std::__unsigned_integer<__int128_t>); #endif // Non-integer -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); #ifndef TEST_HAS_NO_WIDE_CHARACTERS -static_assert(!std::__libcpp_unsigned_integer); +static_assert(!std::__unsigned_integer); #endif -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); -static_assert(!std::__libcpp_unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); +static_assert(!std::__unsigned_integer); diff --git a/libcxx/test/libcxx/containers/container.adaptors/flat.set/scary.compile.pass.cpp b/libcxx/test/libcxx/containers/container.adaptors/flat.set/scary.compile.pass.cpp new file mode 100644 index 0000000000000..99e93fc3b08b9 --- /dev/null +++ b/libcxx/test/libcxx/containers/container.adaptors/flat.set/scary.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class flat_set +// class flat_multiset + +// Extension: SCARY/N2913 iterator compatibility between flat_set and flat_multiset +// Test for the absence of this feature + +#include +#include + +#include "test_macros.h" + +void test() { + typedef std::flat_set M1; + typedef std::flat_multiset M2; + + static_assert(!std::is_convertible_v); + static_assert(!std::is_convertible_v); + + static_assert(!std::is_convertible_v); + static_assert(!std::is_convertible_v); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp index 08d8e119a4d24..1e89cd272e643 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp @@ -195,7 +195,7 @@ constexpr bool test() { std::string a[] = {str1, str1, str, str1, str1}; auto whole = std::ranges::subrange(forward_iterator(std::move_iterator(a)), forward_iterator(std::move_iterator(a + 5))); - bool ret = std::ranges::contains(whole.begin(), whole.end(), "hello world", [&](const std::string i) { + bool ret = std::ranges::contains(whole.begin(), whole.end(), +"hello world", [&](const std::string i) { ++projection_count; return i; }); @@ -207,7 +207,7 @@ constexpr bool test() { std::string a[] = {str1, str1, str, str1, str1}; auto whole = std::ranges::subrange(forward_iterator(std::move_iterator(a)), forward_iterator(std::move_iterator(a + 5))); - bool ret = std::ranges::contains(whole, "hello world", [&](const std::string i) { + bool ret = std::ranges::contains(whole, +"hello world", [&](const std::string i) { ++projection_count; return i; }); diff --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp index ca0f40eb77d49..0531c0e096a13 100644 --- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp @@ -26,6 +26,7 @@ #include #include "compare_types.h" +#include "test_macros.h" namespace fundamentals { static_assert(std::equality_comparable); @@ -43,7 +44,12 @@ static_assert(std::equality_comparable); static_assert(std::equality_comparable); static_assert(std::equality_comparable); static_assert(std::equality_comparable); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(std::equality_comparable); +#else +static_assert(!std::equality_comparable); +#endif static_assert(std::equality_comparable); static_assert(std::equality_comparable); static_assert(std::equality_comparable); diff --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp index 0afbe582ba896..2f8d7862c0f4d 100644 --- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp @@ -107,7 +107,12 @@ static_assert(!check_equality_comparable_with < int, int (S::*)() const volatile&& noexcept > ()); static_assert(check_equality_comparable_with()); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(check_equality_comparable_with()); +#else +static_assert(!check_equality_comparable_with()); +#endif static_assert(!check_equality_comparable_with()); static_assert(!check_equality_comparable_with()); static_assert(!check_equality_comparable_with()); @@ -148,7 +153,12 @@ static_assert( static_assert(!check_equality_comparable_with < int*, int (S::*)() const volatile&& noexcept > ()); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(check_equality_comparable_with()); +#else +static_assert(!check_equality_comparable_with()); +#endif static_assert(!check_equality_comparable_with()); static_assert(!check_equality_comparable_with()); static_assert(!check_equality_comparable_with()); @@ -942,7 +952,12 @@ static_assert( static_assert(!check_equality_comparable_with()); static_assert(check_equality_comparable_with()); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(check_equality_comparable_with()); +#else +static_assert(!check_equality_comparable_with()); +#endif static_assert(check_equality_comparable_with()); static_assert(check_equality_comparable_with()); static_assert(check_equality_comparable_with()); diff --git a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.compile.pass.cpp index 6f8324eaf7647..5959f70cf3963 100644 --- a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.compile.pass.cpp @@ -55,7 +55,10 @@ static_assert(models_totally_ordered()); static_assert(models_totally_ordered()); static_assert(models_totally_ordered()); static_assert(models_totally_ordered()); +// Array comparisons are ill-formed in C++26 +#if TEST_STD_VER <= 23 static_assert(models_totally_ordered()); +#endif static_assert(models_totally_ordered()); static_assert(models_totally_ordered()); static_assert(models_totally_ordered()); diff --git a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.compile.pass.cpp index dffc33265aebf..398ef445baf9d 100644 --- a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.compile.pass.cpp @@ -89,7 +89,12 @@ static_assert(!check_totally_ordered_with()) static_assert(!check_totally_ordered_with < int, int (S::*)() const volatile&& noexcept > ()); static_assert(check_totally_ordered_with()); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(check_totally_ordered_with()); +#else +static_assert(!check_totally_ordered_with()); +#endif static_assert(!check_totally_ordered_with()); static_assert(!check_totally_ordered_with()); static_assert(!check_totally_ordered_with()); @@ -117,7 +122,12 @@ static_assert(!check_totally_ordered_with < int*, int (S::*)() volatile&& noexce static_assert(!check_totally_ordered_with()); static_assert(!check_totally_ordered_with < int*, int (S::*)() const volatile&& noexcept > ()); +// Array comparisons are ill-formed in C++26, but Clang doesn't implement this yet. +#if TEST_STD_VER <= 23 || defined(TEST_COMPILER_CLANG) static_assert(check_totally_ordered_with()); +#else +static_assert(!check_totally_ordered_with()); +#endif static_assert(!check_totally_ordered_with()); static_assert(!check_totally_ordered_with()); static_assert(!check_totally_ordered_with()); diff --git a/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp index 01be1db73041b..671747f89a82e 100644 --- a/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp @@ -26,7 +26,6 @@ constexpr std::size_t N{1}; static_assert(std::three_way_comparable>); // Thanks to SFINAE, the following is not a compiler error but returns `false` -struct NonComparable {}; static_assert(!std::three_way_comparable>); // Implementation detail of `test_sequence_container_array_spaceship` diff --git a/libcxx/test/std/containers/sequences/forwardlist/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/compare.three_way.pass.cpp index 52adfc4d85985..a9ef855e9a73e 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/compare.three_way.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/compare.three_way.pass.cpp @@ -11,7 +11,7 @@ // template // synth-three-way-result operator<=>(const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 #include #include @@ -20,6 +20,9 @@ int main(int, char**) { assert(test_sequence_container_spaceship()); - // `std::forward_list` is not constexpr, so no `static_assert` test here. +#if TEST_STD_VER >= 26 + static_assert(test_sequence_container_spaceship()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/empty.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/empty.pass.cpp index dbc0631d11930..4482d26f308a6 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/empty.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/empty.pass.cpp @@ -10,7 +10,7 @@ // class forward_list -// bool empty() const noexcept; +// bool empty() const noexcept; // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef std::forward_list C; C c; @@ -42,5 +42,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.access/front.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.access/front.pass.cpp index 757db7d957f5f..50b549f17d561 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.access/front.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.access/front.pass.cpp @@ -8,17 +8,18 @@ // -// reference front(); -// const_reference front() const; +// reference front(); // constexpr since C++26 +// const_reference front() const; // constexpr since C++26 #include #include #include +#include "test_allocator.h" #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -58,5 +59,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.compile.fail.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.compile.fail.cpp index 31893a1b95994..4645560048cf6 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.compile.fail.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.compile.fail.cpp @@ -8,7 +8,7 @@ // -// explicit forward_list(const allocator_type& a); +// explicit forward_list(const allocator_type& a); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_allocator.h" #include "../../../NotConstructible.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef test_allocator A; typedef A::value_type T; @@ -26,5 +26,14 @@ int main(int, char**) { assert(c.empty()); } + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.pass.cpp index bfb330fdaf9fc..ffc6d37f28160 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/alloc.pass.cpp @@ -8,7 +8,7 @@ // -// explicit forward_list(const allocator_type& a); +// explicit forward_list(const allocator_type& a); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "../../../NotConstructible.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef test_allocator A; typedef A::value_type T; @@ -46,5 +46,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_copy.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_copy.pass.cpp index 27d450c63dcae..b99af4ccb79ec 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_copy.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list& operator=(const forward_list& x); +// forward_list& operator=(const forward_list& x); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -143,5 +143,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_init.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_init.pass.cpp index 1cdcca82d3352..ea2802b323a91 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_init.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_init.pass.cpp @@ -10,7 +10,7 @@ // -// void assign(initializer_list il); +// void assign(initializer_list il); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -65,5 +65,14 @@ int main(int, char**) { assert(n == 4); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_move.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_move.pass.cpp index 998a7e11ef343..9c88db6166ba7 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_move.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_move.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list& operator=(forward_list&& x); +// forward_list& operator=(forward_list&& x); // constexpr since C++26 #include #include @@ -21,7 +21,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef MoveOnly T; typedef test_allocator A; @@ -194,5 +194,14 @@ int main(int, char**) { assert(c0.empty()); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_op_init.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_op_init.pass.cpp index a22d6c4985bc5..d21898dc4663a 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_op_init.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_op_init.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list& operator=(initializer_list il); +// forward_list& operator=(initializer_list il); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -65,5 +65,14 @@ int main(int, char**) { assert(n == 4); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_range.pass.cpp index 9a35328740790..1601b4b47acd1 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_range.pass.cpp @@ -9,7 +9,7 @@ // // template -// void assign(InputIterator first, InputIterator last); +// void assign(InputIterator first, InputIterator last); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_iterators.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -75,5 +75,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_size_value.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_size_value.pass.cpp index b0fbfa3249e5e..75626b47c5273 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/assign_size_value.pass.cpp @@ -8,7 +8,7 @@ // -// void assign(size_type n, const value_type& v); +// void assign(size_type n, const value_type& v); // constexpr since C++26 #include #include @@ -17,7 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -65,5 +65,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy.pass.cpp index 22d5054b9ae18..12d701bff4b68 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list(const forward_list& x); +// forward_list(const forward_list& x); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -64,5 +64,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy_alloc.pass.cpp index a61233e4b5d22..fc3ff485b0667 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/copy_alloc.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list(const forward_list& x, const allocator_type& a); +// forward_list(const forward_list& x, const allocator_type& a); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -64,5 +64,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/default.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/default.pass.cpp index b493a89b78003..e0ea8bf66cb3b 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/default.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/default.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list(); +// forward_list(); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -38,5 +38,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/from_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/from_range.pass.cpp index 312f6dbad3550..d1e1734e86f9f 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/from_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/from_range.pass.cpp @@ -9,14 +9,14 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // template R> -// forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23 +// forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23; constexpr since C++26 #include #include "../../from_range_sequence_containers.h" #include "test_macros.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { for_all_iterators_and_allocators([]() { test_sequence_container([](const auto&) { // No additional validation to do. @@ -26,8 +26,19 @@ int main(int, char**) { static_assert(test_constraints()); - test_exception_safety_throwing_copy(); - test_exception_safety_throwing_allocator(); + if (!TEST_IS_CONSTANT_EVALUATED) { + test_exception_safety_throwing_copy(); + test_exception_safety_throwing_allocator(); + } + + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init.pass.cpp index b42242b0a83d4..b7acf60aa70cc 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list(initializer_list il); +// forward_list(initializer_list il); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -38,5 +38,14 @@ int main(int, char**) { assert(n == 10); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init_alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init_alloc.pass.cpp index 0b29cbfa9254d..33d569c921a94 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/init_alloc.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list(initializer_list il, const allocator_type& a); +// forward_list(initializer_list il, const allocator_type& a); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -43,5 +43,14 @@ int main(int, char**) { assert(c.get_allocator() == A()); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move.pass.cpp index 762e252ca76fe..20575479f7357 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list(forward_list&& x); +// forward_list(forward_list&& x); // constexpr since C++26 #include #include @@ -21,7 +21,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef MoveOnly T; typedef test_allocator A; @@ -68,5 +68,14 @@ int main(int, char**) { assert(c.get_allocator() == A()); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_alloc.pass.cpp index a9bc2cb12f288..219505bf4fd17 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_alloc.pass.cpp @@ -10,7 +10,7 @@ // -// forward_list(forward_list&& x, const allocator_type& a); +// forward_list(forward_list&& x, const allocator_type& a); // constexpr since C++26 #include #include @@ -21,7 +21,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef MoveOnly T; typedef test_allocator A; @@ -68,5 +68,14 @@ int main(int, char**) { assert(c.get_allocator() == A()); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range.pass.cpp index ebd0e6a5bd1e0..61393eb28938e 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range.pass.cpp @@ -9,7 +9,7 @@ // // template -// forward_list(InputIterator first, InputIterator last); +// forward_list(InputIterator first, InputIterator last); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_iterators.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -45,5 +45,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range_alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range_alloc.pass.cpp index 4a28041ad2cbc..c0637420e328a 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/range_alloc.pass.cpp @@ -10,7 +10,7 @@ // template // forward_list(InputIterator first, InputIterator last, -// const allocator_type& a); +// const allocator_type& a); // constexpr since C++26 #include #include @@ -21,7 +21,7 @@ #include "test_iterators.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -51,5 +51,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp index 81b128d2149e3..206854560c19f 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp @@ -8,8 +8,8 @@ // -// explicit forward_list(size_type n); -// explicit forward_list(size_type n, const Alloc& a); +// explicit forward_list(size_type n); // constexpr since C++26 +// explicit forward_list(size_type n, const Alloc& a); // constexpr since C++26 #include #include diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value.pass.cpp index 663422d1c3c30..85d11e3f40a2f 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list(size_type n, const value_type& v); +// forward_list(size_type n, const value_type& v); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -42,5 +42,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value_alloc.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value_alloc.pass.cpp index af7f7471d4c98..abcdf62452b89 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size_value_alloc.pass.cpp @@ -8,7 +8,7 @@ // -// forward_list(size_type n, const value_type& v, const allocator_type& a); +// forward_list(size_type n, const value_type& v, const allocator_type& a); // constexpr since C++26 #include #include @@ -17,7 +17,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef test_allocator A; typedef A::value_type T; @@ -47,5 +47,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp index 1044d779220ee..86d7769fe16ee 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp @@ -11,7 +11,7 @@ // template // typename forward_list::size_type -// erase(forward_list& c, const U& value); +// erase(forward_list& c, const U& value); // constexpr since C++26 #include #include @@ -21,14 +21,14 @@ #include "min_allocator.h" template -void test0(S s, U val, S expected, std::size_t expected_erased_count) { +TEST_CONSTEXPR_CXX26 void test0(S s, U val, S expected, std::size_t expected_erased_count) { ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val))); assert(expected_erased_count == std::erase(s, val)); assert(s == expected); } template -void test() { +TEST_CONSTEXPR_CXX26 void test() { test0(S(), 1, S(), 0); test0(S({1}), 1, S(), 1); @@ -62,13 +62,21 @@ void test() { test0(S({1, 2, 1}), opt(3), S({1, 2, 1}), 0); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { test>(); test>>(); test>>(); - test>(); test>(); + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp index c4f45a1069a2b..c665f9cccbf0a 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp @@ -11,7 +11,7 @@ // template // typename forward_list::size_type -// erase_if(forward_list& c, Predicate pred); +// erase_if(forward_list& c, Predicate pred); // constexpr since C++26 #include @@ -20,14 +20,14 @@ #include "min_allocator.h" template -void test0(S s, Pred p, S expected, std::size_t expected_erased_count) { +TEST_CONSTEXPR_CXX26 void test0(S s, Pred p, S expected, std::size_t expected_erased_count) { ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p))); assert(expected_erased_count == std::erase_if(s, p)); assert(s == expected); } template -void test() { +TEST_CONSTEXPR_CXX26 void test() { auto is1 = [](auto v) { return v == 1; }; auto is2 = [](auto v) { return v == 2; }; auto is3 = [](auto v) { return v == 3; }; @@ -64,13 +64,21 @@ void test() { test0(S({1, 2, 3}), False, S({1, 2, 3}), 0); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { test>(); test>>(); test>>(); - test>(); test>(); + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/before_begin.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/before_begin.pass.cpp index d66d2cd879515..52b5d87860aab 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/before_begin.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/before_begin.pass.cpp @@ -8,9 +8,9 @@ // -// iterator before_begin(); -// const_iterator before_begin() const; -// const_iterator cbefore_begin() const; +// iterator before_begin(); // constexpr since C++26 +// const_iterator before_begin() const; // constexpr since C++26 +// const_iterator cbefore_begin() const; // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -101,5 +101,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp index 135689b2321c3..560c47b17958f 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterators.pass.cpp @@ -8,12 +8,12 @@ // -// iterator begin(); -// iterator end(); -// const_iterator begin() const; -// const_iterator end() const; -// const_iterator cbegin() const; -// const_iterator cend() const; +// iterator begin(); // constexpr since C++26 +// iterator end(); // constexpr since C++26 +// const_iterator begin() const; // constexpr since C++26 +// const_iterator end() const; // constexpr since C++26 +// const_iterator cbegin() const; // constexpr since C++26 +// const_iterator cend() const; // constexpr since C++26 #include #include @@ -22,7 +22,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -69,6 +69,8 @@ int main(int, char**) { typedef std::forward_list C; C::iterator i; C::const_iterator j; + (void)i; + (void)j; } #if TEST_STD_VER >= 11 { @@ -117,6 +119,8 @@ int main(int, char**) { typedef std::forward_list> C; C::iterator i; C::const_iterator j; + (void)i; + (void)j; } #endif #if TEST_STD_VER > 11 @@ -142,5 +146,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/assign_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/assign_range.pass.cpp index a27cc757025b5..9a3adec1d9756 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/assign_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/assign_range.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // template R> -// constexpr void prepend_range(R&& rg); // C++23 +// constexpr void prepend_range(R&& rg); // C++23; constexpr since C++26 #include @@ -21,7 +21,7 @@ // {empty/one-element/full} container); // - prepending move-only elements; // - an exception is thrown when copying the elements or when allocating new elements. -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { static_assert(test_constraints_assign_range()); for_all_iterators_and_allocators([]() { @@ -31,8 +31,19 @@ int main(int, char**) { }); test_sequence_prepend_range_move_only(); - test_prepend_range_exception_safety_throwing_copy(); - test_prepend_range_exception_safety_throwing_allocator(); + if (!TEST_IS_CONSTANT_EVALUATED) { + test_prepend_range_exception_safety_throwing_copy(); + test_prepend_range_exception_safety_throwing_allocator(); + } + + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/clear.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/clear.pass.cpp index 9f6d34b701df7..2e1768cf8bad9 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/clear.pass.cpp @@ -8,7 +8,7 @@ // -// void clear() noexcept; +// void clear() noexcept; // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "../../../NotConstructible.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef NotConstructible T; typedef std::forward_list C; @@ -64,5 +64,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_after.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_after.pass.cpp index f77d47ee7c74f..6433607af9b39 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_after.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_after.pass.cpp @@ -11,7 +11,7 @@ // // template -// iterator emplace_after(const_iterator p, Args&&... args); +// iterator emplace_after(const_iterator p, Args&&... args); // constexpr since C++26 #include #include @@ -20,7 +20,7 @@ #include "../../../Emplaceable.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef Emplaceable T; typedef std::forward_list C; @@ -84,5 +84,14 @@ int main(int, char**) { assert(std::distance(c.begin(), c.end()) == 4); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_front.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_front.pass.cpp index cd3bb20c52ae5..46ae27b43622e 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_front.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/emplace_front.pass.cpp @@ -10,7 +10,7 @@ // -// template reference emplace_front(Args&&... args); +// template reference emplace_front(Args&&... args); // constexpr since C++26 // return type is 'reference' in C++17; 'void' before #include @@ -21,7 +21,7 @@ #include "../../../Emplaceable.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef Emplaceable T; typedef std::forward_list C; @@ -67,5 +67,14 @@ int main(int, char**) { assert(std::distance(c.begin(), c.end()) == 2); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_many.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_many.pass.cpp index e85951798526d..73cb03c2cb7d2 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_many.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_many.pass.cpp @@ -8,7 +8,7 @@ // -// iterator erase_after(const_iterator first, const_iterator last); +// iterator erase_after(const_iterator first, const_iterator last); // constexpr since C++26 #include #include @@ -17,7 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -153,5 +153,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_one.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_one.pass.cpp index 892228e76def7..12997f1dad3b9 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_one.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/erase_after_one.pass.cpp @@ -8,7 +8,7 @@ // -// iterator erase_after(const_iterator p); +// iterator erase_after(const_iterator p); // constexpr since C++26 #include #include @@ -17,7 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -95,5 +95,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_const.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_const.pass.cpp index 8443158413e7f..d93789dd6bb5c 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_const.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_const.pass.cpp @@ -8,7 +8,7 @@ // -// iterator insert_after(const_iterator p, const value_type& v); +// iterator insert_after(const_iterator p, const value_type& v); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -84,5 +84,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_init.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_init.pass.cpp index de924a10c18f0..54be47f4264ff 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_init.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_init.pass.cpp @@ -10,7 +10,7 @@ // -// iterator insert_after(const_iterator p, initializer_list il); +// iterator insert_after(const_iterator p, initializer_list il); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -70,5 +70,14 @@ int main(int, char**) { assert(*std::next(c.begin(), 4) == 2); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_range.pass.cpp index af810d0f6961c..f89fbd7619da2 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_range.pass.cpp @@ -10,7 +10,7 @@ // template // iterator insert_after(const_iterator p, -// InputIterator first, InputIterator last); +// InputIterator first, InputIterator last); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_iterators.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -77,5 +77,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_rv.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_rv.pass.cpp index acd4bc73f724e..01b76f5cd64f1 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_rv.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_rv.pass.cpp @@ -10,7 +10,7 @@ // -// iterator insert_after(const_iterator p, value_type&& v); +// iterator insert_after(const_iterator p, value_type&& v); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef MoveOnly T; typedef std::forward_list C; @@ -85,5 +85,14 @@ int main(int, char**) { assert(std::distance(c.begin(), c.end()) == 4); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_size_value.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_size_value.pass.cpp index 2506f04311e0e..f4f0521ad2371 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_after_size_value.pass.cpp @@ -8,7 +8,7 @@ // -// iterator insert_after(const_iterator p, size_type n, const value_type& v); +// iterator insert_after(const_iterator p, size_type n, const value_type& v); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -70,5 +70,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_range_after.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_range_after.pass.cpp index 25f4c43f38486..71a291430b435 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_range_after.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/insert_range_after.pass.cpp @@ -8,8 +8,10 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 + // template R> -// constexpr iterator insert_range_after(const_iterator position, R&& rg); // C++23 +// constexpr iterator insert_range_after(const_iterator position, R&& rg); // C++23; constexpr since C++26 #include @@ -321,7 +323,7 @@ constexpr void test_sequence_insert_range_after() { } } -void test_sequence_insert_range_after_move_only() { +TEST_CONSTEXPR_CXX26 void test_sequence_insert_range_after_move_only() { MoveOnly input[5]; std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5}); @@ -366,7 +368,7 @@ void test_insert_range_after_exception_safety_throwing_allocator() { #endif } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { static_assert(test_constraints_insert_range_after()); for_all_iterators_and_allocators([]() { @@ -374,8 +376,19 @@ int main(int, char**) { }); test_sequence_insert_range_after_move_only(); - test_insert_range_after_exception_safety_throwing_copy(); - test_insert_range_after_exception_safety_throwing_allocator(); + if (!TEST_IS_CONSTANT_EVALUATED) { + test_insert_range_after_exception_safety_throwing_copy(); + test_insert_range_after_exception_safety_throwing_allocator(); + } + + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/pop_front.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/pop_front.pass.cpp index 98c7a26341179..9fcade7ff6bba 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/pop_front.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/pop_front.pass.cpp @@ -8,7 +8,7 @@ // -// void pop_front(); +// void pop_front(); // constexpr since C++26 #include #include @@ -17,7 +17,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -71,5 +71,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/prepend_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/prepend_range.pass.cpp index 418aa72052ba9..c4b9cd9bdfc41 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/prepend_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/prepend_range.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // template R> -// constexpr void prepend_range(R&& rg); // C++23 +// constexpr void prepend_range(R&& rg); // C++23; constexpr since C++26 #include @@ -21,7 +21,7 @@ // {empty/one-element/full} container); // - prepending move-only elements; // - an exception is thrown when copying the elements or when allocating new elements. -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { static_assert(test_constraints_prepend_range()); for_all_iterators_and_allocators([]() { @@ -31,8 +31,19 @@ int main(int, char**) { }); test_sequence_prepend_range_move_only(); - test_prepend_range_exception_safety_throwing_copy(); - test_prepend_range_exception_safety_throwing_allocator(); + if (!TEST_IS_CONSTANT_EVALUATED) { + test_prepend_range_exception_safety_throwing_copy(); + test_prepend_range_exception_safety_throwing_allocator(); + } + + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_const.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_const.pass.cpp index f99c40fa0c1a0..61c5dcac0545e 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_const.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_const.pass.cpp @@ -8,7 +8,7 @@ // -// void push_front(const value_type& v); +// void push_front(const value_type& v); // constexpr since C++26 #include #include @@ -16,7 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -44,5 +44,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp index 467037465eedd..cd24d6ff6af06 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: no-exceptions // -// void push_front(const value_type& x); +// void push_front(const value_type& x); // constexpr since C++26 #include #include diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_rv.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_rv.pass.cpp index d3156c5fdd38a..b30ff7a0189e2 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_rv.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/push_front_rv.pass.cpp @@ -10,7 +10,7 @@ // -// void push_front(value_type&& v); +// void push_front(value_type&& v); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "MoveOnly.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef MoveOnly T; typedef std::forward_list C; @@ -45,5 +45,14 @@ int main(int, char**) { assert(std::distance(c.begin(), c.end()) == 2); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size.pass.cpp index 2dacf458d7d9d..f80886113bf25 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size.pass.cpp @@ -8,7 +8,7 @@ // -// void resize(size_type n); +// void resize(size_type n); // constexpr since C++26 #include #include @@ -18,8 +18,8 @@ #include "DefaultOnly.h" #include "min_allocator.h" -int main(int, char**) { - { +TEST_CONSTEXPR_CXX26 bool test() { + if (!TEST_IS_CONSTANT_EVALUATED) { typedef DefaultOnly T; typedef std::forward_list C; C c; @@ -65,7 +65,7 @@ int main(int, char**) { assert(*std::next(c.begin(), 5) == 0); } #if TEST_STD_VER >= 11 - { + if (!TEST_IS_CONSTANT_EVALUATED) { typedef DefaultOnly T; typedef std::forward_list> C; C c; @@ -112,5 +112,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size_value.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size_value.pass.cpp index a6af763e6937f..4ec859b36336d 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.modifiers/resize_size_value.pass.cpp @@ -8,7 +8,7 @@ // -// void resize(size_type n, const value_type& v); +// void resize(size_type n, const value_type& v); // constexpr since C++26 #include #include @@ -22,7 +22,7 @@ # include "container_test_types.h" #endif -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -84,7 +84,7 @@ int main(int, char**) { assert(*std::next(c.begin(), 4) == 10); assert(*std::next(c.begin(), 5) == 10); } - { + if (!TEST_IS_CONSTANT_EVALUATED) { // Test that the allocator's construct method is being used to // construct the new elements and that it's called exactly N times. typedef std::forward_list> Container; @@ -99,5 +99,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue.pass.cpp index 9a162789569d3..d8e80c56bf392 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue.pass.cpp @@ -8,7 +8,7 @@ // -// void merge(forward_list& x); +// void merge(forward_list& x); // constexpr since C++26 #include #include @@ -30,11 +30,11 @@ struct value { int a; int b; - friend bool operator<(const value& lhs, const value& rhs) { return lhs.a < rhs.a; } - friend bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } + friend TEST_CONSTEXPR bool operator<(const value& lhs, const value& rhs) { return lhs.a < rhs.a; } + friend TEST_CONSTEXPR bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // Basic merge operation. typedef int T; typedef std::forward_list C; @@ -116,5 +116,14 @@ int main(int, char**) { assert(c == std::forward_list(std::begin(a), std::end(a))); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue_pred.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue_pred.pass.cpp index 4e1814044808c..0adadb2dd092f 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue_pred.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_lvalue_pred.pass.cpp @@ -8,7 +8,7 @@ // -// template void merge(forward_list& x, Compare comp); +// template void merge(forward_list& x, Compare comp); // constexpr since C++26 #include #include @@ -30,11 +30,11 @@ struct value { int a; int b; - friend bool operator>(const value& lhs, const value& rhs) { return lhs.a > rhs.a; } - friend bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } + friend TEST_CONSTEXPR bool operator>(const value& lhs, const value& rhs) { return lhs.a > rhs.a; } + friend TEST_CONSTEXPR bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // Basic merge operation. typedef int T; typedef std::forward_list C; @@ -117,5 +117,14 @@ int main(int, char**) { assert(c == std::forward_list(std::begin(a), std::end(a))); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue.pass.cpp index acfa014fe2546..906748ec2702b 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue.pass.cpp @@ -10,7 +10,7 @@ // -// void merge(forward_list&& x); +// void merge(forward_list&& x); // constexpr since C++26 #include #include @@ -29,11 +29,11 @@ struct value { int a; int b; - friend bool operator<(const value& lhs, const value& rhs) { return lhs.a < rhs.a; } - friend bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } + friend TEST_CONSTEXPR bool operator<(const value& lhs, const value& rhs) { return lhs.a < rhs.a; } + friend TEST_CONSTEXPR bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // Basic merge operation. typedef int T; typedef std::forward_list C; @@ -109,5 +109,14 @@ int main(int, char**) { assert(c == std::forward_list(std::begin(a), std::end(a))); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue_pred.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue_pred.pass.cpp index 41b56ce7a2884..2ced0b1596e4d 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue_pred.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/merge_rvalue_pred.pass.cpp @@ -10,7 +10,7 @@ // -// template void merge(forward_list&& x, Compare comp); +// template void merge(forward_list&& x, Compare comp); // constexpr since C++26 #include #include @@ -29,11 +29,11 @@ struct value { int a; int b; - friend bool operator>(const value& lhs, const value& rhs) { return lhs.a > rhs.a; } - friend bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } + friend TEST_CONSTEXPR bool operator>(const value& lhs, const value& rhs) { return lhs.a > rhs.a; } + friend TEST_CONSTEXPR bool operator==(const value& lhs, const value& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // Basic merge operation. typedef int T; typedef std::forward_list C; @@ -110,5 +110,14 @@ int main(int, char**) { assert(c == std::forward_list(std::begin(a), std::end(a))); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove.pass.cpp index ec3bf845dcc5a..b17708ba60ee6 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove.pass.cpp @@ -9,7 +9,7 @@ // // void remove(const value_type& v); // C++17 and before -// size_type remove(const value_type& v); // C++20 and after +// size_type remove(const value_type& v); // C++20 and after; // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "min_allocator.h" template -void do_remove(L& l, const typename L::value_type& value, typename L::size_type expected) { +TEST_CONSTEXPR_CXX26 void do_remove(L& l, const typename L::value_type& value, typename L::size_type expected) { typename L::size_type old_size = std::distance(l.begin(), l.end()); #if TEST_STD_VER > 17 ASSERT_SAME_TYPE(decltype(l.remove(value)), typename L::size_type); @@ -32,22 +32,22 @@ void do_remove(L& l, const typename L::value_type& value, typename L::size_type } struct S { - S(int i) : i_(new int(i)) {} - S(const S& rhs) : i_(new int(*rhs.i_)) {} - S& operator=(const S& rhs) { + TEST_CONSTEXPR_CXX20 S(int i) : i_(new int(i)) {} + TEST_CONSTEXPR_CXX20 S(const S& rhs) : i_(new int(*rhs.i_)) {} + TEST_CONSTEXPR_CXX20 S& operator=(const S& rhs) { *i_ = *rhs.i_; return *this; } - ~S() { + TEST_CONSTEXPR_CXX20 ~S() { delete i_; i_ = NULL; } - bool operator==(const S& rhs) const { return *i_ == *rhs.i_; } - int get() const { return *i_; } + TEST_CONSTEXPR bool operator==(const S& rhs) const { return *i_ == *rhs.i_; } + TEST_CONSTEXPR int get() const { return *i_; } int* i_; }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -171,5 +171,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove_if.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove_if.pass.cpp index c6325baea2590..f26205d03f645 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove_if.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/remove_if.pass.cpp @@ -9,7 +9,7 @@ // // template void remove_if(Predicate pred); // C++17 and before -// template size_type remove_if(Predicate pred); // C++20 and after +// template size_type remove_if(Predicate pred); // C++20 and after; constexpr since C++26 #include #include @@ -22,7 +22,7 @@ #include "counting_predicates.h" template -void do_remove_if(L& l, Predicate pred, typename L::size_type expected) { +TEST_CONSTEXPR_CXX26 void do_remove_if(L& l, Predicate pred, typename L::size_type expected) { typename L::size_type old_size = std::distance(l.begin(), l.end()); #if TEST_STD_VER > 17 ASSERT_SAME_TYPE(decltype(l.remove_if(pred)), typename L::size_type); @@ -34,18 +34,18 @@ void do_remove_if(L& l, Predicate pred, typename L::size_type expected) { assert(old_size - std::distance(l.begin(), l.end()) == expected); } -bool g(int i) { return i < 3; } +TEST_CONSTEXPR bool g(int i) { return i < 3; } struct PredLWG526 { - PredLWG526(int i) : i_(i) {} - ~PredLWG526() { i_ = -32767; } - bool operator()(const PredLWG526& p) const { return p.i_ == i_; } + TEST_CONSTEXPR_CXX20 PredLWG526(int i) : i_(i) {} + TEST_CONSTEXPR_CXX20 ~PredLWG526() { i_ = -32767; } + TEST_CONSTEXPR bool operator()(const PredLWG526& p) const { return p.i_ == i_; } - bool operator==(int i) const { return i == i_; } + TEST_CONSTEXPR bool operator==(int i) const { return i == i_; } int i_; }; -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef unary_counting_predicate Predicate; @@ -187,5 +187,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/reverse.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/reverse.pass.cpp index 0d0656897f34e..38f0e74f66323 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/reverse.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/reverse.pass.cpp @@ -8,7 +8,7 @@ // -// void reverse(); +// void reverse(); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "min_allocator.h" template -void test(int N) { +TEST_CONSTEXPR_CXX26 void test1(int N) { C c; for (int i = 0; i < N; ++i) c.push_front(i); @@ -30,12 +30,21 @@ void test(int N) { assert(*j == i); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { for (int i = 0; i < 10; ++i) - test >(i); + test1 >(i); #if TEST_STD_VER >= 11 for (int i = 0; i < 10; ++i) - test> >(i); + test1> >(i); +#endif + + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_flist.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_flist.pass.cpp index 4c91d7397adf0..f8787d70784d1 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_flist.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_flist.pass.cpp @@ -8,7 +8,7 @@ // -// void splice_after(const_iterator p, forward_list&& x); +// void splice_after(const_iterator p, forward_list&& x); // constexpr since C++26 #include #include @@ -19,13 +19,13 @@ #include "min_allocator.h" typedef int T; -const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; -const T t2[] = {10, 11, 12, 13, 14, 15}; -const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); -const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); +TEST_CONSTEXPR const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; +TEST_CONSTEXPR const T t2[] = {10, 11, 12, 13, 14, 15}; +TEST_CONSTEXPR const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); +TEST_CONSTEXPR const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); template -void testd(const C& c, int p, int l) { +TEST_CONSTEXPR_CXX26 void testd(const C& c, int p, int l) { typename C::const_iterator i = c.begin(); int n1 = 0; for (; n1 < p; ++n1, ++i) @@ -37,7 +37,7 @@ void testd(const C& c, int p, int l) { assert(std::distance(c.begin(), c.end()) == size_t1 + l); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // splicing different containers typedef std::forward_list C; @@ -67,5 +67,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_one.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_one.pass.cpp index bb8bdea632547..7202b0e153627 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_one.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_one.pass.cpp @@ -8,7 +8,7 @@ // -// void splice_after(const_iterator p, forward_list&& x, const_iterator i); +// void splice_after(const_iterator p, forward_list&& x, const_iterator i); // constexpr since C++26 #include #include @@ -19,13 +19,13 @@ #include "min_allocator.h" typedef int T; -const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; -const T t2[] = {10, 11, 12}; -const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); -const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); +TEST_CONSTEXPR const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; +TEST_CONSTEXPR const T t2[] = {10, 11, 12}; +TEST_CONSTEXPR const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); +TEST_CONSTEXPR const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); template -void testd(const C& c, int p, int f) { +TEST_CONSTEXPR_CXX26 void testd(const C& c, int p, int f) { typename C::const_iterator i = c.begin(); int n1 = 0; for (; n1 < p; ++n1, ++i) @@ -38,7 +38,7 @@ void testd(const C& c, int p, int f) { } template -void tests(const C& c, int p, int f) { +TEST_CONSTEXPR_CXX26 void tests(const C& c, int p, int f) { typename C::const_iterator i = c.begin(); int n = 0; if (p == f || p == f + 1) { @@ -67,7 +67,7 @@ void tests(const C& c, int p, int f) { assert(std::distance(c.begin(), c.end()) == size_t1); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // splicing different containers typedef std::forward_list C; @@ -117,5 +117,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_range.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_range.pass.cpp index 99b3ed1c7836b..18da6f12b28da 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/splice_after_range.pass.cpp @@ -8,8 +8,10 @@ // +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=3000000 + // void splice_after(const_iterator p, forward_list&& x, -// const_iterator first, const_iterator last); +// const_iterator first, const_iterator last); // constexpr since C++26 #include #include @@ -20,13 +22,13 @@ #include "min_allocator.h" typedef std::ptrdiff_t T; -const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; -const T t2[] = {10, 11, 12, 13, 14, 15}; -const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); -const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); +TEST_CONSTEXPR const T t1[] = {0, 1, 2, 3, 4, 5, 6, 7}; +TEST_CONSTEXPR const T t2[] = {10, 11, 12, 13, 14, 15}; +TEST_CONSTEXPR const std::ptrdiff_t size_t1 = std::end(t1) - std::begin(t1); +TEST_CONSTEXPR const std::ptrdiff_t size_t2 = std::end(t2) - std::begin(t2); template -void testd(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { +TEST_CONSTEXPR_CXX26 void testd(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { typename C::const_iterator i = c.begin(); std::ptrdiff_t n1 = 0; for (; n1 < p; ++n1, ++i) @@ -39,7 +41,7 @@ void testd(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { } template -void tests(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { +TEST_CONSTEXPR_CXX26 void tests(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { typename C::const_iterator i = c.begin(); std::ptrdiff_t n = 0; std::ptrdiff_t d = l > f + 1 ? l - 1 - f : 0; @@ -69,7 +71,7 @@ void tests(const C& c, std::ptrdiff_t p, ptrdiff_t f, ptrdiff_t l) { assert(std::distance(c.begin(), c.end()) == size_t1); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { // splicing different containers typedef std::forward_list C; @@ -157,5 +159,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique.pass.cpp index ebd1a79cdb4bc..28efff3849e68 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique.pass.cpp @@ -9,7 +9,7 @@ // // void unique(); // C++17 and before -// size_type unique(); // C++20 and after +// size_type unique(); // C++20 and after; constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "min_allocator.h" template -void do_unique(L& l, typename L::size_type expected) { +TEST_CONSTEXPR_CXX26 void do_unique(L& l, typename L::size_type expected) { typename L::size_type old_size = std::distance(l.begin(), l.end()); #if TEST_STD_VER > 17 ASSERT_SAME_TYPE(decltype(l.unique()), typename L::size_type); @@ -31,7 +31,7 @@ void do_unique(L& l, typename L::size_type expected) { assert(old_size - std::distance(l.begin(), l.end()) == expected); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -131,5 +131,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique_pred.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique_pred.pass.cpp index 408cbf6ae9c20..f07142dffe9d9 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique_pred.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.ops/unique_pred.pass.cpp @@ -9,7 +9,7 @@ // // template void unique(BinaryPredicate binary_pred); // C++17 and before -// template size_type unique(BinaryPredicate binary_pred); // C++20 and after +// template size_type unique(BinaryPredicate binary_pred); // C++20 and after; constexpr since C++26 #include #include @@ -20,7 +20,7 @@ #include "min_allocator.h" template -void do_unique(L& l, Predicate pred, typename L::size_type expected) { +TEST_CONSTEXPR_CXX26 void do_unique(L& l, Predicate pred, typename L::size_type expected) { typename L::size_type old_size = std::distance(l.begin(), l.end()); #if TEST_STD_VER > 17 ASSERT_SAME_TYPE(decltype(l.unique(pred)), typename L::size_type); @@ -33,17 +33,17 @@ void do_unique(L& l, Predicate pred, typename L::size_type expected) { } struct PredLWG526 { - PredLWG526(int i) : i_(i) {} - ~PredLWG526() { i_ = -32767; } - bool operator()(const PredLWG526& lhs, const PredLWG526& rhs) const { return lhs.i_ == rhs.i_; } + TEST_CONSTEXPR_CXX20 PredLWG526(int i) : i_(i) {} + TEST_CONSTEXPR_CXX20 ~PredLWG526() { i_ = -32767; } + TEST_CONSTEXPR bool operator()(const PredLWG526& lhs, const PredLWG526& rhs) const { return lhs.i_ == rhs.i_; } - bool operator==(int i) const { return i == i_; } + TEST_CONSTEXPR bool operator==(int i) const { return i == i_; } int i_; }; -bool g(int x, int y) { return x == y; } +TEST_CONSTEXPR bool g(int x, int y) { return x == y; } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef std::forward_list C; @@ -157,5 +157,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/equal.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/equal.pass.cpp index ef6b72ee360a9..cb57b094a077d 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/equal.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/equal.pass.cpp @@ -10,11 +10,11 @@ // template // bool operator==(const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 // // template // bool operator!=(const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 #include #include @@ -25,7 +25,7 @@ #include "min_allocator.h" template -void test(int N, int M) { +TEST_CONSTEXPR_CXX26 void test(int N, int M) { C c1; for (int i = 0; i < N; ++i) c1.push_front(i); @@ -44,7 +44,7 @@ void test(int N, int M) { } } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) test >(i, j); @@ -54,5 +54,14 @@ int main(int, char**) { test> >(i, j); #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/member_swap.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/member_swap.pass.cpp index e50f9e6e9e473..f4f7c6d1f7e53 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/member_swap.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/member_swap.pass.cpp @@ -8,7 +8,7 @@ // -// void swap(forward_list& x); +// void swap(forward_list& x); // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -257,5 +257,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/non_member_swap.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/non_member_swap.pass.cpp index cae6950436dee..ce25479781547 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/non_member_swap.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/non_member_swap.pass.cpp @@ -9,7 +9,7 @@ // // template -// void swap(forward_list& x, forward_list& y); +// void swap(forward_list& x, forward_list& y); // constexpr since C++26 #include #include @@ -19,7 +19,7 @@ #include "test_allocator.h" #include "min_allocator.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef int T; typedef test_allocator A; @@ -258,5 +258,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/relational.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/relational.pass.cpp index d16acadaeb893..7bf80ca026e8e 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/relational.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/relational.pass.cpp @@ -10,19 +10,19 @@ // template // bool operator< (const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 // // template // bool operator> (const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 // // template // bool operator>=(const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 // // template // bool operator<=(const forward_list& x, -// const forward_list& y); +// const forward_list& y); // constexpr since C++26 #include #include @@ -33,7 +33,7 @@ #include "min_allocator.h" template -void test(int N, int M) { +TEST_CONSTEXPR_CXX26 void test(int N, int M) { C c1; for (int i = 0; i < N; ++i) c1.push_front(i); @@ -50,7 +50,7 @@ void test(int N, int M) { assert(c1 > c2); } -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) test >(i, j); @@ -60,5 +60,14 @@ int main(int, char**) { test> >(i, j); #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.compile.pass.cpp index b50e67589471d..02b7b471a1ae8 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.compile.pass.cpp @@ -12,10 +12,10 @@ // void swap(forward_list& c) // noexcept(!allocator_type::propagate_on_container_swap::value || -// __is_nothrow_swappable::value); +// __is_nothrow_swappable::value); // constexpr since C++26 // // In C++17, the standard says that swap shall have: -// noexcept(is_always_equal::value); +// noexcept(is_always_equal::value); // constexpr since C++26 // This tests a conforming extension diff --git a/libcxx/test/std/containers/sequences/forwardlist/get_allocator.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/get_allocator.pass.cpp index f37f5c2f513bd..624eeb17799c0 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/get_allocator.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/get_allocator.pass.cpp @@ -10,7 +10,7 @@ // class forward_list -// allocator_type get_allocator() const +// allocator_type get_allocator() const // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { std::allocator alloc; const std::forward_list fl(alloc); @@ -30,5 +30,14 @@ int main(int, char**) { assert(fl.get_allocator() == alloc); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/incomplete.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/incomplete.pass.cpp index b7be03f1062dc..16c6f0b90f96d 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/incomplete.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/incomplete.pass.cpp @@ -8,9 +8,9 @@ // -// forward_list() -// forward_list::iterator() -// forward_list::const_iterator() +// forward_list() // constexpr since C++26 +// forward_list::iterator() // constexpr since C++26 +// forward_list::const_iterator() // constexpr since C++26 #include #include @@ -33,7 +33,7 @@ struct B { }; #endif -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { A a; assert(a.d.empty()); @@ -49,5 +49,14 @@ int main(int, char**) { } #endif + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/max_size.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/max_size.pass.cpp index 5ba0d61f104e0..aab53351f00e2 100644 --- a/libcxx/test/std/containers/sequences/forwardlist/max_size.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/max_size.pass.cpp @@ -8,7 +8,7 @@ // -// size_type max_size() const; +// size_type max_size() const; // constexpr since C++26 #include #include @@ -18,7 +18,7 @@ #include "test_allocator.h" #include "test_macros.h" -int main(int, char**) { +TEST_CONSTEXPR_CXX26 bool test() { { typedef limited_allocator A; typedef std::forward_list C; @@ -42,5 +42,14 @@ int main(int, char**) { assert(c.max_size() <= alloc_max_size(c.get_allocator())); } + return true; +} + +int main(int, char**) { + assert(test()); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.get.area/setg.assert.pass.cpp b/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.get.area/setg.assert.pass.cpp index becf89b12fdd1..973d744a1da44 100644 --- a/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.get.area/setg.assert.pass.cpp +++ b/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.get.area/setg.assert.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: c++03, libcpp-hardening-mode=none // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // diff --git a/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.put.area/setp.assert.pass.cpp b/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.put.area/setp.assert.pass.cpp index abd42272de508..5aaad2738d325 100644 --- a/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.put.area/setp.assert.pass.cpp +++ b/libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.put.area/setp.assert.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: c++03, libcpp-hardening-mode=none // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp index 6a2b098c1b573..9ee32b8417832 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp @@ -9,6 +9,9 @@ // UNSUPPORTED: no-exceptions // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.pass.cpp index 437d064307735..4fdcc3b535a8d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.pass.cpp @@ -11,6 +11,9 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp index 4e34ebcb46c7d..4dfaf7a30d7a2 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp @@ -9,6 +9,9 @@ // UNSUPPORTED: no-exceptions // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + // Libc++ when built for z/OS doesn't contain the aligned allocation functions, // nor does the dynamic library shipped with z/OS. // XFAIL: target={{.+}}-zos{{.*}} diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.pass.cpp index c9b59ecaff396..a1b8466340a2a 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.pass.cpp @@ -13,6 +13,9 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + // Libc++ when built for z/OS doesn't contain the aligned allocation functions, // nor does the dynamic library shipped with z/OS. // XFAIL: target={{.+}}-zos{{.*}} diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp index 6a515555e6dbd..346e881d016be 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp @@ -9,6 +9,9 @@ // UNSUPPORTED: no-exceptions // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.pass.cpp index 729ef3ec46b0c..0013dd3d0cbc3 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.pass.cpp @@ -11,6 +11,9 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp index 7694314c87bf3..fbeb880c83d8d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp @@ -9,6 +9,9 @@ // UNSUPPORTED: no-exceptions // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + // Libc++ when built for z/OS doesn't contain the aligned allocation functions, // nor does the dynamic library shipped with z/OS. // XFAIL: target={{.+}}-zos{{.*}} diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.pass.cpp index 5d321f08282b2..59ecbe205513a 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.pass.cpp @@ -13,6 +13,9 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete +// GCC warns about allocating numeric_limits::max() being too large (which we test here) +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + // Libc++ when built for z/OS doesn't contain the aligned allocation functions, // nor does the dynamic library shipped with z/OS. // XFAIL: target={{.+}}-zos{{.*}} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.compile.pass.cpp index 31b3e900aabcd..05f903dccafe7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.compile.pass.cpp @@ -24,6 +24,10 @@ # error "__cpp_lib_allocator_traits_is_always_equal should not be defined before c++17" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should not be defined before c++23" # endif @@ -54,6 +58,10 @@ # error "__cpp_lib_allocator_traits_is_always_equal should not be defined before c++17" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should not be defined before c++23" # endif @@ -87,6 +95,10 @@ # error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++17" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should not be defined before c++23" # endif @@ -126,6 +138,10 @@ # error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++20" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should not be defined before c++23" # endif @@ -171,6 +187,10 @@ # error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++23" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifndef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should be defined in c++23" # endif @@ -219,6 +239,13 @@ # error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++26" # endif +# ifndef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should be defined in c++26" +# endif +# if __cpp_lib_constexpr_forward_list != 202502L +# error "__cpp_lib_constexpr_forward_list should have the value 202502L in c++26" +# endif + # ifndef __cpp_lib_containers_ranges # error "__cpp_lib_containers_ranges should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index b1cc4afd30696..a13edacd1e46a 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -196,6 +196,10 @@ # error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++20" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif @@ -1084,6 +1088,10 @@ # error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++20" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif @@ -2074,6 +2082,10 @@ # error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++20" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif @@ -3304,6 +3316,10 @@ # error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++20" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifndef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should be defined in c++20" # endif @@ -4756,6 +4772,10 @@ # error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++23" # endif +# ifdef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should not be defined before c++26" +# endif + # ifndef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should be defined in c++23" # endif @@ -6427,6 +6447,13 @@ # error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++26" # endif +# ifndef __cpp_lib_constexpr_forward_list +# error "__cpp_lib_constexpr_forward_list should be defined in c++26" +# endif +# if __cpp_lib_constexpr_forward_list != 202502L +# error "__cpp_lib_constexpr_forward_list should have the value 202502L in c++26" +# endif + # ifndef __cpp_lib_constexpr_functional # error "__cpp_lib_constexpr_functional should be defined in c++26" # endif diff --git a/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/ctor_func.pass.cpp b/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/ctor_func.pass.cpp index c3a88af92d360..c05a9434175a8 100644 --- a/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/ctor_func.pass.cpp +++ b/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/ctor_func.pass.cpp @@ -15,6 +15,9 @@ // discrete_distribution(size_t nw, double xmin, double xmax, // UnaryOperation fw); +// There is a bogus diagnostic about a too large allocation +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include diff --git a/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/param_ctor_func.pass.cpp b/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/param_ctor_func.pass.cpp index 7ef936b7fc355..206bf5a0eb8a2 100644 --- a/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/param_ctor_func.pass.cpp +++ b/libcxx/test/std/numerics/rand/rand.dist/rand.dist.samp/rand.dist.samp.discrete/param_ctor_func.pass.cpp @@ -15,6 +15,9 @@ // param_type(size_t nw, double xmin, double xmax, // UnaryOperation fw); +// There is a bogus diagnostic about a too large allocation +// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-alloc-size-larger-than + #include #include diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp index f4e87bb47399e..521c0b1610bce 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp @@ -312,7 +312,10 @@ constexpr bool main_test() { // Leading separator. { std::array expected = {""sv, "abc"sv, "def"sv}; +// FIXME: Why does GCC complain here? +#ifndef TEST_COMPILER_GCC test_one(" abc def"sv, short_sep, expected); +#endif test_one("12abc12def"sv, long_sep, expected); } @@ -326,7 +329,10 @@ constexpr bool main_test() { // Input consisting of a single separator. { std::array expected = {""sv, ""sv}; +// FIXME: Why does GCC complain here? +#ifndef TEST_COMPILER_GCC test_one(" "sv, short_sep, expected); +#endif test_one("12"sv, long_sep, expected); } @@ -354,7 +360,10 @@ constexpr bool main_test() { // Separators after every character. { std::array expected = {""sv, "a"sv, "b"sv, "c"sv, ""sv}; +// FIXME: Why does GCC complain here? +#ifndef TEST_COMPILER_GCC test_one(" a b c "sv, short_sep, expected); +#endif test_one("12a12b12c12"sv, long_sep, expected); } @@ -383,7 +392,10 @@ constexpr bool main_test() { // Terminating null as a separator. { std::array expected = {"abc"sv, "def"sv}; +// FIXME: Why does GCC complain here? +#ifndef TEST_COMPILER_GCC test_one("abc\0def"sv, '\0', expected); +#endif test_one("abc\0\0def"sv, "\0\0"sv, expected); } diff --git a/libcxx/test/std/time/time.point/time.point.arithmetic/op_++.pass.cpp b/libcxx/test/std/time/time.point/time.point.arithmetic/op_++.pass.cpp new file mode 100644 index 0000000000000..e035d7ef4fa0e --- /dev/null +++ b/libcxx/test/std/time/time.point/time.point.arithmetic/op_++.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: std-at-least-c++20 + +// + +// time_point + +// constexpr time_point& operator++(); + +#include +#include + +#include "test_macros.h" + +constexpr bool test() { + using Clock = std::chrono::system_clock; + using Duration = std::chrono::milliseconds; + std::chrono::time_point t{Duration{5}}; + std::chrono::time_point& tref{++t}; + assert(&tref == &t); + assert(tref.time_since_epoch() == Duration{6}); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/time/time.point/time.point.arithmetic/op_++int.pass.cpp b/libcxx/test/std/time/time.point/time.point.arithmetic/op_++int.pass.cpp new file mode 100644 index 0000000000000..5304d37d5c361 --- /dev/null +++ b/libcxx/test/std/time/time.point/time.point.arithmetic/op_++int.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: std-at-least-c++20 + +// + +// time_point + +// constexpr time_point operator++(int); + +#include +#include + +#include "test_macros.h" + +constexpr bool test() { + using Clock = std::chrono::system_clock; + using Duration = std::chrono::milliseconds; + std::chrono::time_point t1{Duration{3}}; + std::chrono::time_point t2{t1++}; + assert(t1.time_since_epoch() == Duration{4}); + assert(t2.time_since_epoch() == Duration{3}); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/time/time.point/time.point.arithmetic/op_--.pass.cpp b/libcxx/test/std/time/time.point/time.point.arithmetic/op_--.pass.cpp new file mode 100644 index 0000000000000..915156fcc6b8c --- /dev/null +++ b/libcxx/test/std/time/time.point/time.point.arithmetic/op_--.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: std-at-least-c++20 + +// + +// time_point + +// constexpr time_point& operator--(); + +#include +#include + +#include "test_macros.h" + +constexpr bool test() { + using Clock = std::chrono::system_clock; + using Duration = std::chrono::milliseconds; + std::chrono::time_point t{Duration{5}}; + std::chrono::time_point& tref{--t}; + assert(&tref == &t); + assert(tref.time_since_epoch() == Duration{4}); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/time/time.point/time.point.arithmetic/op_--int.pass.cpp b/libcxx/test/std/time/time.point/time.point.arithmetic/op_--int.pass.cpp new file mode 100644 index 0000000000000..cc5f462106bbf --- /dev/null +++ b/libcxx/test/std/time/time.point/time.point.arithmetic/op_--int.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: std-at-least-c++20 + +// + +// time_point + +// constexpr time_point operator--(int); + +#include +#include + +#include "test_macros.h" + +constexpr bool test() { + using Clock = std::chrono::system_clock; + using Duration = std::chrono::milliseconds; + std::chrono::time_point t1{Duration{3}}; + std::chrono::time_point t2{t1--}; + assert(t1.time_since_epoch() == Duration{2}); + assert(t2.time_since_epoch() == Duration{3}); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp index cbd54d623c0f4..97c1e4a40f355 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp @@ -9,8 +9,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`, -// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333 -// XFAIL: gcc-14 +// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995 +// XFAIL: gcc-14, gcc-15 // diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp index a19e17b01f6a9..9570b2faac692 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp @@ -9,8 +9,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`, -// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333. -// XFAIL: gcc-14 +// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995. +// XFAIL: gcc-14, gcc-15 // diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp index f6d3011d1ea96..2ec15b51d11ea 100644 --- a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp @@ -9,8 +9,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`, -// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333 -// XFAIL: gcc-14 +// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995 +// XFAIL: gcc-14, gcc-15 // diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.char_array.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.char_array.pass.cpp index bc056db9e254e..8c4f3000ec1e8 100644 --- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.char_array.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.char_array.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // TODO FMT __builtin_memcpy isn't constexpr in GCC -// UNSUPPORTED: gcc-14 +// UNSUPPORTED: gcc-14, gcc-15 // diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp index 85106c18ec35a..4a2ae963e3bdb 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -23,16 +23,13 @@ #include "test_comparisons.h" #include "test_macros.h" -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(HasSpaceshipOperatorWithInt>); -static_assert(HasSpaceshipOperatorWithInt>); -static_assert(HasSpaceshipOperatorWithInt>); +static_assert(HasOperatorSpaceship, int>); +static_assert(HasOperatorSpaceship, int>); +static_assert(HasOperatorSpaceship, int>); -static_assert(!HasSpaceshipOperatorWithInt>); +static_assert(!HasOperatorSpaceship, int>); // Test comparisons. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp index 794fac00de8a6..3d72459bc5a19 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -22,17 +22,13 @@ #include "test_comparisons.h" #include "test_macros.h" - -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(std::three_way_comparable>); -static_assert(std::three_way_comparable>); -static_assert(std::three_way_comparable>); +static_assert(HasOperatorSpaceship>); +static_assert(HasOperatorSpaceship>); +static_assert(HasOperatorSpaceship>); -static_assert(!std::three_way_comparable>); +static_assert(!HasOperatorSpaceship>); // Test comparisons. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp index 9b1302affa851..1ae22b4ac58e0 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -23,18 +23,15 @@ #include "test_comparisons.h" #include "test_macros.h" -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(std::three_way_comparable_with, const StrongOrder>); -static_assert(std::three_way_comparable_with, const WeakOrder>); -static_assert(std::three_way_comparable_with, const PartialOrder>); +static_assert(HasOperatorSpaceship, std::reference_wrapper>); +static_assert(HasOperatorSpaceship, std::reference_wrapper>); +static_assert(HasOperatorSpaceship, std::reference_wrapper>); -static_assert(!std::three_way_comparable_with, const NonComparable>); -static_assert(!std::three_way_comparable_with, const NonComparable>); -static_assert(!std::three_way_comparable_with, const NonComparable>); +static_assert(!HasOperatorSpaceship, std::reference_wrapper>); +static_assert(!HasOperatorSpaceship, std::reference_wrapper>); +static_assert(!HasOperatorSpaceship, std::reference_wrapper>); // Test comparisons. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp index 465326818f17c..316ff7c303315 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -23,14 +23,13 @@ #include "test_comparisons.h" #include "test_macros.h" -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(HasEqualityOperatorWithInt>); +static_assert(HasOperatorEqual>); +static_assert(HasOperatorEqual, int>); -static_assert(!HasEqualityOperatorWithInt>); +static_assert(!HasOperatorEqual>); +static_assert(!HasOperatorEqual, int>); // Test equality. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp index a50b530bbc6e1..70e79d399861a 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -22,14 +22,11 @@ #include "test_comparisons.h" #include "test_macros.h" -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(std::equality_comparable>); +static_assert(HasOperatorEqual>); -static_assert(!std::equality_comparable>); +static_assert(!HasOperatorEqual>); // Test equality. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp index 10f017742a87f..c68ad5c4aa527 100644 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: std-at-least-c++26 // @@ -23,16 +23,13 @@ #include "test_comparisons.h" #include "test_macros.h" -#include "helper_concepts.h" -#include "helper_types.h" - // Test SFINAE. -static_assert(std::equality_comparable_with, - std::reference_wrapper>); +static_assert( + HasOperatorEqual, std::reference_wrapper>); -static_assert(!std::equality_comparable_with, - std::reference_wrapper>); +static_assert( + !HasOperatorEqual, std::reference_wrapper>); // Test equality. diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h deleted file mode 100644 index 2dbb304f8af63..0000000000000 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H -#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H - -#include -#include - -// Equality - -template -concept HasEqualityOperatorWithInt = requires(T t, int i) { - { t.get() == i } -> std::convertible_to; -}; - -// Spaceship - -template -concept BooleanTestableImpl = std::convertible_to; - -template -concept BooleanTestable = BooleanTestableImpl && requires(T&& t) { - { !std::forward(t) } -> BooleanTestableImpl; -}; - -template -concept HasSpaceshipOperatorWithInt = requires(T t, int i) { - { t < i } -> BooleanTestable; - { i < t } -> BooleanTestable; -}; - -#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h deleted file mode 100644 index cf5e568dbf936..0000000000000 --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H -#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H - -#include - -struct EqualityComparable { - constexpr EqualityComparable(int value) : value_{value} {}; - - friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default; - - int value_; -}; - -static_assert(std::equality_comparable); -static_assert(EqualityComparable{94} == EqualityComparable{94}); -static_assert(EqualityComparable{94} != EqualityComparable{82}); - -struct NonComparable {}; - -static_assert(!std::three_way_comparable); - -#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp index f443d2030961d..47c95c64a0855 100644 --- a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp @@ -18,6 +18,8 @@ #include #include +#include "test_macros.h" + template void test() { // Test the type of the variables @@ -98,8 +100,13 @@ int main(int, char**) { // Test with virtual inheritance { +#ifdef TEST_COMPILER_GCC // FIXME: Is this a GCC or Clang bug? Or is the standards wording ambiguous? + test(); + test(); +#else test(); test(); +#endif test(); test(); test(); diff --git a/libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.pass.cpp similarity index 94% rename from libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.compile.pass.cpp rename to libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.pass.cpp index 935a6e3db0017..37d66831c7ce5 100644 --- a/libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.compile.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.unary/dependent_return_type.pass.cpp @@ -168,3 +168,7 @@ void instantiate() { void_t(); #endif } + +// This is not a .compile.pass.cpp because we want to ensure that GCC doesn't complain about incorrect builtins usage, +// which only happens during CodeGen. +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp index 681ad13a07dfd..afd76e65060e3 100644 --- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // These compilers don't support __builtin_is_implicit_lifetime yet. -// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16, apple-clang-17 +// UNSUPPORTED: clang-18, clang-19, gcc-14, gcc-15, apple-clang-15, apple-clang-16, apple-clang-17 // diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp index e7931e07e31d1..23f131d2fc499 100644 --- a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp @@ -12,6 +12,9 @@ // template // constexpr optional make_optional(Args&&... args); +// GCC crashes on this file, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120577 +// XFAIL: gcc-15 + #include #include #include diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp index 80371d6333712..5ddb229ad9268 100644 --- a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp @@ -12,6 +12,9 @@ // template // constexpr optional make_optional(initializer_list il, Args&&... args); +// GCC crashes on this file, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120577 +// XFAIL: gcc-15 + #include #include #include diff --git a/libcxx/test/std/utilities/template.bitset/bitset.cons/char_ptr_ctor.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.cons/char_ptr_ctor.pass.cpp index 86b144ed87b70..4f9cdaeb38c0b 100644 --- a/libcxx/test/std/utilities/template.bitset/bitset.cons/char_ptr_ctor.pass.cpp +++ b/libcxx/test/std/utilities/template.bitset/bitset.cons/char_ptr_ctor.pass.cpp @@ -72,6 +72,35 @@ TEST_CONSTEXPR_CXX23 void test_char_pointer_ctor() for (std::size_t i = 10; i < v.size(); ++i) assert(v[i] == false); } + // Verify that this constructor doesn't read over the given bound. + // See https://github.com/llvm/llvm-project/issues/143684 + { + const char not_null_terminated[] = {'1', '0', '1', '0', '1', '0', '1', '0', '1', '0'}; + std::bitset v(not_null_terminated, 10); + std::size_t M = std::min(v.size(), 10); + for (std::size_t i = 0; i < M; ++i) + assert(v[i] == (not_null_terminated[M - 1 - i] == '1')); + for (std::size_t i = 10; i < v.size(); ++i) + assert(!v[i]); + } + { + const char not_null_terminated[] = {'1', 'a', '1', 'a', '1', 'a', '1', 'a', '1', 'a'}; + std::bitset v(not_null_terminated, 10, 'a'); + std::size_t M = std::min(v.size(), 10); + for (std::size_t i = 0; i < M; ++i) + assert(v[i] == (not_null_terminated[M - 1 - i] == '1')); + for (std::size_t i = 10; i < v.size(); ++i) + assert(!v[i]); + } + { + const char not_null_terminated[] = {'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a'}; + std::bitset v(not_null_terminated, 10, 'a', 'b'); + std::size_t M = std::min(v.size(), 10); + for (std::size_t i = 0; i < M; ++i) + assert(v[i] == (not_null_terminated[M - 1 - i] == 'b')); + for (std::size_t i = 10; i < v.size(); ++i) + assert(!v[i]); + } } TEST_CONSTEXPR_CXX23 bool test() { diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp index e6812e9a3a30a..ae5984c155300 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03 // FIXME: Why does this start to fail with GCC 14? -// XFAIL: !(c++11 || c++14) && gcc-14 +// XFAIL: !(c++11 || c++14) && (gcc-14 || gcc-15) // See https://llvm.org/PR31384. diff --git a/libcxx/test/support/counting_predicates.h b/libcxx/test/support/counting_predicates.h index 6f34ce76302a8..8fb2db1af70d3 100644 --- a/libcxx/test/support/counting_predicates.h +++ b/libcxx/test/support/counting_predicates.h @@ -16,42 +16,44 @@ template struct unary_counting_predicate { public: - typedef Arg argument_type; - typedef bool result_type; + typedef Arg argument_type; + typedef bool result_type; - unary_counting_predicate(Predicate p) : p_(p), count_(0) {} - unary_counting_predicate(const unary_counting_predicate&) = default; - unary_counting_predicate& operator=(const unary_counting_predicate&) = default; - ~unary_counting_predicate() {} + TEST_CONSTEXPR_CXX20 unary_counting_predicate(Predicate p) : p_(p), count_(0) {} + unary_counting_predicate(const unary_counting_predicate&) = default; + unary_counting_predicate& operator=(const unary_counting_predicate&) = default; + TEST_CONSTEXPR_CXX20 ~unary_counting_predicate() {} - bool operator () (const Arg &a) const { ++count_; return p_(a); } - std::size_t count() const { return count_; } - void reset() { count_ = 0; } + TEST_CONSTEXPR_CXX14 bool operator()(const Arg& a) const { + ++count_; + return p_(a); + } + TEST_CONSTEXPR std::size_t count() const { return count_; } + TEST_CONSTEXPR_CXX14 void reset() { count_ = 0; } private: - Predicate p_; - mutable std::size_t count_; + Predicate p_; + mutable std::size_t count_; }; - -template +template struct binary_counting_predicate { public: - typedef Arg1 first_argument_type; - typedef Arg2 second_argument_type; - typedef bool result_type; - - TEST_CONSTEXPR binary_counting_predicate(Predicate p) : p_(p), count_(0) {} - TEST_CONSTEXPR_CXX14 bool operator()(const Arg1& a1, const Arg2& a2) const { - ++count_; - return p_(a1, a2); - } - TEST_CONSTEXPR std::size_t count() const { return count_; } - TEST_CONSTEXPR_CXX14 void reset() { count_ = 0; } - - private: - Predicate p_; - mutable std::size_t count_; + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef bool result_type; + + TEST_CONSTEXPR binary_counting_predicate(Predicate p) : p_(p), count_(0) {} + TEST_CONSTEXPR_CXX14 bool operator()(const Arg1& a1, const Arg2& a2) const { + ++count_; + return p_(a1, a2); + } + TEST_CONSTEXPR std::size_t count() const { return count_; } + TEST_CONSTEXPR_CXX14 void reset() { count_ = 0; } + +private: + Predicate p_; + mutable std::size_t count_; }; #if TEST_STD_VER > 14 @@ -66,13 +68,13 @@ class counting_predicate { constexpr counting_predicate(Predicate pred, int& count) : pred_(std::move(pred)), count_(&count) {} template - constexpr decltype(auto) operator()(Args&& ...args) { + constexpr decltype(auto) operator()(Args&&... args) { ++(*count_); return pred_(std::forward(args)...); } template - constexpr decltype(auto) operator()(Args&& ...args) const { + constexpr decltype(auto) operator()(Args&&... args) const { ++(*count_); return pred_(std::forward(args)...); } diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h index db6977a96a2fe..d9729e0451b49 100644 --- a/libcxx/test/support/test_comparisons.h +++ b/libcxx/test/support/test_comparisons.h @@ -268,6 +268,29 @@ struct PartialOrder { } }; -#endif +template +concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; }; + +template +concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; }; + +struct NonComparable {}; +static_assert(!std::equality_comparable); +static_assert(!HasOperatorEqual); +static_assert(!HasOperatorSpaceship); + +class EqualityComparable { +public: + constexpr EqualityComparable(int value) : value_{value} {}; + + friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default; + +private: + int value_; +}; +static_assert(std::equality_comparable); +static_assert(HasOperatorEqual); + +#endif // TEST_STD_VER >= 20 #endif // TEST_COMPARISONS_H diff --git a/libcxx/test/support/test_container_comparisons.h b/libcxx/test/support/test_container_comparisons.h index f7bf78e48a1f8..53db5ba99ce47 100644 --- a/libcxx/test/support/test_container_comparisons.h +++ b/libcxx/test/support/test_container_comparisons.h @@ -88,7 +88,6 @@ constexpr bool test_sequence_container_spaceship() { std::weak_ordering>(); // Thanks to SFINAE, the following is not a compiler error but returns `false` - struct NonComparable {}; static_assert(!std::three_way_comparable>); return true; @@ -163,7 +162,6 @@ constexpr void test_sequence_container_adaptor_spaceship_with_type() { template