diff --git a/.github/workflows/build-metrics-container.yml b/.github/workflows/build-metrics-container.yml index 786c41214d853..e1407a29cc295 100644 --- a/.github/workflows/build-metrics-container.yml +++ b/.github/workflows/build-metrics-container.yml @@ -21,39 +21,19 @@ jobs: build-metrics-container: if: github.repository_owner == 'llvm' runs-on: ubuntu-24.04 - outputs: - container-name: ${{ steps.vars.outputs.container-name }} - container-name-tag: ${{ steps.vars.outputs.container-name-tag }} - container-filename: ${{ steps.vars.outputs.container-filename }} steps: - name: Checkout LLVM uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: - sparse-checkout: .ci/metrics/ - - name: Write Variables - id: vars - run: | - tag=`date +%s` - container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/metrics" - echo "container-name=$container_name" >> $GITHUB_OUTPUT - echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT - echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT + sparse-checkout: | + .ci/metrics/ + .github/actions/build-container - name: Build Container - working-directory: ./.ci/metrics - run: | - podman build -t ${{ steps.vars.outputs.container-name-tag }} -f Dockerfile . - # Save the container so we have it in case the push fails. This also - # allows us to separate the push step into a different job so we can - # maintain minimal permissions while building the container. - - name: Save Container Image - run: | - podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }} - - name: Upload Container Image - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: ./.github/actions/build-container with: - name: container - path: ${{ steps.vars.outputs.container-filename }} - retention-days: 14 + container-name: metrics + context: .ci/metrics + dockerfile: .ci/metrics/Dockerfile push-metrics-container: if: github.event_name == 'push' @@ -65,14 +45,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - name: Download Container - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + - name: Checkout LLVM + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + sparse-checkout: | + .github/actions/push-container + + - uses: ./.github/actions/push-container with: - name: container - - name: Push Container - run: | - podman load -i ${{ needs.build-metrics-container.outputs.container-filename }} - podman tag ${{ needs.build-metrics-container.outputs.container-name-tag }} ${{ needs.build-metrics-container.outputs.container-name }}:latest - podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io - podman push ${{ needs.build-metrics-container.outputs.container-name-tag }} - podman push ${{ needs.build-metrics-container.outputs.container-name }}:latest + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/containers/github-action-ci-windows/Dockerfile b/.github/workflows/containers/github-action-ci-windows/Dockerfile index f1e4f1538540b..509b3d2335106 100644 --- a/.github/workflows/containers/github-action-ci-windows/Dockerfile +++ b/.github/workflows/containers/github-action-ci-windows/Dockerfile @@ -90,7 +90,7 @@ RUN powershell -Command \ RUN git config --system core.longpaths true & \ git config --global core.autocrlf false -ARG RUNNER_VERSION=2.329.0 +ARG RUNNER_VERSION=2.330.0 ENV RUNNER_VERSION=$RUNNER_VERSION RUN powershell -Command \ diff --git a/.github/workflows/containers/github-action-ci/Dockerfile b/.github/workflows/containers/github-action-ci/Dockerfile index 1b376dd4420b3..37b0f2009179e 100644 --- a/.github/workflows/containers/github-action-ci/Dockerfile +++ b/.github/workflows/containers/github-action-ci/Dockerfile @@ -99,7 +99,7 @@ WORKDIR /home/gha FROM ci-container AS ci-container-agent -ENV GITHUB_RUNNER_VERSION=2.329.0 +ENV GITHUB_RUNNER_VERSION=2.330.0 RUN mkdir actions-runner && \ cd actions-runner && \ diff --git a/clang-tools-extra/docs/clang-tidy/checks/mpi/buffer-deref.rst b/clang-tools-extra/docs/clang-tidy/checks/mpi/buffer-deref.rst index ef9f391f31fa7..9658246b21d2a 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/mpi/buffer-deref.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/mpi/buffer-deref.rst @@ -5,9 +5,10 @@ mpi-buffer-deref This check verifies if a buffer passed to an MPI (Message Passing Interface) function is sufficiently dereferenced. Buffers should be passed as a single -pointer or array. As MPI function signatures specify ``void *`` for their buffer -types, insufficiently dereferenced buffers can be passed, like for example as -double pointers or multidimensional arrays, without a compiler warning emitted. +pointer or array. As MPI function signatures specify ``void *`` for their +buffer types, insufficiently dereferenced buffers can be passed, like for +example as double pointers or multidimensional arrays, without a compiler +warning emitted. Examples: diff --git a/clang-tools-extra/docs/clang-tidy/checks/mpi/type-mismatch.rst b/clang-tools-extra/docs/clang-tidy/checks/mpi/type-mismatch.rst index 10752ef3b1cb8..e5d174c33315d 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/mpi/type-mismatch.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/mpi/type-mismatch.rst @@ -3,10 +3,11 @@ mpi-type-mismatch ================= -This check verifies if buffer type and MPI (Message Passing Interface) datatype -pairs match for used MPI functions. All MPI datatypes defined by the MPI -standard (3.1) are verified by this check. User defined typedefs, custom MPI -datatypes and null pointer constants are skipped, in the course of verification. +This check verifies if buffer type and MPI (Message Passing Interface) +datatype pairs match for used MPI functions. All MPI datatypes defined +by the MPI standard (3.1) are verified by this check. User defined typedefs, +custom MPI datatypes and null pointer constants are skipped, in the course +of verification. Example: diff --git a/clang-tools-extra/docs/clang-tidy/checks/objc/forbidden-subclassing.rst b/clang-tools-extra/docs/clang-tidy/checks/objc/forbidden-subclassing.rst index 4bb023cdabc8b..389409412e251 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/objc/forbidden-subclassing.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/objc/forbidden-subclassing.rst @@ -3,11 +3,11 @@ objc-forbidden-subclassing ========================== -Finds Objective-C classes which are subclasses of classes which are not designed -to be subclassed. +Finds Objective-C classes which are subclasses of classes which are +not designed to be subclassed. -By default, includes a list of Objective-C classes which are publicly documented -as not supporting subclassing. +By default, includes a list of Objective-C classes which are publicly +documented as not supporting subclassing. .. note:: diff --git a/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst b/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst index b5a1386d2166e..ea54a0586bb28 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst @@ -3,71 +3,93 @@ objc-nsdate-formatter ===================== -When ``NSDateFormatter`` is used to convert an ``NSDate`` type to a ``String`` type, the user -can specify a custom format string. Certain format specifiers are undesirable -despite being legal. See http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns for all legal date patterns. +When ``NSDateFormatter`` is used to convert an ``NSDate`` type to a ``String`` +type, the user can specify a custom format string. Certain format specifiers +are undesirable despite being legal. +See http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns +for all legal date patterns. -This checker reports as warnings the following string patterns in a date format specifier: +This checker reports as warnings the following string patterns in a date +format specifier: -#. yyyy + ww : Calendar year specified with week of a week year (unless YYYY is also specified). +#. yyyy + ww : Calendar year specified with week of a week year + (unless YYYY is also specified). - * | **Example 1:** Input Date: `29 December 2014` ; Format String: `yyyy-ww`; + * | **Example 1:** Input Date: `29 December 2014` ; + | Format String: `yyyy-ww`; | Output string: `2014-01` (Wrong because it’s not the first week of 2014) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `dd-MM-yyyy (ww-YYYY)`; + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `dd-MM-yyyy (ww-YYYY)`; | Output string: `29-12-2014 (01-2015)` (This is correct) #. F without ee/EE : Numeric day of week in a month without actual day. * | **Example:** Input Date: `29 December 2014` ; Format String: `F-MM`; - | Output string: `5-12` (Wrong because it reads as *5th ___ of Dec* in English) + | Output string: `5-12` (Wrong because it reads as *5th ___ of Dec* in + | English) #. F without MM : Numeric day of week in a month without month. * | **Example:** Input Date: `29 December 2014` ; Format String: `F-EE` - | Output string: `5-Mon` (Wrong because it reads as *5th Mon of ___* in English) + | Output string: `5-Mon` (Wrong because it reads as *5th Mon of ___* in + | English) #. WW without MM : Week of the month without the month. * | **Example:** Input Date: `29 December 2014` ; Format String: `WW-yyyy` - | Output string: `05-2014` (Wrong because it reads as *5th Week of ___* in English) + | Output string: `05-2014` (Wrong because it reads as *5th Week of ___* in + | English) -#. YYYY + QQ : Week year specified with quarter of normal year (unless yyyy is also specified). +#. YYYY + QQ : Week year specified with quarter of normal year + (unless yyyy is also specified). * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-QQ` - | Output string: `2015-04` (Wrong because it’s not the 4th quarter of 2015) + | Output string: `2015-04` (Wrong because it’s not the 4th quarter of + | 2015) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (QQ-yyyy)` + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `ww-YYYY (QQ-yyyy)` | Output string: `01-2015 (04-2014)` (This is correct) -#. YYYY + MM : Week year specified with Month of a calendar year (unless yyyy is also specified). +#. YYYY + MM : Week year specified with Month of a calendar year + (unless yyyy is also specified). * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-MM` | Output string: `2015-12` (Wrong because it’s not the 12th month of 2015) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (MM-yyyy)` + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `ww-YYYY (MM-yyyy)` | Output string: `01-2015 (12-2014)` (This is correct) -#. YYYY + DD : Week year with day of a calendar year (unless yyyy is also specified). +#. YYYY + DD : Week year with day of a calendar year + (unless yyyy is also specified). * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-DD` | Output string: `2015-363` (Wrong because it’s not the 363rd day of 2015) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (DD-yyyy)` + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `ww-YYYY (DD-yyyy)` | Output string: `01-2015 (363-2014)` (This is correct) -#. YYYY + WW : Week year with week of a calendar year (unless yyyy is also specified). +#. YYYY + WW : Week year with week of a calendar year + (unless yyyy is also specified). * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-WW` | Output string: `2015-05` (Wrong because it’s not the 5th week of 2015) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (WW-MM-yyyy)` + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `ww-YYYY (WW-MM-yyyy)` | Output string: `01-2015 (05-12-2014)` (This is correct) -#. YYYY + F : Week year with day of week in a calendar month (unless yyyy is also specified). +#. YYYY + F : Week year with day of week in a calendar month + (unless yyyy is also specified). - * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-ww-F-EE` - | Output string: `2015-01-5-Mon` (Wrong because it’s not the 5th Monday of January in 2015) + * | **Example 1:** Input Date: `29 December 2014` ; + | Format String: `YYYY-ww-F-EE` + | Output string: `2015-01-5-Mon` (Wrong because it’s not the 5th Monday of + | January in 2015) - * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (F-EE-MM-yyyy)` + * | **Example 2:** Input Date: `29 December 2014` ; + | Format String: `ww-YYYY (F-EE-MM-yyyy)` | Output string: `01-2015 (5-Mon-12-2014)` (This is correct) diff --git a/clang-tools-extra/docs/clang-tidy/checks/objc/property-declaration.rst b/clang-tools-extra/docs/clang-tidy/checks/objc/property-declaration.rst index 60b9c82e9f926..53f9453afcfae 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/objc/property-declaration.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/objc/property-declaration.rst @@ -23,8 +23,8 @@ The check will only fix 'CamelCase' to 'camelCase'. In some other cases we will only provide warning messages since the property name could be complicated. Users will need to come up with a proper name by their own. -This check also accepts special acronyms as prefixes or suffixes. Such prefixes or suffixes -will suppress the Lower Camel Case check according to the guide: +This check also accepts special acronyms as prefixes or suffixes. Such prefixes +or suffixes will suppress the Lower Camel Case check according to the guide: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-1002931-BBCFHEAB For a full list of well-known acronyms: diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/no-int-to-ptr.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/no-int-to-ptr.rst index 8233ea13f94e0..dc69f203aac45 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/no-int-to-ptr.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/no-int-to-ptr.rst @@ -7,8 +7,8 @@ Diagnoses every integer to pointer cast. While casting an (integral) pointer to an integer is obvious - you just get the integral value of the pointer, casting an integer to an (integral) pointer -is deceivingly different. While you will get a pointer with that integral value, -if you got that integral value via a pointer-to-integer cast originally, +is deceivingly different. While you will get a pointer with that integral +value, if you got that integral value via a pointer-to-integer cast originally, the new pointer will lack the provenance information from the original pointer. So while (integral) pointer to integer casts are effectively no-ops, diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst index 2901d721706c8..e6d25d9dabf09 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst @@ -3,11 +3,11 @@ performance-noexcept-swap ========================= -The check flags user-defined swap and iter_swap functions not marked with ``noexcept`` or -marked with ``noexcept(expr)`` where ``expr`` evaluates to ``false`` -(but is not a ``false`` literal itself). +The check flags user-defined swap and iter_swap functions not marked with +``noexcept`` or marked with ``noexcept(expr)`` where ``expr`` evaluates to +``false`` (but is not a ``false`` literal itself). -When a swap or iter_swap function is marked as ``noexcept``, it assures the compiler that -no exceptions will be thrown during the swapping of two objects, which allows -the compiler to perform certain optimizations such as omitting exception -handling code. +When a swap or iter_swap function is marked as ``noexcept``, it assures the +compiler that no exceptions will be thrown during the swapping of two objects, +which allows the compiler to perform certain optimizations such as omitting +exception handling code. diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-copy-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-copy-initialization.rst index 0e9d5476e7016..00581b10334ff 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-copy-initialization.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/unnecessary-copy-initialization.rst @@ -9,8 +9,8 @@ const reference. The check is only applied if it is safe to replace the copy by a const reference. This is the case when the variable is const qualified or when it is -only used as a const, i.e. only const methods or operators are invoked on it, or -it is used as const reference or value argument in constructors or function +only used as a const, i.e. only const methods or operators are invoked on it, +or it is used as const reference or value argument in constructors or function calls. Example: diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/simd-intrinsics.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/simd-intrinsics.rst index ab43c2fa58d4c..7ba3a1dd976d8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/simd-intrinsics.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/simd-intrinsics.rst @@ -19,18 +19,18 @@ objects. Otherwise, it just complains the intrinsics are non-portable (and there are `P0214`_ alternatives). -Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power AltiVec/VSX, -ARM NEON). It is common that SIMD code implementing the same algorithm, is -written in multiple target-dispatching pieces to optimize for different -architectures or micro-architectures. +Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power +AltiVec/VSX, ARM NEON). It is common that SIMD code implementing the same +algorithm, is written in multiple target-dispatching pieces to optimize for +different architectures or micro-architectures. The C++ standard proposal `P0214`_ and its extensions cover many common SIMD operations. By migrating from target-dependent intrinsics to `P0214`_ -operations, the SIMD code can be simplified and pieces for different targets can -be unified. +operations, the SIMD code can be simplified and pieces for different targets +can be unified. -Refer to `P0214`_ for introduction and motivation for the data-parallel standard -library. +Refer to `P0214`_ for introduction and motivation for the data-parallel +standard library. Options ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/std-allocator-const.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/std-allocator-const.rst index 31463c2b65dd3..fdde5522a56e2 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/std-allocator-const.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/std-allocator-const.rst @@ -9,11 +9,11 @@ elements). These are not allowed in standard C++, and should usually be Per C++ ``[allocator.requirements.general]``: "T is any cv-unqualified object type", ``std::allocator`` is undefined. Many standard containers use -``std::allocator`` by default and therefore their ``const T`` instantiations are -undefined. +``std::allocator`` by default and therefore their ``const T`` instantiations +are undefined. -libc++ defines ``std::allocator`` as an extension which will be removed -in the future. +libc++ defines ``std::allocator`` as an extension which will be +removed in the future. libstdc++ and MSVC do not support ``std::allocator``: diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst index 913b20f93b438..e21dedfacd5b1 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst @@ -3,16 +3,17 @@ portability-template-virtual-member-function ============================================ -Finds cases when an uninstantiated virtual member function in a template class causes -cross-compiler incompatibility. +Finds cases when an uninstantiated virtual member function in a template class +causes cross-compiler incompatibility. -Upon instantiating a template class, non-virtual member functions don't have to be -instantiated unless they are used. Virtual member function instantiation on the other hand -is unspecified and depends on the implementation of the compiler. +Upon instantiating a template class, non-virtual member functions don't have +to be instantiated unless they are used. Virtual member function instantiation +on the other hand is unspecified and depends on the implementation of the +compiler. -In the following snippets the virtual member function is not instantiated by GCC and Clang, -but it is instantiated by MSVC, so while the snippet is accepted by the former compilers, -it is rejected by the latter. +In the following snippets the virtual member function is not instantiated by +GCC and Clang, but it is instantiated by MSVC, so while the snippet is accepted +by the former compilers, it is rejected by the latter. .. code:: c++ @@ -32,6 +33,7 @@ it is rejected by the latter. return 0; } -Cross-platform projects that need to support MSVC on Windows might see compiler errors -because certain virtual member functions are instantiated, which are not instantiated -by other compilers on other platforms. This check highlights such virtual member functions. +Cross-platform projects that need to support MSVC on Windows might see compiler +errors because certain virtual member functions are instantiated, which are not +instantiated by other compilers on other platforms. This check highlights such +virtual member functions. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-contains.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-contains.rst index 9f5b263f7f671..120d360ab5841 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-contains.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-contains.rst @@ -30,5 +30,5 @@ Initial expression Result This check will apply to any class that has a ``contains`` method, notably including ``std::set``, ``std::unordered_set``, ``std::map``, and -``std::unordered_map`` as of C++20, and ``std::string`` and ``std::string_view`` -as of C++23. +``std::unordered_map`` as of C++20, and ``std::string`` and +``std::string_view`` as of C++23. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst index a4eff16cbab14..4b2ef6ef1fbea 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst @@ -6,11 +6,11 @@ readability-container-data-pointer Finds cases where code could use ``data()`` rather than the address of the element at index 0 in a container. This pattern is commonly used to materialize a pointer to the backing data of a container. ``std::vector`` and -``std::string`` provide a ``data()`` accessor to retrieve the data pointer which -should be preferred. +``std::string`` provide a ``data()`` accessor to retrieve the data pointer +which should be preferred. -This also ensures that in the case that the container is empty, the data pointer -access does not perform an errant memory access. +This also ensures that in the case that the container is empty, the data +pointer access does not perform an errant memory access. Options ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/convert-member-functions-to-static.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/convert-member-functions-to-static.rst index 641cb83d6df04..59f4632109c92 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/convert-member-functions-to-static.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/convert-member-functions-to-static.rst @@ -10,5 +10,6 @@ After applying modifications as suggested by the check, running the check again might find more opportunities to mark member functions ``static``. After making a member function ``static``, you might want to run the check -:doc:`readability-static-accessed-through-instance <../readability/static-accessed-through-instance>` to replace calls like +:doc:`readability-static-accessed-through-instance +<../readability/static-accessed-through-instance>` to replace calls like ``Instance.method()`` by ``Class::method()``. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/delete-null-pointer.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/delete-null-pointer.rst index 21c91b460caf9..08779151de02b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/delete-null-pointer.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/delete-null-pointer.rst @@ -3,7 +3,8 @@ readability-delete-null-pointer =============================== -Checks the ``if`` statements where a pointer's existence is checked and then deletes the pointer. +Checks the ``if`` statements where a pointer's existence is checked and +then deletes the pointer. The check is unnecessary as deleting a null pointer has no effect. .. code:: c++ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/else-after-return.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/else-after-return.rst index 25fb40856f40c..569fa24d81c49 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/else-after-return.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/else-after-return.rst @@ -9,7 +9,8 @@ Early exit is one of the suggested enforcements of that. Please do not use ``else`` or ``else if`` after something that interrupts control flow - like ``return``, ``break``, ``continue``, ``throw``. -The following piece of code illustrates how the check works. This piece of code: +The following piece of code illustrates how the check works. +This piece of code: .. code-block:: c++ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/function-cognitive-complexity.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/function-cognitive-complexity.rst index 3710917f6cee1..430006e68ceb4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/function-cognitive-complexity.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/function-cognitive-complexity.rst @@ -68,8 +68,8 @@ Nesting level ^^^^^^^^^^^^^ While by itself the nesting level does not change the function's Cognitive -Complexity metric, it is tracked, and is used by the next, third building block. -The following structures increase the nesting level (by `1`): +Complexity metric, it is tracked, and is used by the next, third building +block. The following structures increase the nesting level (by `1`): * Conditional operators: diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst index 271970c292c8f..c4d39a28a4cb8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst @@ -16,7 +16,8 @@ The following options are described below: - :option:`MinimumVariableNameLength`, :option:`IgnoredVariableNames` - :option:`MinimumParameterNameLength`, :option:`IgnoredParameterNames` - :option:`MinimumLoopCounterNameLength`, :option:`IgnoredLoopCounterNames` - - :option:`MinimumExceptionNameLength`, :option:`IgnoredExceptionVariableNames` + - :option:`MinimumExceptionNameLength`, + :option:`IgnoredExceptionVariableNames` .. option:: MinimumVariableNameLength diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst index 6c4e0b7dec198..2c0d69f0264e7 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst @@ -31,12 +31,13 @@ The naming of virtual methods is reported where they occur in the base class, but not where they are overridden, as it can't be fixed locally there. This also applies for pseudo-override patterns like CRTP. -``Leading_upper_snake_case`` is a naming convention where the first word is capitalized -followed by lower case word(s) separated by underscore(s) '_'. Examples include: -`Cap_snake_case`, `Cobra_case`, `Foo_bar_baz`, and `Master_copy_8gb`. +``Leading_upper_snake_case`` is a naming convention where the first word is +capitalized followed by lower case word(s) separated by underscore(s) '_'. +Examples include: `Cap_snake_case`, `Cobra_case`, `Foo_bar_baz`, +and `Master_copy_8gb`. -Hungarian notation can be customized using different *HungarianPrefix* settings. -The options and their corresponding values are: +Hungarian notation can be customized using different *HungarianPrefix* +settings. The options and their corresponding values are: - ``Off`` - the default setting - ``On`` - example: ``int iVariable`` @@ -57,62 +58,164 @@ The available options are summarized below: **Specific options** - - :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix` - - :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix` - - :option:`ClassConstexprCase`, :option:`ClassConstexprPrefix`, :option:`ClassConstexprSuffix`, :option:`ClassConstexprIgnoredRegexp`, :option:`ClassConstexprHungarianPrefix` - - :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix` - - :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix` - - :option:`ClassMethodCase`, :option:`ClassMethodPrefix`, :option:`ClassMethodSuffix`, :option:`ClassMethodIgnoredRegexp` - - :option:`ConceptCase`, :option:`ConceptPrefix`, :option:`ConceptSuffix`, :option:`ConceptIgnoredRegexp` - - :option:`ConstantCase`, :option:`ConstantPrefix`, :option:`ConstantSuffix`, :option:`ConstantIgnoredRegexp`, :option:`ConstantHungarianPrefix` - - :option:`ConstantMemberCase`, :option:`ConstantMemberPrefix`, :option:`ConstantMemberSuffix`, :option:`ConstantMemberIgnoredRegexp`, :option:`ConstantMemberHungarianPrefix` - - :option:`ConstantParameterCase`, :option:`ConstantParameterPrefix`, :option:`ConstantParameterSuffix`, :option:`ConstantParameterIgnoredRegexp`, :option:`ConstantParameterHungarianPrefix` - - :option:`ConstantPointerParameterCase`, :option:`ConstantPointerParameterPrefix`, :option:`ConstantPointerParameterSuffix`, :option:`ConstantPointerParameterIgnoredRegexp`, :option:`ConstantPointerParameterHungarianPrefix` - - :option:`ConstexprFunctionCase`, :option:`ConstexprFunctionPrefix`, :option:`ConstexprFunctionSuffix`, :option:`ConstexprFunctionIgnoredRegexp` - - :option:`ConstexprMethodCase`, :option:`ConstexprMethodPrefix`, :option:`ConstexprMethodSuffix`, :option:`ConstexprMethodIgnoredRegexp` - - :option:`ConstexprVariableCase`, :option:`ConstexprVariablePrefix`, :option:`ConstexprVariableSuffix`, :option:`ConstexprVariableIgnoredRegexp`, :option:`ConstexprVariableHungarianPrefix` - - :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp` - - :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix` - - :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp` - - :option:`GlobalConstexprVariableCase`, :option:`GlobalConstexprVariablePrefix`, :option:`GlobalConstexprVariableSuffix`, :option:`GlobalConstexprVariableIgnoredRegexp`, :option:`GlobalConstexprVariableHungarianPrefix` - - :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix` - - :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix` - - :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp` - - :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix` - - :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix` - - :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp` - - :option:`LocalConstexprVariableCase`, :option:`LocalConstexprVariablePrefix`, :option:`LocalConstexprVariableSuffix`, :option:`LocalConstexprVariableIgnoredRegexp`, :option:`LocalConstexprVariableHungarianPrefix` - - :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix` - - :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix` - - :option:`LocalPointerCase`, :option:`LocalPointerPrefix`, :option:`LocalPointerSuffix`, :option:`LocalPointerIgnoredRegexp`, :option:`LocalPointerHungarianPrefix` - - :option:`LocalVariableCase`, :option:`LocalVariablePrefix`, :option:`LocalVariableSuffix`, :option:`LocalVariableIgnoredRegexp`, :option:`LocalVariableHungarianPrefix` - - :option:`MacroDefinitionCase`, :option:`MacroDefinitionPrefix`, :option:`MacroDefinitionSuffix`, :option:`MacroDefinitionIgnoredRegexp` - - :option:`MemberCase`, :option:`MemberPrefix`, :option:`MemberSuffix`, :option:`MemberIgnoredRegexp`, :option:`MemberHungarianPrefix` - - :option:`MethodCase`, :option:`MethodPrefix`, :option:`MethodSuffix`, :option:`MethodIgnoredRegexp` - - :option:`NamespaceCase`, :option:`NamespacePrefix`, :option:`NamespaceSuffix`, :option:`NamespaceIgnoredRegexp` - - :option:`ParameterCase`, :option:`ParameterPrefix`, :option:`ParameterSuffix`, :option:`ParameterIgnoredRegexp`, :option:`ParameterHungarianPrefix` - - :option:`ParameterPackCase`, :option:`ParameterPackPrefix`, :option:`ParameterPackSuffix`, :option:`ParameterPackIgnoredRegexp` - - :option:`PointerParameterCase`, :option:`PointerParameterPrefix`, :option:`PointerParameterSuffix`, :option:`PointerParameterIgnoredRegexp`, :option:`PointerParameterHungarianPrefix` - - :option:`PrivateMemberCase`, :option:`PrivateMemberPrefix`, :option:`PrivateMemberSuffix`, :option:`PrivateMemberIgnoredRegexp`, :option:`PrivateMemberHungarianPrefix` - - :option:`PrivateMethodCase`, :option:`PrivateMethodPrefix`, :option:`PrivateMethodSuffix`, :option:`PrivateMethodIgnoredRegexp` - - :option:`ProtectedMemberCase`, :option:`ProtectedMemberPrefix`, :option:`ProtectedMemberSuffix`, :option:`ProtectedMemberIgnoredRegexp`, :option:`ProtectedMemberHungarianPrefix` - - :option:`ProtectedMethodCase`, :option:`ProtectedMethodPrefix`, :option:`ProtectedMethodSuffix`, :option:`ProtectedMethodIgnoredRegexp` - - :option:`PublicMemberCase`, :option:`PublicMemberPrefix`, :option:`PublicMemberSuffix`, :option:`PublicMemberIgnoredRegexp`, :option:`PublicMemberHungarianPrefix` - - :option:`PublicMethodCase`, :option:`PublicMethodPrefix`, :option:`PublicMethodSuffix`, :option:`PublicMethodIgnoredRegexp` - - :option:`ScopedEnumConstantCase`, :option:`ScopedEnumConstantPrefix`, :option:`ScopedEnumConstantSuffix`, :option:`ScopedEnumConstantIgnoredRegexp` - - :option:`StaticConstexprVariableCase`, :option:`StaticConstexprVariablePrefix`, :option:`StaticConstexprVariableSuffix`, :option:`StaticConstexprVariableIgnoredRegexp`, :option:`StaticConstexprVariableHungarianPrefix` - - :option:`StaticConstantCase`, :option:`StaticConstantPrefix`, :option:`StaticConstantSuffix`, :option:`StaticConstantIgnoredRegexp`, :option:`StaticConstantHungarianPrefix` - - :option:`StaticVariableCase`, :option:`StaticVariablePrefix`, :option:`StaticVariableSuffix`, :option:`StaticVariableIgnoredRegexp`, :option:`StaticVariableHungarianPrefix` - - :option:`StructCase`, :option:`StructPrefix`, :option:`StructSuffix`, :option:`StructIgnoredRegexp` - - :option:`TemplateParameterCase`, :option:`TemplateParameterPrefix`, :option:`TemplateParameterSuffix`, :option:`TemplateParameterIgnoredRegexp` - - :option:`TemplateTemplateParameterCase`, :option:`TemplateTemplateParameterPrefix`, :option:`TemplateTemplateParameterSuffix`, :option:`TemplateTemplateParameterIgnoredRegexp` - - :option:`TypeAliasCase`, :option:`TypeAliasPrefix`, :option:`TypeAliasSuffix`, :option:`TypeAliasIgnoredRegexp` - - :option:`TypedefCase`, :option:`TypedefPrefix`, :option:`TypedefSuffix`, :option:`TypedefIgnoredRegexp` - - :option:`TypeTemplateParameterCase`, :option:`TypeTemplateParameterPrefix`, :option:`TypeTemplateParameterSuffix`, :option:`TypeTemplateParameterIgnoredRegexp` - - :option:`UnionCase`, :option:`UnionPrefix`, :option:`UnionSuffix`, :option:`UnionIgnoredRegexp` - - :option:`ValueTemplateParameterCase`, :option:`ValueTemplateParameterPrefix`, :option:`ValueTemplateParameterSuffix`, :option:`ValueTemplateParameterIgnoredRegexp` - - :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix` - - :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp` + - :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, + :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, + :option:`AbstractClassHungarianPrefix` + - :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, + :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix` + - :option:`ClassConstexprCase`, :option:`ClassConstexprPrefix`, + :option:`ClassConstexprSuffix`, :option:`ClassConstexprIgnoredRegexp`, + :option:`ClassConstexprHungarianPrefix` + - :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, + :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, + :option:`ClassConstantHungarianPrefix` + - :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, + :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, + :option:`ClassMemberHungarianPrefix` + - :option:`ClassMethodCase`, :option:`ClassMethodPrefix`, + :option:`ClassMethodSuffix`, :option:`ClassMethodIgnoredRegexp` + - :option:`ConceptCase`, :option:`ConceptPrefix`, :option:`ConceptSuffix`, + :option:`ConceptIgnoredRegexp` + - :option:`ConstantCase`, :option:`ConstantPrefix`, :option:`ConstantSuffix`, + :option:`ConstantIgnoredRegexp`, :option:`ConstantHungarianPrefix` + - :option:`ConstantMemberCase`, :option:`ConstantMemberPrefix`, + :option:`ConstantMemberSuffix`, :option:`ConstantMemberIgnoredRegexp`, + :option:`ConstantMemberHungarianPrefix` + - :option:`ConstantParameterCase`, :option:`ConstantParameterPrefix`, + :option:`ConstantParameterSuffix`, :option:`ConstantParameterIgnoredRegexp`, + :option:`ConstantParameterHungarianPrefix` + - :option:`ConstantPointerParameterCase`, + :option:`ConstantPointerParameterPrefix`, + :option:`ConstantPointerParameterSuffix`, + :option:`ConstantPointerParameterIgnoredRegexp`, + :option:`ConstantPointerParameterHungarianPrefix` + - :option:`ConstexprFunctionCase`, :option:`ConstexprFunctionPrefix`, + :option:`ConstexprFunctionSuffix`, :option:`ConstexprFunctionIgnoredRegexp` + - :option:`ConstexprMethodCase`, :option:`ConstexprMethodPrefix`, + :option:`ConstexprMethodSuffix`, :option:`ConstexprMethodIgnoredRegexp` + - :option:`ConstexprVariableCase`, :option:`ConstexprVariablePrefix`, + :option:`ConstexprVariableSuffix`, :option:`ConstexprVariableIgnoredRegexp`, + :option:`ConstexprVariableHungarianPrefix` + - :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, + :option:`EnumIgnoredRegexp` + - :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, + :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, + :option:`EnumConstantHungarianPrefix` + - :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, + :option:`FunctionIgnoredRegexp` + - :option:`GlobalConstexprVariableCase`, + :option:`GlobalConstexprVariablePrefix`, + :option:`GlobalConstexprVariableSuffix`, + :option:`GlobalConstexprVariableIgnoredRegexp`, + :option:`GlobalConstexprVariableHungarianPrefix` + - :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, + :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, + :option:`GlobalConstantHungarianPrefix` + - :option:`GlobalConstantPointerCase`, + :option:`GlobalConstantPointerPrefix`, + :option:`GlobalConstantPointerSuffix`, + :option:`GlobalConstantPointerIgnoredRegexp`, + :option:`GlobalConstantPointerHungarianPrefix` + - :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, + :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp` + - :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, + :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, + :option:`GlobalPointerHungarianPrefix` + - :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, + :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, + :option:`GlobalVariableHungarianPrefix` + - :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, + :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp` + - :option:`LocalConstexprVariableCase`, + :option:`LocalConstexprVariablePrefix`, + :option:`LocalConstexprVariableSuffix`, + :option:`LocalConstexprVariableIgnoredRegexp`, + :option:`LocalConstexprVariableHungarianPrefix` + - :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, + :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, + :option:`LocalConstantHungarianPrefix` + - :option:`LocalConstantPointerCase`, + :option:`LocalConstantPointerPrefix`, + :option:`LocalConstantPointerSuffix`, + :option:`LocalConstantPointerIgnoredRegexp`, + :option:`LocalConstantPointerHungarianPrefix` + - :option:`LocalPointerCase`, :option:`LocalPointerPrefix`, + :option:`LocalPointerSuffix`, :option:`LocalPointerIgnoredRegexp`, + :option:`LocalPointerHungarianPrefix` + - :option:`LocalVariableCase`, :option:`LocalVariablePrefix`, + :option:`LocalVariableSuffix`, :option:`LocalVariableIgnoredRegexp`, + :option:`LocalVariableHungarianPrefix` + - :option:`MacroDefinitionCase`, :option:`MacroDefinitionPrefix`, + :option:`MacroDefinitionSuffix`, :option:`MacroDefinitionIgnoredRegexp` + - :option:`MemberCase`, :option:`MemberPrefix`, :option:`MemberSuffix`, + :option:`MemberIgnoredRegexp`, :option:`MemberHungarianPrefix` + - :option:`MethodCase`, :option:`MethodPrefix`, :option:`MethodSuffix`, + :option:`MethodIgnoredRegexp` + - :option:`NamespaceCase`, :option:`NamespacePrefix`, + :option:`NamespaceSuffix`, :option:`NamespaceIgnoredRegexp` + - :option:`ParameterCase`, :option:`ParameterPrefix`, + :option:`ParameterSuffix`, :option:`ParameterIgnoredRegexp`, + :option:`ParameterHungarianPrefix` + - :option:`ParameterPackCase`, :option:`ParameterPackPrefix`, + :option:`ParameterPackSuffix`, :option:`ParameterPackIgnoredRegexp` + - :option:`PointerParameterCase`, :option:`PointerParameterPrefix`, + :option:`PointerParameterSuffix`, :option:`PointerParameterIgnoredRegexp`, + :option:`PointerParameterHungarianPrefix` + - :option:`PrivateMemberCase`, :option:`PrivateMemberPrefix`, + :option:`PrivateMemberSuffix`, :option:`PrivateMemberIgnoredRegexp`, + :option:`PrivateMemberHungarianPrefix` + - :option:`PrivateMethodCase`, :option:`PrivateMethodPrefix`, + :option:`PrivateMethodSuffix`, :option:`PrivateMethodIgnoredRegexp` + - :option:`ProtectedMemberCase`, :option:`ProtectedMemberPrefix`, + :option:`ProtectedMemberSuffix`, :option:`ProtectedMemberIgnoredRegexp`, + :option:`ProtectedMemberHungarianPrefix` + - :option:`ProtectedMethodCase`, :option:`ProtectedMethodPrefix`, + :option:`ProtectedMethodSuffix`, :option:`ProtectedMethodIgnoredRegexp` + - :option:`PublicMemberCase`, :option:`PublicMemberPrefix`, + :option:`PublicMemberSuffix`, :option:`PublicMemberIgnoredRegexp`, + :option:`PublicMemberHungarianPrefix` + - :option:`PublicMethodCase`, :option:`PublicMethodPrefix`, + :option:`PublicMethodSuffix`, :option:`PublicMethodIgnoredRegexp` + - :option:`ScopedEnumConstantCase`, :option:`ScopedEnumConstantPrefix`, + :option:`ScopedEnumConstantSuffix`, + :option:`ScopedEnumConstantIgnoredRegexp` + - :option:`StaticConstexprVariableCase`, + :option:`StaticConstexprVariablePrefix`, + :option:`StaticConstexprVariableSuffix`, + :option:`StaticConstexprVariableIgnoredRegexp`, + :option:`StaticConstexprVariableHungarianPrefix` + - :option:`StaticConstantCase`, :option:`StaticConstantPrefix`, + :option:`StaticConstantSuffix`, :option:`StaticConstantIgnoredRegexp`, + :option:`StaticConstantHungarianPrefix` + - :option:`StaticVariableCase`, :option:`StaticVariablePrefix`, + :option:`StaticVariableSuffix`, :option:`StaticVariableIgnoredRegexp`, + :option:`StaticVariableHungarianPrefix` + - :option:`StructCase`, :option:`StructPrefix`, :option:`StructSuffix`, + :option:`StructIgnoredRegexp` + - :option:`TemplateParameterCase`, :option:`TemplateParameterPrefix`, + :option:`TemplateParameterSuffix`, :option:`TemplateParameterIgnoredRegexp` + - :option:`TemplateTemplateParameterCase`, + :option:`TemplateTemplateParameterPrefix`, + :option:`TemplateTemplateParameterSuffix`, + :option:`TemplateTemplateParameterIgnoredRegexp` + - :option:`TypeAliasCase`, :option:`TypeAliasPrefix`, + :option:`TypeAliasSuffix`, :option:`TypeAliasIgnoredRegexp` + - :option:`TypedefCase`, :option:`TypedefPrefix`, :option:`TypedefSuffix`, + :option:`TypedefIgnoredRegexp` + - :option:`TypeTemplateParameterCase`, + :option:`TypeTemplateParameterPrefix`, + :option:`TypeTemplateParameterSuffix`, + :option:`TypeTemplateParameterIgnoredRegexp` + - :option:`UnionCase`, :option:`UnionPrefix`, :option:`UnionSuffix`, + :option:`UnionIgnoredRegexp` + - :option:`ValueTemplateParameterCase`, + :option:`ValueTemplateParameterPrefix`, + :option:`ValueTemplateParameterSuffix`, + :option:`ValueTemplateParameterIgnoredRegexp` + - :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, + :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix` + - :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, + :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp` Options description @@ -1608,8 +1711,8 @@ After: #define pre_my_macro_definition_post -Note: This will not warn on builtin macros or macros defined on the command line -using the ``-D`` flag. +Note: This will not warn on builtin macros or macros defined on the +command line using the ``-D`` flag. .. option:: MemberCase @@ -2804,44 +2907,45 @@ distinguished as the given name. The first character of the given name can be capitalized to separate it from the type indicators (see also CamelCase). Otherwise the case of this character denotes scope. -The following table is the default mapping table of Hungarian Notation which -maps Decl to its prefix string. You can also have your own style in config file. - -================= ============== ====================== ============== ============== ============== -Primitive Type Microsoft Type ------------------ -------------- ---------------------- -------------- -------------- -------------- - Type Prefix Type Prefix Type Prefix -================= ============== ====================== ============== ============== ============== -int8_t i8 signed int si BOOL b -int16_t i16 signed short ss BOOLEAN b -int32_t i32 signed short int ssi BYTE by -int64_t i64 signed long long int slli CHAR c -uint8_t u8 signed long long sll UCHAR uc -uint16_t u16 signed long int sli SHORT s -uint32_t u32 signed long sl USHORT us -uint64_t u64 signed s WORD w -char8_t c8 unsigned long long int ulli DWORD dw -char16_t c16 unsigned long long ull DWORD32 dw32 -char32_t c32 unsigned long int uli DWORD64 dw64 -float f unsigned long ul LONG l -double d unsigned short int usi ULONG ul -char c unsigned short us ULONG32 ul32 -bool b unsigned int ui ULONG64 ul64 -_Bool b unsigned char uc ULONGLONG ull -int i unsigned u HANDLE h -size_t n long long int lli INT i -short s long double ld INT8 i8 -signed i long long ll INT16 i16 -unsigned u long int li INT32 i32 -long l long l INT64 i64 -long long ll ptrdiff_t p UINT ui -unsigned long ul void *none* UINT8 u8 -long double ld UINT16 u16 -ptrdiff_t p UINT32 u32 -wchar_t wc UINT64 u64 -short int si PVOID p -short s -================= ============== ====================== ============== ============== ============== +The following table is the default mapping table of Hungarian Notation +which maps Decl to its prefix string. You can also have your own style +in config file. + +============== ======== ====================== ======== ============== ======== +Primitive Type Microsoft Type +-------------- -------- ---------------------- -------- -------------- -------- + Type Prefix Type Prefix Type Prefix +============== ======== ====================== ======== ============== ======== +int8_t i8 signed int si BOOL b +int16_t i16 signed short ss BOOLEAN b +int32_t i32 signed short int ssi BYTE by +int64_t i64 signed long long int slli CHAR c +uint8_t u8 signed long long sll UCHAR uc +uint16_t u16 signed long int sli SHORT s +uint32_t u32 signed long sl USHORT us +uint64_t u64 signed s WORD w +char8_t c8 unsigned long long int ulli DWORD dw +char16_t c16 unsigned long long ull DWORD32 dw32 +char32_t c32 unsigned long int uli DWORD64 dw64 +float f unsigned long ul LONG l +double d unsigned short int usi ULONG ul +char c unsigned short us ULONG32 ul32 +bool b unsigned int ui ULONG64 ul64 +_Bool b unsigned char uc ULONGLONG ull +int i unsigned u HANDLE h +size_t n long long int lli INT i +short s long double ld INT8 i8 +signed i long long ll INT16 i16 +unsigned u long int li INT32 i32 +long l long l INT64 i64 +long long ll ptrdiff_t p UINT ui +unsigned long ul void *none* UINT8 u8 +long double ld UINT16 u16 +ptrdiff_t p UINT32 u32 +wchar_t wc UINT64 u64 +short int si PVOID p +short s +============== ======== ====================== ======== ============== ======== **There are more trivial options for Hungarian Notation:** diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst index 88cff387f4c16..3a37b25023129 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst @@ -4,9 +4,9 @@ readability-implicit-bool-conversion ==================================== This check can be used to find implicit conversions between built-in types and -booleans. Depending on use case, it may simply help with readability of the code, -or in some cases, point to potential bugs which remain unnoticed due to implicit -conversions. +booleans. Depending on use case, it may simply help with readability of the +code, or in some cases, point to potential bugs which remain unnoticed due to +implicit conversions. The following is a real-world example of bug which was hiding behind implicit ``bool`` conversion: diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/make-member-function-const.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/make-member-function-const.rst index 5d1f8d1239b01..73059e26378de 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/make-member-function-const.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/make-member-function-const.rst @@ -37,7 +37,8 @@ In addition, this check ignores functions that * are templated or part of a class template * have an empty body * do not (implicitly) use ``this`` at all - (see :doc:`readability-convert-member-functions-to-static <../readability/convert-member-functions-to-static>`). + (see :doc:`readability-convert-member-functions-to-static + <../readability/convert-member-functions-to-static>`). The following real-world examples will be preserved by the check: diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst index 59f17ebc2d08b..9bc98d5ccc6c9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst @@ -3,15 +3,16 @@ readability-math-missing-parentheses ==================================== -Check for missing parentheses in mathematical expressions that involve operators -of different priorities. +Check for missing parentheses in mathematical expressions that involve +operators of different priorities. Parentheses in mathematical expressions clarify the order -of operations, especially with different-priority operators. Lengthy or multiline -expressions can obscure this order, leading to coding errors. IDEs can aid clarity -by highlighting parentheses. Explicitly using parentheses also clarifies what the -developer had in mind when writing the expression. Ensuring their presence reduces -ambiguity and errors, promoting clearer and more maintainable code. +of operations, especially with different-priority operators. Lengthy or +multiline expressions can obscure this order, leading to coding errors. +IDEs can aid clarity by highlighting parentheses. Explicitly using parentheses +also clarifies what the developer had in mind when writing the expression. +Ensuring their presence reduces ambiguity and errors, promoting clearer and +more maintainable code. Before: diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/named-parameter.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/named-parameter.rst index 48b7e84d38ec8..0dd25e23fc653 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/named-parameter.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/named-parameter.rst @@ -10,8 +10,9 @@ Guide: https://google.github.io/styleguide/cppguide.html#Function_Declarations_and_Definitions -All parameters should have the same name in both the function declaration and definition. -If a parameter is not utilized, its name can be commented out in a function definition. +All parameters should have the same name in both the function declaration and +definition. If a parameter is not utilized, its name can be commented out in a +function definition. .. code-block:: c++ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst index b84f7a1c40bd4..70cf75b72ff78 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/operators-representation.rst @@ -69,9 +69,10 @@ To configure check to enforce Alternative Token Representation for all operators set options to `and;and_eq;bitand;bitor;compl;not;not_eq;or;or_eq;xor;xor_eq`. -Developers do not need to enforce all operators, and can mix the representations -as desired by specifying a semicolon-separated list of both traditional and -alternative tokens in the configuration, such as `and;||;not`. +Developers do not need to enforce all operators, and can mix the +representations as desired by specifying a semicolon-separated list of +both traditional and alternative tokens in the configuration, +such as `and;||;not`. .. option:: BinaryOperators diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst index 23eaa225f03a3..4b6c14ba1cf87 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst @@ -18,9 +18,9 @@ In this example, the ``static_cast(value)`` is redundant, as it performs a cast from an ``int`` to another ``int``. Casting operations involving constructor conversions, user-defined conversions, -functional casts, type-dependent casts, casts between distinct type aliases that -refer to the same underlying type, as well as bitfield-related casts and casts -directly from lvalue to rvalue, are all disregarded by the check. +functional casts, type-dependent casts, casts between distinct type aliases +that refer to the same underlying type, as well as bitfield-related casts and +casts directly from lvalue to rvalue, are all disregarded by the check. Options ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-control-flow.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-control-flow.rst index aeaf345b99e74..ac435af2ac1aa 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-control-flow.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-control-flow.rst @@ -4,7 +4,8 @@ readability-redundant-control-flow ================================== This check looks for procedures (functions returning no value) with ``return`` -statements at the end of the function. Such ``return`` statements are redundant. +statements at the end of the function. Such ``return`` statements are +redundant. Loop statements (``for``, ``while``, ``do while``) are checked for redundant ``continue`` statements at the end of the loop body. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst index 7b507771d6799..84495a5605bec 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst @@ -4,7 +4,8 @@ readability-redundant-string-cstr ================================= -Finds unnecessary calls to ``std::string::c_str()`` and ``std::string::data()``. +Finds unnecessary calls to ``std::string::c_str()`` and +``std::string::data()``. Options ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/reference-to-constructed-temporary.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/reference-to-constructed-temporary.rst index 09fd0c735fe78..5f1aea1a7ba5c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/reference-to-constructed-temporary.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/reference-to-constructed-temporary.rst @@ -23,10 +23,10 @@ Examples of problematic code include: In the first example, a ``const std::string&`` reference variable ``str`` is assigned a temporary object created by the ``std::string("hello")`` constructor. In the second example, a ``const Point&`` reference variable ``p`` -is assigned an object that is constructed from an initializer list ``{ 1, 2 }``. -Both of these examples extend the lifetime of the temporary object to the -lifetime of the reference variable, which can make it difficult to reason about -and may lead to subtle bugs or misunderstanding. +is assigned an object that is constructed from an initializer list +``{ 1, 2 }``. Both of these examples extend the lifetime of the temporary +object to the lifetime of the reference variable, which can make it difficult +to reason about and may lead to subtle bugs or misunderstanding. To avoid these issues, it is recommended to change the reference variable to a (``const``) value variable. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/simplify-boolean-expr.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/simplify-boolean-expr.rst index 3d00d5b043a60..5b733e5eaf4d7 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/simplify-boolean-expr.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/simplify-boolean-expr.rst @@ -75,8 +75,9 @@ Examples: an implicit conversion of an integer quantity ``i & 1`` to ``bool`` and becomes ``return (i & 1) != 0;`` - 6. Given ``struct X { explicit operator bool(); };``, and an instance ``x`` of - ``struct X``, the conditional return ``if (x) return true; return false;`` + 6. Given ``struct X { explicit operator bool(); };``, and an instance ``x`` + of ``struct X``, the conditional return + ``if (x) return true; return false;`` becomes ``return static_cast(x);`` Options diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst index 4be2473bed2d7..db9bec2ca8509 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst @@ -8,11 +8,11 @@ Finds string comparisons using the compare method. A common mistake is to use the string's ``compare`` method instead of using the equality or inequality operators. The compare method is intended for sorting functions and thus returns a negative number, a positive number or -zero depending on the lexicographical relationship between the strings compared. -If an equality or inequality check can suffice, that is recommended. This is -recommended to avoid the risk of incorrect interpretation of the return value -and to simplify the code. The string equality and inequality operators can -also be faster than the ``compare`` method due to early termination. +zero depending on the lexicographical relationship between the strings +compared. If an equality or inequality check can suffice, that is recommended. +This is recommended to avoid the risk of incorrect interpretation of the return +value and to simplify the code. The string equality and inequality operators +can also be faster than the ``compare`` method due to early termination. Example ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/suspicious-call-argument.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/suspicious-call-argument.rst index 03d9bbacf444e..2b3a265d4af7f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/suspicious-call-argument.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/suspicious-call-argument.rst @@ -235,8 +235,8 @@ Parameter names are the identifiers as written in the source code. Argument names are: * If a variable is passed, the variable's name. - * If a subsequent function call's return value is used as argument, the called - function's name. + * If a subsequent function call's return value is used as argument, the + called function's name. * Otherwise, empty string. Empty argument or parameter names are ignored by the heuristics. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/uppercase-literal-suffix.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/uppercase-literal-suffix.rst index f2809dbc0b5f9..dcedfb10c05b6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/uppercase-literal-suffix.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/uppercase-literal-suffix.rst @@ -10,8 +10,8 @@ By default, only the suffixes that begin with ``l`` (``l``, ``ll``, ``lu``, `hicpp-uppercase-literal-suffix` redirects here as an alias for this check. Detects when the integral literal or floating point (decimal or hexadecimal) -literal has a non-uppercase suffix and provides a fix-it hint with the uppercase -suffix. +literal has a non-uppercase suffix and provides a fix-it hint with the +uppercase suffix. All valid combinations of suffixes are supported. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst index 6e58766275107..cfbc551bf07c0 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst @@ -3,9 +3,9 @@ readability-use-anyofallof ========================== -Finds range-based for loops that can be replaced by a call to ``std::any_of`` or -``std::all_of``. In C++20 mode, suggests ``std::ranges::any_of`` or -``std::ranges::all_of``. +Finds range-based for loops that can be replaced by a call to +``std::any_of`` or ``std::all_of``. In C++20 mode, suggests +``std::ranges::any_of`` or ``std::ranges::all_of``. Example: diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f2d8eb43b15a7..2891af65611a0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -348,6 +348,10 @@ Attribute Changes in Clang - New format attributes ``gnu_printf``, ``gnu_scanf``, ``gnu_strftime`` and ``gnu_strfmon`` are added as aliases for ``printf``, ``scanf``, ``strftime`` and ``strfmon``. (#GH16219) +- New function attribute `malloc_span` is added. It has semantics similar to that of the `malloc` + attribute, but `malloc_span` applies not to functions returning pointers, but to functions returning + span-like structures (i.e. those that contain a pointer field and a size integer field or two pointers). + Improvements to Clang's diagnostics ----------------------------------- @@ -677,6 +681,8 @@ Improvements to Clang's diagnostics or continue (#GH166013) - Clang now emits a diagnostic in case `vector_size` or `ext_vector_type` attributes are used with a negative size (#GH165463). +- Clang no longer emits ``-Wmissing-noreturn`` for virtual methods where + the function body consists of a `throw` expression (#GH167247). Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index ae8029797a36e..ad4e2d65771b8 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -818,14 +818,57 @@ class OpenACCAtomicConstruct final // A struct to represent a broken-down version of the associated statement, // providing the information specified in OpenACC3.3 Section 2.12. - struct StmtInfo { + struct SingleStmtInfo { + // Holds the entire expression for this. In the case of a normal + // read/write/update, this should just be the associated statement. in the + // case of an update, this is going to be the sub-expression this + // represents. + const Expr *WholeExpr; const Expr *V; const Expr *X; // Listed as 'expr' in the standard, this is typically a generic expression // as a component. const Expr *RefExpr; - // TODO: OpenACC: We should expand this as we're implementing the other - // atomic construct kinds. + static SingleStmtInfo Empty() { + return {nullptr, nullptr, nullptr, nullptr}; + } + + static SingleStmtInfo createRead(const Expr *WholeExpr, const Expr *V, + const Expr *X) { + return {WholeExpr, V, X, /*RefExpr=*/nullptr}; + } + static SingleStmtInfo createWrite(const Expr *WholeExpr, const Expr *X, + const Expr *RefExpr) { + return {WholeExpr, /*V=*/nullptr, X, RefExpr}; + } + static SingleStmtInfo createUpdate(const Expr *WholeExpr, const Expr *X) { + return {WholeExpr, /*V=*/nullptr, X, /*RefExpr=*/nullptr}; + } + }; + + struct StmtInfo { + enum class StmtForm { + Read, + Write, + Update, + ReadWrite, + ReadUpdate, + UpdateRead + } Form; + SingleStmtInfo First, Second; + + static StmtInfo createUpdateRead(SingleStmtInfo First, + SingleStmtInfo Second) { + return {StmtForm::UpdateRead, First, Second}; + } + static StmtInfo createReadWrite(SingleStmtInfo First, + SingleStmtInfo Second) { + return {StmtForm::ReadWrite, First, Second}; + } + static StmtInfo createReadUpdate(SingleStmtInfo First, + SingleStmtInfo Second) { + return {StmtForm::ReadUpdate, First, Second}; + } }; const StmtInfo getAssociatedStmtInfo() const; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0097476bc0d8d..8e5f7ef0bb82d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2072,6 +2072,12 @@ def Restrict : InheritableAttr { let Documentation = [RestrictDocs]; } +def MallocSpan : InheritableAttr { + let Spellings = [Clang<"malloc_span">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MallocSpanDocs]; +} + def LayoutVersion : InheritableAttr, TargetSpecificAttr { let Spellings = [Declspec<"layout_version">]; let Args = [UnsignedArgument<"Version">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 4813191d2d602..c1b1510f363d4 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5247,6 +5247,23 @@ yet implemented in clang. }]; } +def MallocSpanDocs : Documentation { + let Category = DocCatFunction; + let Heading = "malloc_span"; + let Content = [{ +The ``malloc_span`` attribute can be used to mark that a function which acts +like a system memory allocation function and returns a span-like structure, +where the returned memory range does not alias storage from any other object +accessible to the caller. + +In this context, a span-like structure is assumed to have two non-static data +members, one of which is a pointer to the start of the allocated memory and +the other one is either an integer type containing the size of the actually +allocated memory or a pointer to the end of the allocated region. Note, static +data members do not impact whether a type is span-like or not. + }]; +} + def ReturnsNonNullDocs : Documentation { let Category = NullabilityDocs; let Content = [{ diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index 3a5e31de2bc50..324e0deb241ab 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -19,6 +19,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringTable.h" +#include "llvm/TargetParser/Triple.h" #include // VC++ defines 'alloca' as an object-like macro, which interferes with our @@ -405,6 +406,22 @@ class Context { return strchr(getAttributesString(ID), 'g') != nullptr; } + /// Determine whether we can generate LLVM intrinsics for the given + /// builtin ID, based on whether it has side effects such as setting errno. + /// + /// \param BuiltinID The builtin ID to check. + /// \param Trip The target triple. + /// \param ErrnoOverwritten Indicates whether the errno setting behavior + /// has been overwritten via '#pragma float_control(precise, on/off)'. + /// \param MathErrnoEnabled Indicates whether math-errno is enabled on + /// command line. + /// \param HasOptNoneAttr True iff 'attribute__((optnone))' is used. + /// \param IsOptimizationEnabled True iff the optimization level is not 'O0'. + bool shouldGenerateFPMathIntrinsic(unsigned BuiltinID, llvm::Triple Trip, + std::optional ErrnoOverwritten, + bool MathErrnoEnabled, bool HasOptNoneAttr, + bool IsOptimizationEnabled) const; + const char *getRequiredFeatures(unsigned ID) const; unsigned getRequiredVectorWidth(unsigned ID) const; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f4aa20d0a25e4..75e2703b6f997 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3445,6 +3445,24 @@ def err_attribute_integers_only : Error< def warn_attribute_return_pointers_only : Warning< "%0 attribute only applies to return values that are pointers">, InGroup; +def warn_attribute_return_span_only + : Warning<"%0 attribute only applies to functions that return span-like " + "structures">, + InGroup; +def note_returned_not_struct : Note<"returned type is not a struct type">; +def note_returned_incomplete_type : Note<"returned type is incomplete">; +def note_returned_not_two_field_struct + : Note<"returned struct has %0 fields, expected 2">; +def note_returned_not_span_struct + : Note<"returned struct fields are not a supported combination for a " + "span-like type (expected pointer/integer or pointer/pointer)">; +def note_returned_not_integer_field + : Note<"%ordinal0 field is expected to be an integer">; +def note_returned_not_wide_enough_field + : Note<"%ordinal0 field of span-like type is not a wide enough integer " + "(minimum width: %1)">; +def note_type_inherits_from_base + : Note<"returned type inherits from a base class">; def warn_attribute_return_pointers_refs_only : Warning< "%0 attribute only applies to return values that are pointers or references">, InGroup; diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e612d6a0ba886..06e0796959c8f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4658,6 +4658,44 @@ def CIR_TryOp : CIR_Op<"try",[ let hasLLVMLowering = false; } +//===----------------------------------------------------------------------===// +// Exception related: EhInflightOp +//===----------------------------------------------------------------------===// + +def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> { + let summary = "Materialize the catch clause formal parameter"; + let description = [{ + `cir.eh.inflight_exception` returns two values: + - `exception_ptr`: The exception pointer for the inflight exception + - `type_id`: the type info index for the exception type + This operation is expected to be the first operation in the unwind + destination basic blocks of a `cir.try_call` operation. + + The `cleanup` attribute indicates that clean up code must be run before the + values produced by this operation are used to dispatch the exception. This + cleanup code must be executed even if the exception is not caught. + This helps CIR to pass down more accurate information for LLVM lowering + to landingpads. + + Example: + + ```mlir + %exception_ptr, %type_id = cir.eh.inflight_exception + %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] + %exception_ptr, %type_id = cir.eh.inflight_exception cleanup + `` + }]; + + let arguments = (ins UnitAttr:$cleanup, + OptionalAttr:$catch_type_list); + let results = (outs CIR_VoidPtrType:$exception_ptr, CIR_UInt32:$type_id); + let assemblyFormat = [{ + (`cleanup` $cleanup^)? + ($catch_type_list^)? + attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fd2a2469142e4..cbfcc9bc0ea99 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5111,6 +5111,11 @@ class Sema final : public SemaBase { /// Essentially, this just moves them to the current pool. void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); + /// Check that the type is a plain record with one field being a pointer + /// type and the other field being an integer. This matches the common + /// implementation of std::span or sized_allocation_t in P0901R11. + bool CheckSpanLikeType(const AttributeCommonInfo &CI, const QualType &Ty); + /// Check if IdxExpr is a valid parameter index for a function or /// instance method D. May output an error. /// diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index 39dfa19002da8..d3a7e7601f618 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -324,30 +324,220 @@ OpenACCAtomicConstruct *OpenACCAtomicConstruct::Create( return Inst; } -static std::pair getBinaryOpArgs(const Expr *Op) { +static std::optional> +getBinaryAssignOpArgs(const Expr *Op, bool &IsCompoundAssign) { if (const auto *BO = dyn_cast(Op)) { - assert(BO->isAssignmentOp()); - return {BO->getLHS(), BO->getRHS()}; + if (!BO->isAssignmentOp()) + return std::nullopt; + IsCompoundAssign = BO->isCompoundAssignmentOp(); + return std::pair(BO->getLHS(), BO->getRHS()); } - const auto *OO = cast(Op); - assert(OO->isAssignmentOp()); - return {OO->getArg(0), OO->getArg(1)}; + if (const auto *OO = dyn_cast(Op)) { + if (!OO->isAssignmentOp()) + return std::nullopt; + IsCompoundAssign = OO->getOperator() != OO_Equal; + return std::pair(OO->getArg(0), OO->getArg(1)); + } + return std::nullopt; +} +static std::optional> +getBinaryAssignOpArgs(const Expr *Op) { + bool IsCompoundAssign; + return getBinaryAssignOpArgs(Op, IsCompoundAssign); } -static std::pair getUnaryOpArgs(const Expr *Op) { +static std::optional getUnaryOpArgs(const Expr *Op) { if (const auto *UO = dyn_cast(Op)) - return {true, UO->getSubExpr()}; + return UO->getSubExpr(); if (const auto *OpCall = dyn_cast(Op)) { // Post-inc/dec have a second unused argument to differentiate it, so we // accept -- or ++ as unary, or any operator call with only 1 arg. - if (OpCall->getNumArgs() == 1 || OpCall->getOperator() != OO_PlusPlus || - OpCall->getOperator() != OO_MinusMinus) - return {true, OpCall->getArg(0)}; + if (OpCall->getNumArgs() == 1 || OpCall->getOperator() == OO_PlusPlus || + OpCall->getOperator() == OO_MinusMinus) + return {OpCall->getArg(0)}; } - return {false, nullptr}; + return std::nullopt; +} + +// Read is of the form `v = x;`, where both sides are scalar L-values. This is a +// BinaryOperator or CXXOperatorCallExpr. +static std::optional +getReadStmtInfo(const Expr *E, bool ForAtomicComputeSingleStmt = false) { + std::optional> BinaryArgs = + getBinaryAssignOpArgs(E); + + if (!BinaryArgs) + return std::nullopt; + + // We want the L-value for each side, so we ignore implicit casts. + auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createRead( + E, BinaryArgs->first->IgnoreImpCasts(), + BinaryArgs->second->IgnoreImpCasts()); + + // The atomic compute single-stmt variant has to do a 'fixup' step for the 'X' + // value, since it is dependent on the RHS. So if we're in that version, we + // skip the checks on X. + if ((!ForAtomicComputeSingleStmt && + (!Res.X->isLValue() || !Res.X->getType()->isScalarType())) || + !Res.V->isLValue() || !Res.V->getType()->isScalarType()) + return std::nullopt; + + return Res; +} + +// Write supports only the format 'x = expr', where the expression is scalar +// type, and 'x' is a scalar l value. As above, this can come in 2 forms; +// Binary Operator or CXXOperatorCallExpr. +static std::optional +getWriteStmtInfo(const Expr *E) { + std::optional> BinaryArgs = + getBinaryAssignOpArgs(E); + if (!BinaryArgs) + return std::nullopt; + // We want the L-value for ONLY the X side, so we ignore implicit casts. For + // the right side (the expr), we emit it as an r-value so we need to + // maintain implicit casts. + auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createWrite( + E, BinaryArgs->first->IgnoreImpCasts(), BinaryArgs->second); + + if (!Res.X->isLValue() || !Res.X->getType()->isScalarType()) + return std::nullopt; + return Res; +} + +static std::optional +getUpdateStmtInfo(const Expr *E) { + std::optional UnaryArgs = getUnaryOpArgs(E); + if (UnaryArgs) { + auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createUpdate( + E, (*UnaryArgs)->IgnoreImpCasts()); + + if (!Res.X->isLValue() || !Res.X->getType()->isScalarType()) + return std::nullopt; + + return Res; + } + + bool IsRHSCompoundAssign = false; + std::optional> BinaryArgs = + getBinaryAssignOpArgs(E, IsRHSCompoundAssign); + if (!BinaryArgs) + return std::nullopt; + + auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createUpdate( + E, BinaryArgs->first->IgnoreImpCasts()); + + if (!Res.X->isLValue() || !Res.X->getType()->isScalarType()) + return std::nullopt; + + // 'update' has to be either a compound-assignment operation, or + // assignment-to-a-binary-op. Return nullopt if these are not the case. + // If we are already compound-assign, we're done! + if (IsRHSCompoundAssign) + return Res; + + // else we have to check that we have a binary operator. + const Expr *RHS = BinaryArgs->second->IgnoreImpCasts(); + + if (isa(RHS)) { + return Res; + } else if (const auto *OO = dyn_cast(RHS)) { + if (OO->isInfixBinaryOp()) + return Res; + } + + return std::nullopt; +} + +/// The statement associated with an atomic capture comes in 1 of two forms: A +/// compound statement containing two statements, or a single statement. In +/// either case, the compound/single statement is decomposed into 2 separate +/// operations, eihter a read/write, read/update, or update/read. This function +/// figures out that information in the form listed in the standard (filling in +/// V, X, or Expr) for each of these operations. +static OpenACCAtomicConstruct::StmtInfo +getCaptureStmtInfo(const Stmt *AssocStmt) { + + if (const auto *CmpdStmt = dyn_cast(AssocStmt)) { + // We checked during Sema to ensure we only have 2 statements here, and + // that both are expressions, we can look at these to see what the valid + // options are. + const Expr *Stmt1 = cast(*CmpdStmt->body().begin())->IgnoreImpCasts(); + const Expr *Stmt2 = + cast(*(CmpdStmt->body().begin() + 1))->IgnoreImpCasts(); + + // The compound statement form allows read/write, read/update, or + // update/read. First we get the information for a 'Read' to see if this is + // one of the former two. + std::optional Read = + getReadStmtInfo(Stmt1); + + if (Read) { + // READ : WRITE + // v = x; x = expr + // READ : UPDATE + // v = x; x binop = expr + // v = x; x = x binop expr + // v = x; x = expr binop x + // v = x; x++ + // v = x; ++x + // v = x; x-- + // v = x; --x + std::optional Update = + getUpdateStmtInfo(Stmt2); + // Since we already know the first operation is a read, the second is + // either an update, which we check, or a write, which we can assume next. + if (Update) + return OpenACCAtomicConstruct::StmtInfo::createReadUpdate(*Read, + *Update); + + std::optional Write = + getWriteStmtInfo(Stmt2); + return OpenACCAtomicConstruct::StmtInfo::createReadWrite(*Read, *Write); + } + // UPDATE: READ + // x binop = expr; v = x + // x = x binop expr; v = x + // x = expr binop x ; v = x + // ++ x; v = x + // x++; v = x + // --x; v = x + // x--; v = x + // Otherwise, it is one of the above forms for update/read. + std::optional Update = + getUpdateStmtInfo(Stmt1); + Read = getReadStmtInfo(Stmt2); + + return OpenACCAtomicConstruct::StmtInfo::createUpdateRead(*Update, *Read); + } else { + // All of the possible forms (listed below) that are writable as a single + // line are expressed as an update, then as a read. We should be able to + // just run these two in the right order. + // UPDATE: READ + // v = x++; + // v = x--; + // v = ++x; + // v = --x; + // v = x binop=expr + // v = x = x binop expr + // v = x = expr binop x + + const Expr *E = cast(AssocStmt); + + std::optional Read = + getReadStmtInfo(E, /*ForAtomicComputeSingleStmt=*/true); + std::optional Update = + getUpdateStmtInfo(Read->X); + + // Fixup this, since the 'X' for the read is the result after write, but is + // the same value as the LHS-most variable of the update(its X). + Read->X = Update->X; + return OpenACCAtomicConstruct::StmtInfo::createUpdateRead(*Update, *Read); + } + return {}; } const OpenACCAtomicConstruct::StmtInfo @@ -357,48 +547,28 @@ OpenACCAtomicConstruct::getAssociatedStmtInfo() const { // asserts to ensure we don't get off into the weeds. assert(getAssociatedStmt() && "invalid associated stmt?"); - const Expr *AssocStmt = cast(getAssociatedStmt()); switch (AtomicKind) { - case OpenACCAtomicKind::Capture: - assert(false && "Only 'read'/'write'/'update' have been implemented here"); - return {}; - case OpenACCAtomicKind::Read: { - // Read only supports the format 'v = x'; where both sides are a scalar - // expression. This can come in 2 forms; BinaryOperator or - // CXXOperatorCallExpr (rarely). - std::pair BinaryArgs = - getBinaryOpArgs(AssocStmt); - // We want the L-value for each side, so we ignore implicit casts. - return {BinaryArgs.first->IgnoreImpCasts(), - BinaryArgs.second->IgnoreImpCasts(), /*expr=*/nullptr}; - } - case OpenACCAtomicKind::Write: { - // Write supports only the format 'x = expr', where the expression is scalar - // type, and 'x' is a scalar l value. As above, this can come in 2 forms; - // Binary Operator or CXXOperatorCallExpr. - std::pair BinaryArgs = - getBinaryOpArgs(AssocStmt); - // We want the L-value for ONLY the X side, so we ignore implicit casts. For - // the right side (the expr), we emit it as an r-value so we need to - // maintain implicit casts. - return {/*v=*/nullptr, BinaryArgs.first->IgnoreImpCasts(), - BinaryArgs.second}; - } + case OpenACCAtomicKind::Read: + return OpenACCAtomicConstruct::StmtInfo{ + OpenACCAtomicConstruct::StmtInfo::StmtForm::Read, + *getReadStmtInfo(cast(getAssociatedStmt())), + OpenACCAtomicConstruct::SingleStmtInfo::Empty()}; + + case OpenACCAtomicKind::Write: + return OpenACCAtomicConstruct::StmtInfo{ + OpenACCAtomicConstruct::StmtInfo::StmtForm::Write, + *getWriteStmtInfo(cast(getAssociatedStmt())), + OpenACCAtomicConstruct::SingleStmtInfo::Empty()}; + case OpenACCAtomicKind::None: - case OpenACCAtomicKind::Update: { - std::pair UnaryArgs = getUnaryOpArgs(AssocStmt); - if (UnaryArgs.first) - return {/*v=*/nullptr, UnaryArgs.second->IgnoreImpCasts(), - /*expr=*/nullptr}; - - std::pair BinaryArgs = - getBinaryOpArgs(AssocStmt); - // For binary args, we just store the RHS as an expression (in the - // expression slot), since the codegen just wants the whole thing for a - // recipe. - return {/*v=*/nullptr, BinaryArgs.first->IgnoreImpCasts(), - BinaryArgs.second}; - } + case OpenACCAtomicKind::Update: + return OpenACCAtomicConstruct::StmtInfo{ + OpenACCAtomicConstruct::StmtInfo::StmtForm::Update, + *getUpdateStmtInfo(cast(getAssociatedStmt())), + OpenACCAtomicConstruct::SingleStmtInfo::Empty()}; + + case OpenACCAtomicKind::Capture: + return getCaptureStmtInfo(getAssociatedStmt()); } llvm_unreachable("unknown OpenACC atomic kind"); diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index acd98fe84adf5..e477da34fd5e0 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -197,6 +197,96 @@ static bool builtinIsSupported(const llvm::StringTable &Strings, return true; } +static bool isBuiltinConstForTriple(unsigned BuiltinID, llvm::Triple Trip) { + // There's a special case with the fma builtins where they are always const + // if the target environment is GNU or the target is OS is Windows and we're + // targeting the MSVCRT.dll environment. + // FIXME: This list can be become outdated. Need to find a way to get it some + // other way. + switch (BuiltinID) { + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BI__builtin_fmaf16: + case Builtin::BIfma: + case Builtin::BIfmaf: + case Builtin::BIfmal: { + if (Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) + return true; + break; + } + default: + break; + } + + return false; +} + +bool Builtin::Context::shouldGenerateFPMathIntrinsic( + unsigned BuiltinID, llvm::Triple Trip, std::optional ErrnoOverwritten, + bool MathErrnoEnabled, bool HasOptNoneAttr, + bool IsOptimizationEnabled) const { + + // True if we are compiling at -O2 and errno has been disabled + // using the '#pragma float_control(precise, off)', and + // attribute opt-none hasn't been seen. + bool ErrnoOverridenToFalseWithOpt = ErrnoOverwritten.has_value() && + !ErrnoOverwritten.value() && + !HasOptNoneAttr && IsOptimizationEnabled; + + // There are LLVM math intrinsics/instructions corresponding to math library + // functions except the LLVM op will never set errno while the math library + // might. Also, math builtins have the same semantics as their math library + // twins. Thus, we can transform math library and builtin calls to their + // LLVM counterparts if the call is marked 'const' (known to never set errno). + // In case FP exceptions are enabled, the experimental versions of the + // intrinsics model those. + bool ConstAlways = + isConst(BuiltinID) || isBuiltinConstForTriple(BuiltinID, Trip); + + bool ConstWithoutErrnoAndExceptions = + isConstWithoutErrnoAndExceptions(BuiltinID); + bool ConstWithoutExceptions = isConstWithoutExceptions(BuiltinID); + + // ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is + // disabled. + // Math intrinsics are generated only when math-errno is disabled. Any pragmas + // or attributes that affect math-errno should prevent or allow math + // intrinsics to be generated. Intrinsics are generated: + // 1- In fast math mode, unless math-errno is overriden + // via '#pragma float_control(precise, on)', or via an + // 'attribute__((optnone))'. + // 2- If math-errno was enabled on command line but overriden + // to false via '#pragma float_control(precise, off))' and + // 'attribute__((optnone))' hasn't been used. + // 3- If we are compiling with optimization and errno has been disabled + // via '#pragma float_control(precise, off)', and + // 'attribute__((optnone))' hasn't been used. + + bool ConstWithoutErrnoOrExceptions = + ConstWithoutErrnoAndExceptions || ConstWithoutExceptions; + bool GenerateIntrinsics = + (ConstAlways && !HasOptNoneAttr) || + (!MathErrnoEnabled && + !(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) && + !HasOptNoneAttr); + if (!GenerateIntrinsics) { + GenerateIntrinsics = + ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions; + if (!GenerateIntrinsics) + GenerateIntrinsics = + ConstWithoutErrnoOrExceptions && + (!MathErrnoEnabled && + !(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) && + !HasOptNoneAttr); + if (!GenerateIntrinsics) + GenerateIntrinsics = + ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt; + } + + return GenerateIntrinsics; +} + /// initializeBuiltins - Mark the identifiers for all the builtins with their /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp index d5b413cb58eb2..bd70bfe4fef51 100644 --- a/clang/lib/Basic/Targets/Hexagon.cpp +++ b/clang/lib/Basic/Targets/Hexagon.cpp @@ -155,9 +155,14 @@ bool HexagonTargetInfo::handleTargetFeatures(std::vector &Features, HasFastHalfType = true; HasFloat16 = true; } + if (CPU.compare("hexagonv81") >= 0) + HasBFloat16 = true; + return true; } +bool HexagonTargetInfo::hasBFloat16Type() const { return HasBFloat16; } + const char *const HexagonTargetInfo::GCCRegNames[] = { // Scalar registers: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h index a65663ca09eee..53c348a3246f9 100644 --- a/clang/lib/Basic/Targets/Hexagon.h +++ b/clang/lib/Basic/Targets/Hexagon.h @@ -64,6 +64,8 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { // for modeling predicate registers in HVX, and the bool -> byte // correspondence matches the HVX architecture. BoolWidth = BoolAlign = 8; + BFloat16Width = BFloat16Align = 16; + BFloat16Format = &llvm::APFloat::BFloat(); } llvm::SmallVector getTargetBuiltins() const override; @@ -95,6 +97,8 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { bool hasFeature(StringRef Feature) const override; + bool hasBFloat16Type() const override; + bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index f777562ba6309..fc5a501e6a700 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2388,9 +2388,9 @@ mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator( // type, so evaluating it returns a null Value. However, a conditional // with non-void type must return a non-null Value. if (!result && !e->getType()->isVoidType()) { - cgf.cgm.errorNYI(e->getSourceRange(), - "throw expression in conditional operator"); - result = {}; + result = builder.getConstant( + loc, cir::PoisonAttr::get(builder.getContext(), + cgf.convertType(e->getType()))); } return result; diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp index 9e55bd5b7ae71..80de920c075e7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenACC.cpp @@ -314,15 +314,80 @@ const VarDecl *getLValueDecl(const Expr *e) { return cast(dre->getDecl()); } -mlir::LogicalResult -CIRGenFunction::emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s) { - // For now, we are only support 'read'/'write'/'update', so diagnose. We can - // switch on the kind later once we implement the 'capture' form. - if (s.getAtomicKind() == OpenACCAtomicKind::Capture) { - cgm.errorNYI(s.getSourceRange(), "OpenACC Atomic Construct"); - return mlir::failure(); +static mlir::acc::AtomicReadOp +emitAtomicRead(CIRGenFunction &cgf, CIRGenBuilderTy &builder, + mlir::Location start, + const OpenACCAtomicConstruct::SingleStmtInfo &inf) { + // Atomic 'read' only permits 'v = x', where v and x are both scalar L + // values. The getAssociatedStmtInfo strips off implicit casts, which + // includes implicit conversions and L-to-R-Value conversions, so we can + // just emit it as an L value. The Flang implementation has no problem with + // different types, so it appears that the dialect can handle the + // conversions. + mlir::Value v = cgf.emitLValue(inf.V).getPointer(); + mlir::Value x = cgf.emitLValue(inf.X).getPointer(); + mlir::Type resTy = cgf.convertType(inf.V->getType()); + return mlir::acc::AtomicReadOp::create(builder, start, x, v, resTy, + /*ifCond=*/{}); +} + +static mlir::acc::AtomicWriteOp +emitAtomicWrite(CIRGenFunction &cgf, CIRGenBuilderTy &builder, + mlir::Location start, + const OpenACCAtomicConstruct::SingleStmtInfo &inf) { + mlir::Value x = cgf.emitLValue(inf.X).getPointer(); + mlir::Value expr = cgf.emitAnyExpr(inf.RefExpr).getValue(); + return mlir::acc::AtomicWriteOp::create(builder, start, x, expr, + /*ifCond=*/{}); +} + +static std::pair +emitAtomicUpdate(CIRGenFunction &cgf, CIRGenBuilderTy &builder, + mlir::Location start, mlir::Location end, + const OpenACCAtomicConstruct::SingleStmtInfo &inf) { + mlir::Value x = cgf.emitLValue(inf.X).getPointer(); + auto op = mlir::acc::AtomicUpdateOp::create(builder, start, x, /*ifCond=*/{}); + + mlir::LogicalResult res = mlir::success(); + { + mlir::OpBuilder::InsertionGuard guardCase(builder); + mlir::Type argTy = cast(x.getType()).getPointee(); + std::array recipeType{argTy}; + std::array recipeLoc{start}; + auto *recipeBlock = builder.createBlock( + &op.getRegion(), op.getRegion().end(), recipeType, recipeLoc); + builder.setInsertionPointToEnd(recipeBlock); + // Since we have an initial value that we know is a scalar type, we can + // just emit the entire statement here after sneaking-in our 'alloca' in + // the right place, then loading out of it. Flang does a lot less work + // (probably does its own emitting!), but we have more complicated AST + // nodes to worry about, so we can just count on opt to remove the extra + // alloca/load/store set. + auto alloca = cir::AllocaOp::create( + builder, start, x.getType(), argTy, "x_var", + cgf.cgm.getSize( + cgf.getContext().getTypeAlignInChars(inf.X->getType()))); + + alloca.setInitAttr(builder.getUnitAttr()); + builder.CIRBaseBuilderTy::createStore(start, recipeBlock->getArgument(0), + alloca); + + const VarDecl *xval = getLValueDecl(inf.X); + CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, xval}; + cgf.replaceAddrOfLocalVar( + xval, Address{alloca, argTy, cgf.getContext().getDeclAlign(xval)}); + + res = cgf.emitStmt(inf.WholeExpr, /*useCurrentScope=*/true); + + auto load = cir::LoadOp::create(builder, start, {alloca}); + mlir::acc::YieldOp::create(builder, end, {load}); } + return {res, op}; +} + +mlir::LogicalResult +CIRGenFunction::emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s) { // While Atomic is an 'associated statement' construct, it 'steals' the // expression it is associated with rather than emitting it inside of it. So // it has custom emit logic. @@ -331,78 +396,89 @@ CIRGenFunction::emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s) { OpenACCAtomicConstruct::StmtInfo inf = s.getAssociatedStmtInfo(); switch (s.getAtomicKind()) { - case OpenACCAtomicKind::Capture: - llvm_unreachable("Unimplemented atomic construct type, should have " - "diagnosed/returned above"); - return mlir::failure(); case OpenACCAtomicKind::Read: { - - // Atomic 'read' only permits 'v = x', where v and x are both scalar L - // values. The getAssociatedStmtInfo strips off implicit casts, which - // includes implicit conversions and L-to-R-Value conversions, so we can - // just emit it as an L value. The Flang implementation has no problem with - // different types, so it appears that the dialect can handle the - // conversions. - mlir::Value v = emitLValue(inf.V).getPointer(); - mlir::Value x = emitLValue(inf.X).getPointer(); - mlir::Type resTy = convertType(inf.V->getType()); - auto op = mlir::acc::AtomicReadOp::create(builder, start, x, v, resTy, - /*ifCond=*/{}); + assert(inf.Form == OpenACCAtomicConstruct::StmtInfo::StmtForm::Read); + mlir::acc::AtomicReadOp op = + emitAtomicRead(*this, builder, start, inf.First); emitOpenACCClauses(op, s.getDirectiveKind(), s.getDirectiveLoc(), s.clauses()); return mlir::success(); } case OpenACCAtomicKind::Write: { - mlir::Value x = emitLValue(inf.X).getPointer(); - mlir::Value expr = emitAnyExpr(inf.RefExpr).getValue(); - auto op = mlir::acc::AtomicWriteOp::create(builder, start, x, expr, - /*ifCond=*/{}); + assert(inf.Form == OpenACCAtomicConstruct::StmtInfo::StmtForm::Write); + auto op = emitAtomicWrite(*this, builder, start, inf.First); emitOpenACCClauses(op, s.getDirectiveKind(), s.getDirectiveLoc(), s.clauses()); return mlir::success(); } case OpenACCAtomicKind::None: case OpenACCAtomicKind::Update: { - mlir::Value x = emitLValue(inf.X).getPointer(); - auto op = - mlir::acc::AtomicUpdateOp::create(builder, start, x, /*ifCond=*/{}); + assert(inf.Form == OpenACCAtomicConstruct::StmtInfo::StmtForm::Update); + auto [res, op] = emitAtomicUpdate(*this, builder, start, end, inf.First); + emitOpenACCClauses(op, s.getDirectiveKind(), s.getDirectiveLoc(), + s.clauses()); + return res; + } + case OpenACCAtomicKind::Capture: { + // Atomic-capture is made up of two statements, either an update = read, + // read + update, or read + write. As a result, the IR represents the + // capture region as having those two 'inside' of it. + auto op = mlir::acc::AtomicCaptureOp::create(builder, start, /*ifCond=*/{}); emitOpenACCClauses(op, s.getDirectiveKind(), s.getDirectiveLoc(), s.clauses()); mlir::LogicalResult res = mlir::success(); { mlir::OpBuilder::InsertionGuard guardCase(builder); - mlir::Type argTy = cast(x.getType()).getPointee(); - std::array recipeType{argTy}; - std::array recipeLoc{start}; - mlir::Block *recipeBlock = builder.createBlock( - &op.getRegion(), op.getRegion().end(), recipeType, recipeLoc); - builder.setInsertionPointToEnd(recipeBlock); - - // Since we have an initial value that we know is a scalar type, we can - // just emit the entire statement here after sneaking-in our 'alloca' in - // the right place, then loading out of it. Flang does a lot less work - // (probably does its own emitting!), but we have more complicated AST - // nodes to worry about, so we can just count on opt to remove the extra - // alloca/load/store set. - auto alloca = cir::AllocaOp::create( - builder, start, x.getType(), argTy, "x_var", - cgm.getSize(getContext().getTypeAlignInChars(inf.X->getType()))); - - alloca.setInitAttr(mlir::UnitAttr::get(&getMLIRContext())); - builder.CIRBaseBuilderTy::createStore(start, recipeBlock->getArgument(0), - alloca); - - const VarDecl *xval = getLValueDecl(inf.X); - CIRGenFunction::DeclMapRevertingRAII declMapRAII{*this, xval}; - replaceAddrOfLocalVar( - xval, Address{alloca, argTy, getContext().getDeclAlign(xval)}); - - res = emitStmt(s.getAssociatedStmt(), /*useCurrentScope=*/true); - - auto load = cir::LoadOp::create(builder, start, {alloca}); - mlir::acc::YieldOp::create(builder, end, {load}); - } + mlir::Block *block = + builder.createBlock(&op.getRegion(), op.getRegion().end(), {}, {}); + + builder.setInsertionPointToStart(block); + + auto terminator = mlir::acc::TerminatorOp::create(builder, end); + + // The AtomicCaptureOp only permits the two acc.atomic.* operations inside + // of it, so all other parts of the expression need to be emitted before + // the AtomicCaptureOp, then moved into place. + builder.setInsertionPoint(op); + + switch (inf.Form) { + default: + llvm_unreachable("invalid form for Capture"); + case OpenACCAtomicConstruct::StmtInfo::StmtForm::ReadWrite: { + mlir::acc::AtomicReadOp first = + emitAtomicRead(*this, builder, start, inf.First); + mlir::acc::AtomicWriteOp second = + emitAtomicWrite(*this, builder, start, inf.Second); + + first->moveBefore(terminator); + second->moveBefore(terminator); + break; + } + case OpenACCAtomicConstruct::StmtInfo::StmtForm::ReadUpdate: { + mlir::acc::AtomicReadOp first = + emitAtomicRead(*this, builder, start, inf.First); + auto [this_res, second] = + emitAtomicUpdate(*this, builder, start, end, inf.Second); + res = this_res; + + first->moveBefore(terminator); + second->moveBefore(terminator); + break; + } + case OpenACCAtomicConstruct::StmtInfo::StmtForm::UpdateRead: { + auto [this_res, first] = + emitAtomicUpdate(*this, builder, start, end, inf.First); + res = this_res; + mlir::acc::AtomicReadOp second = + emitAtomicRead(*this, builder, start, inf.Second); + + first->moveBefore(terminator); + second->moveBefore(terminator); + break; + } + } + } return res; } } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4912bd197dba4..b35359609521e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -284,7 +284,10 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( callOp->getContext(), /*other=*/ModRefInfo::Ref, /*argMem=*/ModRefInfo::Ref, - /*inaccessibleMem=*/ModRefInfo::Ref); + /*inaccessibleMem=*/ModRefInfo::Ref, + /*errnoMem=*/ModRefInfo::Ref, + /*targetMem0=*/ModRefInfo::Ref, + /*targetMem1=*/ModRefInfo::Ref); noUnwind = true; willReturn = true; break; @@ -293,7 +296,10 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( callOp->getContext(), /*other=*/ModRefInfo::NoModRef, /*argMem=*/ModRefInfo::NoModRef, - /*inaccessibleMem=*/ModRefInfo::NoModRef); + /*inaccessibleMem=*/ModRefInfo::NoModRef, + /*errnoMem=*/ModRefInfo::NoModRef, + /*targetMem0=*/ModRefInfo::NoModRef, + /*targetMem1=*/ModRefInfo::NoModRef); noUnwind = true; willReturn = true; break; @@ -3098,6 +3104,90 @@ mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite( return mlir::success(); } +static mlir::LLVM::LLVMStructType +getLLVMLandingPadStructTy(mlir::ConversionPatternRewriter &rewriter) { + // Create the landing pad type: struct { ptr, i32 } + mlir::MLIRContext *ctx = rewriter.getContext(); + auto llvmPtr = mlir::LLVM::LLVMPointerType::get(ctx); + llvm::SmallVector structFields = {llvmPtr, rewriter.getI32Type()}; + return mlir::LLVM::LLVMStructType::getLiteral(ctx, structFields); +} + +mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite( + cir::EhInflightOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto llvmFn = op->getParentOfType(); + assert(llvmFn && "expected LLVM function parent"); + mlir::Block *entryBlock = &llvmFn.getRegion().front(); + assert(entryBlock->isEntryBlock()); + + mlir::ArrayAttr catchListAttr = op.getCatchTypeListAttr(); + mlir::SmallVector catchSymAddrs; + + auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + mlir::Location loc = op.getLoc(); + + // %landingpad = landingpad { ptr, i32 } + // Note that since llvm.landingpad has to be the first operation on the + // block, any needed value for its operands has to be added somewhere else. + if (catchListAttr) { + // catch ptr @_ZTIi + // catch ptr @_ZTIPKc + for (mlir::Attribute catchAttr : catchListAttr) { + auto symAttr = cast(catchAttr); + // Generate `llvm.mlir.addressof` for each symbol, and place those + // operations in the LLVM function entry basic block. + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPointToStart(entryBlock); + mlir::Value addrOp = mlir::LLVM::AddressOfOp::create( + rewriter, loc, llvmPtrTy, symAttr.getValue()); + catchSymAddrs.push_back(addrOp); + } + } else if (!op.getCleanup()) { + // We need to emit catch-all only if cleanup is not set, because when we + // have catch-all handler, there is no case when we set would unwind past + // the handler + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPointToStart(entryBlock); + mlir::Value nullOp = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy); + catchSymAddrs.push_back(nullOp); + } + + // %slot = extractvalue { ptr, i32 } %x, 0 + // %selector = extractvalue { ptr, i32 } %x, 1 + mlir::LLVM::LLVMStructType llvmLandingPadStructTy = + getLLVMLandingPadStructTy(rewriter); + auto landingPadOp = mlir::LLVM::LandingpadOp::create( + rewriter, loc, llvmLandingPadStructTy, catchSymAddrs); + + if (op.getCleanup()) + landingPadOp.setCleanup(true); + + mlir::Value slot = + mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 0); + mlir::Value selector = + mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1); + rewriter.replaceOp(op, mlir::ValueRange{slot, selector}); + + // Landing pads are required to be in LLVM functions with personality + // attribute. + // TODO(cir): for now hardcode personality creation in order to start + // adding exception tests, once we annotate CIR with such information, + // change it to be in FuncOp lowering instead. + mlir::OpBuilder::InsertionGuard guard(rewriter); + // Insert personality decl before the current function. + rewriter.setInsertionPoint(llvmFn); + auto personalityFnTy = + mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {}, + /*isVarArg=*/true); + + const StringRef fnName = "__gxx_personality_v0"; + createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy); + llvmFn.setPersonality(fnName); + + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite( cir::TrapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 16074215e8275..ceb7d8791da87 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2640,84 +2640,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // fast-math which implies math-errno. bool OptNone = CurFuncDecl && CurFuncDecl->hasAttr(); - // True if we are compiling at -O2 and errno has been disabled - // using the '#pragma float_control(precise, off)', and - // attribute opt-none hasn't been seen. - bool ErrnoOverridenToFalseWithOpt = - ErrnoOverriden.has_value() && !ErrnoOverriden.value() && !OptNone && - CGM.getCodeGenOpts().OptimizationLevel != 0; - - // There are LLVM math intrinsics/instructions corresponding to math library - // functions except the LLVM op will never set errno while the math library - // might. Also, math builtins have the same semantics as their math library - // twins. Thus, we can transform math library and builtin calls to their - // LLVM counterparts if the call is marked 'const' (known to never set errno). - // In case FP exceptions are enabled, the experimental versions of the - // intrinsics model those. - bool ConstAlways = - getContext().BuiltinInfo.isConst(BuiltinID); - - // There's a special case with the fma builtins where they are always const - // if the target environment is GNU or the target is OS is Windows and we're - // targeting the MSVCRT.dll environment. - // FIXME: This list can be become outdated. Need to find a way to get it some - // other way. - switch (BuiltinID) { - case Builtin::BI__builtin_fma: - case Builtin::BI__builtin_fmaf: - case Builtin::BI__builtin_fmal: - case Builtin::BI__builtin_fmaf16: - case Builtin::BIfma: - case Builtin::BIfmaf: - case Builtin::BIfmal: { - auto &Trip = CGM.getTriple(); - if (Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) - ConstAlways = true; - break; - } - default: - break; - } + bool IsOptimizationEnabled = CGM.getCodeGenOpts().OptimizationLevel != 0; + + bool GenerateFPMathIntrinsics = + getContext().BuiltinInfo.shouldGenerateFPMathIntrinsic( + BuiltinID, CGM.getTriple(), ErrnoOverriden, getLangOpts().MathErrno, + OptNone, IsOptimizationEnabled); - bool ConstWithoutErrnoAndExceptions = - getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); - bool ConstWithoutExceptions = - getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID); - - // ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is - // disabled. - // Math intrinsics are generated only when math-errno is disabled. Any pragmas - // or attributes that affect math-errno should prevent or allow math - // intrinsics to be generated. Intrinsics are generated: - // 1- In fast math mode, unless math-errno is overriden - // via '#pragma float_control(precise, on)', or via an - // 'attribute__((optnone))'. - // 2- If math-errno was enabled on command line but overriden - // to false via '#pragma float_control(precise, off))' and - // 'attribute__((optnone))' hasn't been used. - // 3- If we are compiling with optimization and errno has been disabled - // via '#pragma float_control(precise, off)', and - // 'attribute__((optnone))' hasn't been used. - - bool ConstWithoutErrnoOrExceptions = - ConstWithoutErrnoAndExceptions || ConstWithoutExceptions; - bool GenerateIntrinsics = - (ConstAlways && !OptNone) || - (!getLangOpts().MathErrno && - !(ErrnoOverriden.has_value() && ErrnoOverriden.value()) && !OptNone); - if (!GenerateIntrinsics) { - GenerateIntrinsics = - ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions; - if (!GenerateIntrinsics) - GenerateIntrinsics = - ConstWithoutErrnoOrExceptions && - (!getLangOpts().MathErrno && - !(ErrnoOverriden.has_value() && ErrnoOverriden.value()) && !OptNone); - if (!GenerateIntrinsics) - GenerateIntrinsics = - ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt; - } - if (GenerateIntrinsics) { + if (GenerateFPMathIntrinsics) { switch (BuiltinIDIfNoAsmLabel) { case Builtin::BIacos: case Builtin::BIacosf: diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 208afff24d498..9403d26576eb0 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -27,6 +27,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -599,6 +600,36 @@ CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, VariableName.str()); } +static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M, + llvm::Value *Source, unsigned Location, + StringRef Name) { + auto *GV = new llvm::GlobalVariable( + M, Source->getType(), /* isConstant= */ false, + llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 8, /* isExternallyInitialized= */ false); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + addLocationDecoration(GV, Location); + B.CreateStore(Source, GV); +} + +void CGHLSLRuntime::emitSPIRVUserSemanticStore( + llvm::IRBuilder<> &B, llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, std::optional Index) { + Twine BaseName = Twine(Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); + unsigned Location = SPIRVLastAssignedOutputSemanticLocation; + + // DXC completely ignores the semantic/index pair. Location are assigned from + // the first semantic to the last. + llvm::ArrayType *AT = dyn_cast(Source->getType()); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + SPIRVLastAssignedOutputSemanticLocation += ElementCount; + createSPIRVLocationStore(B, CGM.getModule(), Source, Location, + VariableName.str()); +} + llvm::Value * CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, HLSLAppliedSemanticAttr *Semantic, @@ -619,6 +650,23 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, return Value; } +void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B, + llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index) { + // DXIL packing rules etc shall be handled here. + // FIXME: generate proper sigpoint, index, col, row values. + SmallVector Args{B.getInt32(4), + B.getInt32(0), + B.getInt32(0), + B.getInt8(0), + llvm::PoisonValue::get(B.getInt32Ty()), + Source}; + + llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output; + B.CreateIntrinsic(/*ReturnType=*/CGM.VoidTy, IntrinsicID, Args, nullptr); +} + llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional Index) { @@ -631,6 +679,19 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( llvm_unreachable("Unsupported target for user-semantic load."); } +void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index) { + if (CGM.getTarget().getTriple().isSPIRV()) + return emitSPIRVUserSemanticStore(B, Source, Semantic, Index); + + if (CGM.getTarget().getTriple().isDXIL()) + return emitDXILUserSemanticStore(B, Source, Semantic, Index); + + llvm_unreachable("Unsupported target for user-semantic load."); +} + llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic, std::optional Index) { @@ -679,6 +740,34 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( llvm_unreachable("non-handled system semantic. FIXME."); } +static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M, + llvm::Value *Source, const Twine &Name, + unsigned BuiltInID) { + auto *GV = new llvm::GlobalVariable( + M, Source->getType(), /* isConstant= */ false, + llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 8, /* isExternallyInitialized= */ false); + addSPIRVBuiltinDecoration(GV, BuiltInID); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + B.CreateStore(Source, GV); +} + +void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index) { + + std::string SemanticName = Semantic->getAttrName()->getName().upper(); + if (SemanticName == "SV_POSITION") + createSPIRVBuiltinStore(B, CGM.getModule(), Source, + Semantic->getAttrName()->getName(), + /* BuiltIn::Position */ 0); + else + llvm_unreachable("non-handled system semantic. FIXME."); +} + llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad( IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) { @@ -689,6 +778,16 @@ llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad( return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); } +void CGHLSLRuntime::handleScalarSemanticStore( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic) { + std::optional Index = Semantic->getSemanticIndex(); + if (Semantic->getAttrName()->getName().starts_with_insensitive("SV_")) + emitSystemSemanticStore(B, Source, Decl, Semantic, Index); + else + emitUserSemanticStore(B, Source, Decl, Semantic, Index); +} + std::pair> CGHLSLRuntime::handleStructSemanticLoad( IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, @@ -715,6 +814,35 @@ CGHLSLRuntime::handleStructSemanticLoad( return std::make_pair(Aggregate, AttrBegin); } +specific_attr_iterator +CGHLSLRuntime::handleStructSemanticStore( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd) { + + const llvm::StructType *ST = cast(Source->getType()); + + const clang::RecordDecl *RD = nullptr; + if (const FunctionDecl *FD = dyn_cast(Decl)) + RD = FD->getDeclaredReturnType()->getAsRecordDecl(); + else + RD = Decl->getType()->getAsRecordDecl(); + assert(RD); + + assert(std::distance(RD->field_begin(), RD->field_end()) == + ST->getNumElements()); + + auto FieldDecl = RD->field_begin(); + for (unsigned I = 0; I < ST->getNumElements(); ++I) { + llvm::Value *Extract = B.CreateExtractValue(Source, I); + AttrBegin = + handleSemanticStore(B, FD, Extract, *FieldDecl, AttrBegin, AttrEnd); + } + + return AttrBegin; +} + std::pair> CGHLSLRuntime::handleSemanticLoad( IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, @@ -731,6 +859,22 @@ CGHLSLRuntime::handleSemanticLoad( AttrBegin); } +specific_attr_iterator +CGHLSLRuntime::handleSemanticStore( + IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd) { + assert(AttrBegin != AttrEnd); + if (Source->getType()->isStructTy()) + return handleStructSemanticStore(B, FD, Source, Decl, AttrBegin, AttrEnd); + + HLSLAppliedSemanticAttr *Attr = *AttrBegin; + ++AttrBegin; + handleScalarSemanticStore(B, FD, Source, Decl, Attr); + return AttrBegin; +} + void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn) { llvm::Module &M = CGM.getModule(); @@ -762,20 +906,22 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, OB.emplace_back("convergencectrl", bundleArgs); } - // FIXME: support struct parameters where semantics are on members. - // See: https://github.com/llvm/llvm-project/issues/57874 + llvm::DenseMap OutputSemantic; + unsigned SRetOffset = 0; for (const auto &Param : Fn->args()) { if (Param.hasStructRetAttr()) { - // FIXME: support output. - // See: https://github.com/llvm/llvm-project/issues/57874 SRetOffset = 1; - Args.emplace_back(PoisonValue::get(Param.getType())); + llvm::Type *VarType = Param.getParamStructRetType(); + llvm::Value *Var = B.CreateAlloca(VarType); + OutputSemantic.try_emplace(FD, Var); + Args.push_back(Var); continue; } const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset); llvm::Value *SemanticValue = nullptr; + // FIXME: support inout/out parameters for semantics. if ([[maybe_unused]] HLSLParamModifierAttr *MA = PD->getAttr()) { llvm_unreachable("Not handled yet"); @@ -802,8 +948,20 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB); CI->setCallingConv(Fn->getCallingConv()); - // FIXME: Handle codegen for return type semantics. - // See: https://github.com/llvm/llvm-project/issues/57875 + + if (Fn->getReturnType() != CGM.VoidTy) + OutputSemantic.try_emplace(FD, CI); + + for (auto &[Decl, Source] : OutputSemantic) { + AllocaInst *AI = dyn_cast(Source); + llvm::Value *SourceValue = + AI ? B.CreateLoad(AI->getAllocatedType(), Source) : Source; + + auto AttrBegin = Decl->specific_attr_begin(); + auto AttrEnd = Decl->specific_attr_end(); + handleSemanticStore(B, FD, SourceValue, Decl, AttrBegin, AttrEnd); + } + B.CreateRetVoid(); // Add and identify root signature to function, if applicable diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index e6f3cc09819bd..c883282a8d9c8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -184,12 +184,22 @@ class CGHLSLRuntime { HLSLAppliedSemanticAttr *Semantic, std::optional Index); + void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic); + void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, + llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic); + std::pair> handleStructSemanticLoad( llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, @@ -197,12 +207,24 @@ class CGHLSLRuntime { specific_attr_iterator begin, specific_attr_iterator end); + specific_attr_iterator handleStructSemanticStore( + llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd); + std::pair> handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type, const clang::DeclaratorDecl *Decl, specific_attr_iterator begin, specific_attr_iterator end); + specific_attr_iterator + handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD, + llvm::Value *Source, const clang::DeclaratorDecl *Decl, + specific_attr_iterator AttrBegin, + specific_attr_iterator AttrEnd); + public: CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {} virtual ~CGHLSLRuntime() {} @@ -266,10 +288,22 @@ class CGHLSLRuntime { HLSLAppliedSemanticAttr *Semantic, std::optional Index); + void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source, + const clang::DeclaratorDecl *Decl, + HLSLAppliedSemanticAttr *Semantic, + std::optional Index); + llvm::Triple::ArchType getArch(); llvm::DenseMap LayoutTypes; unsigned SPIRVLastAssignedInputSemanticLocation = 0; + unsigned SPIRVLastAssignedOutputSemanticLocation = 0; }; } // namespace CodeGen diff --git a/clang/lib/Headers/llvm_libc_wrappers/assert.h b/clang/lib/Headers/llvm_libc_wrappers/assert.h index 610ed96a458c6..7eadb2c354aab 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/assert.h +++ b/clang/lib/Headers/llvm_libc_wrappers/assert.h @@ -19,13 +19,11 @@ #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif -#pragma omp begin declare target - -#include - -#pragma omp end declare target +// TODO: Define these for CUDA / HIP. #undef __LIBC_ATTRS diff --git a/clang/lib/Headers/llvm_libc_wrappers/ctype.h b/clang/lib/Headers/llvm_libc_wrappers/ctype.h index 960cf43302c4c..79b0c1e9be953 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/ctype.h +++ b/clang/lib/Headers/llvm_libc_wrappers/ctype.h @@ -13,128 +13,16 @@ #error "This file is for GPU offloading compilation only" #endif -// The GNU headers like to define 'toupper' and 'tolower' redundantly. This is -// necessary to prevent it from doing that and remapping our implementation. -#if (defined(__NVPTX__) || defined(__AMDGPU__)) && defined(__GLIBC__) -#pragma push_macro("__USE_EXTERN_INLINES") -#undef __USE_EXTERN_INLINES -#endif - #include_next -#if (defined(__NVPTX__) || defined(__AMDGPU__)) && defined(__GLIBC__) -#pragma pop_macro("__USE_EXTERN_INLINES") -#endif - -#if __has_include() - #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif -// The GNU headers like to provide these as macros, we need to undefine them so -// they do not conflict with the following definitions for the GPU. - -#pragma push_macro("isalnum") -#pragma push_macro("isalpha") -#pragma push_macro("isascii") -#pragma push_macro("isblank") -#pragma push_macro("iscntrl") -#pragma push_macro("isdigit") -#pragma push_macro("isgraph") -#pragma push_macro("islower") -#pragma push_macro("isprint") -#pragma push_macro("ispunct") -#pragma push_macro("isspace") -#pragma push_macro("isupper") -#pragma push_macro("isxdigit") -#pragma push_macro("toascii") -#pragma push_macro("tolower") -#pragma push_macro("toupper") -#pragma push_macro("isalnum_l") -#pragma push_macro("isalpha_l") -#pragma push_macro("isascii_l") -#pragma push_macro("isblank_l") -#pragma push_macro("iscntrl_l") -#pragma push_macro("isdigit_l") -#pragma push_macro("isgraph_l") -#pragma push_macro("islower_l") -#pragma push_macro("isprint_l") -#pragma push_macro("ispunct_l") -#pragma push_macro("isspace_l") -#pragma push_macro("isupper_l") -#pragma push_macro("isxdigit_l") - -#undef isalnum -#undef isalpha -#undef isascii -#undef iscntrl -#undef isdigit -#undef islower -#undef isgraph -#undef isprint -#undef ispunct -#undef isspace -#undef isupper -#undef isblank -#undef isxdigit -#undef toascii -#undef tolower -#undef toupper -#undef isalnum_l -#undef isalpha_l -#undef iscntrl_l -#undef isdigit_l -#undef islower_l -#undef isgraph_l -#undef isprint_l -#undef ispunct_l -#undef isspace_l -#undef isupper_l -#undef isblank_l -#undef isxdigit_l - -#pragma omp begin declare target - -#include - -#pragma omp end declare target - -// Restore the original macros when compiling on the host. -#if !defined(__NVPTX__) && !defined(__AMDGPU__) -#pragma pop_macro("isalnum") -#pragma pop_macro("isalpha") -#pragma pop_macro("isascii") -#pragma pop_macro("isblank") -#pragma pop_macro("iscntrl") -#pragma pop_macro("isdigit") -#pragma pop_macro("isgraph") -#pragma pop_macro("islower") -#pragma pop_macro("isprint") -#pragma pop_macro("ispunct") -#pragma pop_macro("isspace") -#pragma pop_macro("isupper") -#pragma pop_macro("isxdigit") -#pragma pop_macro("toascii") -#pragma pop_macro("tolower") -#pragma pop_macro("toupper") -#pragma pop_macro("isalnum_l") -#pragma pop_macro("isalpha_l") -#pragma pop_macro("isascii_l") -#pragma pop_macro("isblank_l") -#pragma pop_macro("iscntrl_l") -#pragma pop_macro("isdigit_l") -#pragma pop_macro("isgraph_l") -#pragma pop_macro("islower_l") -#pragma pop_macro("isprint_l") -#pragma pop_macro("ispunct_l") -#pragma pop_macro("isspace_l") -#pragma pop_macro("isupper_l") -#pragma pop_macro("isxdigit_l") -#endif +// TODO: Define these for CUDA / HIP. #undef __LIBC_ATTRS -#endif - #endif // __CLANG_LLVM_LIBC_WRAPPERS_CTYPE_H__ diff --git a/clang/lib/Headers/llvm_libc_wrappers/inttypes.h b/clang/lib/Headers/llvm_libc_wrappers/inttypes.h index 415f1e4b7bcab..22613898248f3 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/inttypes.h +++ b/clang/lib/Headers/llvm_libc_wrappers/inttypes.h @@ -19,13 +19,11 @@ #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif -#pragma omp begin declare target - -#include - -#pragma omp end declare target +// TODO: Define these for CUDA / HIP. #undef __LIBC_ATTRS diff --git a/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt b/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt deleted file mode 100644 index e012cd9e29312..0000000000000 --- a/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -LLVM libc declarations -====================== - -This directory will be filled by the `libc` project with declarations that are -availible on the device. Each declaration will use the `__LIBC_ATTRS` attribute -to control emission on the device side. diff --git a/clang/lib/Headers/llvm_libc_wrappers/stdio.h b/clang/lib/Headers/llvm_libc_wrappers/stdio.h index 950f91b3763e8..0c3e44823da70 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/stdio.h +++ b/clang/lib/Headers/llvm_libc_wrappers/stdio.h @@ -6,45 +6,19 @@ // //===----------------------------------------------------------------------===// +#ifndef __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__ +#define __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__ + #if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__) #error "This file is for GPU offloading compilation only" #endif #include_next -// In some old versions of glibc, other standard headers sometimes define -// special macros (e.g., __need_FILE) before including stdio.h to cause stdio.h -// to produce special definitions. Future includes of stdio.h when those -// special macros are undefined are expected to produce the normal definitions -// from stdio.h. -// -// We do not apply our include guard (__CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__) -// unconditionally to the above include_next. Otherwise, after an occurrence of -// the first glibc stdio.h use case described above, the include_next would be -// skipped for remaining includes of stdio.h, leaving required symbols -// undefined. -// -// We make the following assumptions to handle all use cases: -// -// 1. If the above include_next produces special glibc definitions, then (a) it -// does not produce the normal definitions that we must intercept below, (b) -// the current file was included from a glibc header that already defined -// __GLIBC__ (usually by including glibc's ), and (c) the above -// include_next does not define _STDIO_H. In that case, we skip the rest of -// the current file and don't guard against future includes. -// 2. If the above include_next produces the normal stdio.h definitions, then -// either (a) __GLIBC__ is not defined because C headers are from some other -// libc implementation or (b) the above include_next defines _STDIO_H to -// prevent the above include_next from having any effect in the future. -#if !defined(__GLIBC__) || defined(_STDIO_H) - -#ifndef __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__ -#define __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__ - -#if __has_include() - #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif // Some headers provide these as macros. Temporarily undefine them so they do @@ -60,21 +34,19 @@ #pragma omp begin declare target -#include +__LIBC_ATTRS extern FILE *stderr; +__LIBC_ATTRS extern FILE *stdin; +__LIBC_ATTRS extern FILE *stdout; #pragma omp end declare target -#undef __LIBC_ATTRS - // Restore the original macros when compiling on the host. #if !defined(__NVPTX__) && !defined(__AMDGPU__) -#pragma pop_macro("stdout") #pragma pop_macro("stderr") #pragma pop_macro("stdin") +#pragma pop_macro("stdout") #endif -#endif +#undef __LIBC_ATTRS #endif // __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__ - -#endif diff --git a/clang/lib/Headers/llvm_libc_wrappers/stdlib.h b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h index d79e7fa041ad4..7af5e2ebe031a 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/stdlib.h +++ b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h @@ -15,39 +15,18 @@ #include_next -#if __has_include() - #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif #pragma omp begin declare target -// The LLVM C library uses these named types so we forward declare them. -typedef void (*__atexithandler_t)(void); -typedef int (*__search_compare_t)(const void *, const void *); -typedef int (*__qsortcompare_t)(const void *, const void *); -typedef int (*__qsortrcompare_t)(const void *, const void *, void *); - -// Enforce ABI compatibility with the structs used by the LLVM C library. -_Static_assert(__builtin_offsetof(div_t, quot) == 0, "ABI mismatch!"); -_Static_assert(__builtin_offsetof(ldiv_t, quot) == 0, "ABI mismatch!"); -_Static_assert(__builtin_offsetof(lldiv_t, quot) == 0, "ABI mismatch!"); - -#if defined(__GLIBC__) && __cplusplus >= 201103L -#define at_quick_exit atexit -#endif - -#include - -#if defined(__GLIBC__) && __cplusplus >= 201103L -#undef at_quick_exit -#endif +// TODO: Define these for CUDA / HIP. #pragma omp end declare target #undef __LIBC_ATTRS -#endif - #endif // __CLANG_LLVM_LIBC_WRAPPERS_STDLIB_H__ diff --git a/clang/lib/Headers/llvm_libc_wrappers/string.h b/clang/lib/Headers/llvm_libc_wrappers/string.h index 519f46672e56f..596c997d2c243 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/string.h +++ b/clang/lib/Headers/llvm_libc_wrappers/string.h @@ -24,89 +24,20 @@ extern "C" { #undef __cplusplus #endif -#include_next #pragma pop_macro("__cplusplus") #ifdef __cplusplus } #endif -#if __has_include() - #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) -#endif - -#pragma omp begin declare target - -// The GNU headers provide C++ standard compliant headers when in C++ mode and -// the LLVM libc does not. We need to manually provide the definitions using the -// same prototypes. -#if defined(__cplusplus) && defined(__GLIBC__) && \ - defined(__CORRECT_ISO_CPP_STRING_H_PROTO) - -#ifndef __LIBC_ATTRS -#define __LIBC_ATTRS -#endif - -extern "C" { -void *memccpy(void *__restrict, const void *__restrict, int, - size_t) __LIBC_ATTRS; -int memcmp(const void *, const void *, size_t) __LIBC_ATTRS; -void *memcpy(void *__restrict, const void *__restrict, size_t) __LIBC_ATTRS; -void *memmem(const void *, size_t, const void *, size_t) __LIBC_ATTRS; -void *memmove(void *, const void *, size_t) __LIBC_ATTRS; -void *mempcpy(void *__restrict, const void *__restrict, size_t) __LIBC_ATTRS; -void *memset(void *, int, size_t) __LIBC_ATTRS; -char *stpcpy(char *__restrict, const char *__restrict) __LIBC_ATTRS; -char *stpncpy(char *__restrict, const char *__restrict, size_t) __LIBC_ATTRS; -char *strcat(char *__restrict, const char *__restrict) __LIBC_ATTRS; -int strcmp(const char *, const char *) __LIBC_ATTRS; -int strcoll(const char *, const char *) __LIBC_ATTRS; -char *strcpy(char *__restrict, const char *__restrict) __LIBC_ATTRS; -size_t strcspn(const char *, const char *) __LIBC_ATTRS; -char *strdup(const char *) __LIBC_ATTRS; -size_t strlen(const char *) __LIBC_ATTRS; -char *strncat(char *__restrict, const char *__restrict, size_t) __LIBC_ATTRS; -int strncmp(const char *, const char *, size_t) __LIBC_ATTRS; -char *strncpy(char *__restrict, const char *__restrict, size_t) __LIBC_ATTRS; -char *strndup(const char *, size_t) __LIBC_ATTRS; -size_t strnlen(const char *, size_t) __LIBC_ATTRS; -size_t strspn(const char *, const char *) __LIBC_ATTRS; -char *strtok(char *__restrict, const char *__restrict) __LIBC_ATTRS; -char *strtok_r(char *__restrict, const char *__restrict, - char **__restrict) __LIBC_ATTRS; -size_t strxfrm(char *__restrict, const char *__restrict, size_t) __LIBC_ATTRS; -} - -extern "C++" { -char *strstr(char *, const char *) noexcept __LIBC_ATTRS; -const char *strstr(const char *, const char *) noexcept __LIBC_ATTRS; -char *strpbrk(char *, const char *) noexcept __LIBC_ATTRS; -const char *strpbrk(const char *, const char *) noexcept __LIBC_ATTRS; -char *strrchr(char *, int) noexcept __LIBC_ATTRS; -const char *strrchr(const char *, int) noexcept __LIBC_ATTRS; -char *strchr(char *, int) noexcept __LIBC_ATTRS; -const char *strchr(const char *, int) noexcept __LIBC_ATTRS; -char *strchrnul(char *, int) noexcept __LIBC_ATTRS; -const char *strchrnul(const char *, int) noexcept __LIBC_ATTRS; -char *strcasestr(char *, const char *) noexcept __LIBC_ATTRS; -const char *strcasestr(const char *, const char *) noexcept __LIBC_ATTRS; -void *memrchr(void *__s, int __c, size_t __n) noexcept __LIBC_ATTRS; -const void *memrchr(const void *__s, int __c, size_t __n) noexcept __LIBC_ATTRS; -void *memchr(void *__s, int __c, size_t __n) noexcept __LIBC_ATTRS; -const void *memchr(const void *__s, int __c, size_t __n) noexcept __LIBC_ATTRS; -} - #else -#include - +#define __LIBC_ATTRS #endif -#pragma omp end declare target +// TODO: Define these for CUDA / HIP. #undef __LIBC_ATTRS -#endif - #endif // __CLANG_LLVM_LIBC_WRAPPERS_STRING_H__ diff --git a/clang/lib/Headers/llvm_libc_wrappers/time.h b/clang/lib/Headers/llvm_libc_wrappers/time.h index e18a16a281f18..57e436ae87664 100644 --- a/clang/lib/Headers/llvm_libc_wrappers/time.h +++ b/clang/lib/Headers/llvm_libc_wrappers/time.h @@ -15,21 +15,15 @@ #include_next -#if __has_include() - #if defined(__HIP__) || defined(__CUDA__) #define __LIBC_ATTRS __attribute__((device)) +#else +#define __LIBC_ATTRS #endif -#pragma omp begin declare target - -_Static_assert(sizeof(clock_t) == sizeof(long), "ABI mismatch!"); +// TODO: Define these for CUDA / HIP. -#include - -#pragma omp end declare target - -#endif +#undef __LIBC_ATTRS #else #include_next diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index bda7aa32a9348..e3af5023c74d0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1839,6 +1839,70 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RestrictAttr(S.Context, AL, DeallocE, DeallocPtrIdx)); } +bool Sema::CheckSpanLikeType(const AttributeCommonInfo &CI, + const QualType &Ty) { + // Note that there may also be numerous cases of pointer + integer / + // pointer + pointer / integer + pointer structures not actually exhibiting + // a span-like semantics, so sometimes these heuristics expectedly + // lead to false positive results. + auto emitWarning = [this, &CI](unsigned NoteDiagID) { + Diag(CI.getLoc(), diag::warn_attribute_return_span_only) << CI; + return Diag(CI.getLoc(), NoteDiagID); + }; + if (Ty->isDependentType()) + return false; + // isCompleteType is used to force template class instantiation. + if (!isCompleteType(CI.getLoc(), Ty)) + return emitWarning(diag::note_returned_incomplete_type); + const RecordDecl *RD = Ty->getAsRecordDecl(); + if (!RD || RD->isUnion()) + return emitWarning(diag::note_returned_not_struct); + if (const auto *CXXRD = dyn_cast(RD)) { + if (CXXRD->getNumBases() > 0) { + return emitWarning(diag::note_type_inherits_from_base); + } + } + auto FieldsBegin = RD->field_begin(); + auto FieldsCount = std::distance(FieldsBegin, RD->field_end()); + if (FieldsCount != 2) + return emitWarning(diag::note_returned_not_two_field_struct) << FieldsCount; + QualType FirstFieldType = FieldsBegin->getType(); + QualType SecondFieldType = std::next(FieldsBegin)->getType(); + auto validatePointerType = [](const QualType &T) { + // It must not point to functions. + return T->isPointerType() && !T->isFunctionPointerType(); + }; + auto checkIntegerType = [this, emitWarning](const QualType &T, + const int FieldNo) -> bool { + const auto *BT = dyn_cast(T.getCanonicalType()); + if (!BT || !BT->isInteger()) + return emitWarning(diag::note_returned_not_integer_field) << FieldNo; + auto IntSize = Context.getTypeSize(Context.IntTy); + if (Context.getTypeSize(BT) < IntSize) + return emitWarning(diag::note_returned_not_wide_enough_field) + << FieldNo << IntSize; + return false; + }; + if (validatePointerType(FirstFieldType) && + validatePointerType(SecondFieldType)) { + // Pointer + pointer. + return false; + } else if (validatePointerType(FirstFieldType)) { + // Pointer + integer? + return checkIntegerType(SecondFieldType, 2); + } else if (validatePointerType(SecondFieldType)) { + // Integer + pointer? + return checkIntegerType(FirstFieldType, 1); + } + return emitWarning(diag::note_returned_not_span_struct); +} + +static void handleMallocSpanAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + QualType ResultType = getFunctionOrMethodResultType(D); + if (!S.CheckSpanLikeType(AL, ResultType)) + D->addAttr(::new (S.Context) MallocSpanAttr(S.Context, AL)); +} + static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Ensure we don't combine these with themselves, since that causes some // confusing behavior. @@ -1966,8 +2030,16 @@ static bool isKnownToAlwaysThrow(const FunctionDecl *FD) { if (const auto *EWC = dyn_cast(OnlyStmt)) { OnlyStmt = EWC->getSubExpr(); } - // Check if the only statement is a throw expression. - return isa(OnlyStmt); + + if (isa(OnlyStmt)) { + const auto *MD = dyn_cast(FD); + if (MD && MD->isVirtual()) { + const auto *RD = MD->getParent(); + return MD->hasAttr() || (RD && RD->isEffectivelyFinal()); + } + return true; + } + return false; } void clang::inferNoReturnAttr(Sema &S, const Decl *D) { @@ -7268,6 +7340,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Restrict: handleRestrictAttr(S, D, AL); break; + case ParsedAttr::AT_MallocSpan: + handleMallocSpanAttr(S, D, AL); + break; case ParsedAttr::AT_Mode: handleModeAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 5555916c2536f..e7ee3b1adf941 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -773,7 +773,7 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { bool SemaHLSL::determineActiveSemanticOnScalar( FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) { + SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr(); if (ActiveSemantic.Semantic) @@ -805,7 +805,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar( for (unsigned I = 0; I < ElementCount; ++I) { Twine VariableName = BaseName.concat(Twine(Location + I)); - auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str()); + auto [_, Inserted] = UsedSemantics.insert(VariableName.str()); if (!Inserted) { Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap) << VariableName.str(); @@ -816,26 +816,29 @@ bool SemaHLSL::determineActiveSemanticOnScalar( return true; } -bool SemaHLSL::determineActiveSemantic( - FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic, llvm::StringSet<> &ActiveInputSemantics) { +bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, + DeclaratorDecl *OutputDecl, + DeclaratorDecl *D, + SemanticInfo &ActiveSemantic, + llvm::StringSet<> &UsedSemantics) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr(); if (ActiveSemantic.Semantic) ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); } - const Type *T = D->getType()->getUnqualifiedDesugaredType(); + const Type *T = D == FD ? &*FD->getReturnType() : &*D->getType(); + T = T->getUnqualifiedDesugaredType(); + const RecordType *RT = dyn_cast(T); if (!RT) return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic, - ActiveInputSemantics); + UsedSemantics); const RecordDecl *RD = RT->getDecl(); for (FieldDecl *Field : RD->fields()) { SemanticInfo Info = ActiveSemantic; - if (!determineActiveSemantic(FD, OutputDecl, Field, Info, - ActiveInputSemantics)) { + if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -915,13 +918,21 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { if (ActiveSemantic.Semantic) ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); + // FIXME: Verify output semantics in parameters. if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic, ActiveInputSemantics)) { Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); } } - // FIXME: Verify return type semantic annotation. + + SemanticInfo ActiveSemantic; + llvm::StringSet<> ActiveOutputSemantics; + ActiveSemantic.Semantic = FD->getAttr(); + if (ActiveSemantic.Semantic) + ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); + if (!FD->getReturnType()->isVoidType()) + determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics); } void SemaHLSL::checkSemanticAnnotation( diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3a4b2ccc74350..26693514bb278 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -796,6 +796,14 @@ static void instantiateDependentHLSLParamModifierAttr( "out or inout parameter type must be a reference and restrict qualified"); } +static void instantiateDependentMallocSpanAttr(Sema &S, + const MallocSpanAttr *Attr, + Decl *New) { + QualType RT = getFunctionOrMethodResultType(New); + if (!S.CheckSpanLikeType(*Attr, RT)) + New->addAttr(Attr->clone(S.getASTContext())); +} + void Sema::InstantiateAttrsForDecl( const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -1007,6 +1015,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (auto *A = dyn_cast(TmplAttr)) { + instantiateDependentMallocSpanAttr(*this, A, New); + continue; + } + if (auto *A = dyn_cast(TmplAttr)) { if (!New->hasAttr()) { auto *NewAttr = A->clone(Context); diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index 68bee710e5ce5..2db5310271e1d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -115,7 +115,23 @@ class RAIIMutexDescriptor { return false; const IdentifierInfo *II = cast(C->getDecl()->getParent())->getIdentifier(); - return II == Guard; + if (II != Guard) + return false; + + // For unique_lock, check if it's constructed with a ctor that takes the tag + // type defer_lock_t. In this case, the lock is not acquired. + if constexpr (std::is_same_v) { + if (GuardName == "unique_lock" && C->getNumArgs() >= 2) { + const Expr *SecondArg = C->getArgExpr(1); + QualType ArgType = SecondArg->getType().getNonReferenceType(); + if (const auto *RD = ArgType->getAsRecordDecl(); + RD && RD->getName() == "defer_lock_t" && RD->isInStdNamespace()) { + return false; + } + } + } + + return true; } public: diff --git a/clang/test/Analysis/block-in-critical-section.cpp b/clang/test/Analysis/block-in-critical-section.cpp index ee9a708f231a8..674a09265faa5 100644 --- a/clang/test/Analysis/block-in-critical-section.cpp +++ b/clang/test/Analysis/block-in-critical-section.cpp @@ -16,9 +16,12 @@ struct lock_guard { lock_guard(std::mutex) {} ~lock_guard() {} }; +struct defer_lock_t {}; +constexpr defer_lock_t defer_lock{}; template struct unique_lock { unique_lock(std::mutex) {} + unique_lock(std::mutex, defer_lock_t) {} // defer_lock parameter ~unique_lock() {} }; template @@ -309,3 +312,9 @@ void testTrylockCurrentlyFalsePositive(pthread_mutex_t *m) { // FIXME: this is a false positive, the lock was not acquired } } + +void testBlockInCriticalSectionUniqueLockWithDeferLock() { + std::mutex g_mutex; + std::unique_lock lock(g_mutex, std::defer_lock); + sleep(1); // no-warning +} diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c index 99ae4506b1f16..35d977f2b3dac 100644 --- a/clang/test/CIR/CodeGen/call.c +++ b/clang/test/CIR/CodeGen/call.c @@ -130,7 +130,7 @@ int f12(void) { // OGCG: %{{.+}} = call i32 @f10(i32 noundef 1) #[[ATTR0:.+]] // OGCG-NEXT: %{{.+}} = call i32 @f11(i32 noundef 2) #[[ATTR1:.+]] -// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read, errnomem: none, target_mem0: none, target_mem1: none) } +// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } // LLVM: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } // OGCG: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } diff --git a/clang/test/CIR/CodeGen/ternary-throw.cpp b/clang/test/CIR/CodeGen/ternary-throw.cpp index fb8897fa18a74..74168c19ca7c3 100644 --- a/clang/test/CIR/CodeGen/ternary-throw.cpp +++ b/clang/test/CIR/CodeGen/ternary-throw.cpp @@ -195,3 +195,46 @@ const int& test_cond_const_false_throw_true() { // OGCG-NOT: __cxa_throw // OGCG: ret ptr %[[A]] +const int &test_cond_const_true_throw_true() { + const int a = 30; + return true ? throw 0 : a; +} + +// CIR-LABEL: cir.func{{.*}} @_Z31test_cond_const_true_throw_truev( +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__retval"] +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["a", init, const] +// CIR: %[[CONST_30:.*]] = cir.const #cir.int<30> : !s32i +// CIR: cir.store{{.*}} %[[CONST_30]], %[[A_ADDR]] : !s32i, !cir.ptr +// CIR: %[[EXCEPTION:.*]] = cir.alloc.exception 4 -> !cir.ptr +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[EXCEPTION]] : !s32i, !cir.ptr +// CIR: cir.throw %[[EXCEPTION]] : !cir.ptr, @_ZTIi +// CIR: cir.unreachable +// CIR: ^[[NO_PRED_LABEL:.*]]: +// CIR: %[[CONST_NULL:.*]] = cir.const #cir.ptr : !cir.ptr +// CIR: cir.store %[[CONST_NULL]], %[[RET_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr>, !cir.ptr +// CIR: cir.return %[[TMP_RET]] : !cir.ptr + +// LLVM-LABEL: define{{.*}} ptr @_Z31test_cond_const_true_throw_truev( +// LLVM: %[[RET_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 30, ptr %[[A_ADDR]], align 4 +// LLVM: %[[EXCEPTION:.*]] = call ptr @__cxa_allocate_exception(i64 4) +// LLVM: store i32 0, ptr %[[EXCEPTION]], align 16 +// LLVM: call void @__cxa_throw(ptr %[[EXCEPTION]], ptr @_ZTIi, ptr null) +// LLVM: unreachable +// LLVM: [[NO_PRED_LABEL:.*]]: +// LLVM: store ptr null, ptr %[[RET_ADDR]], align 8 +// LLVM: %[[TMP_RET:.*]] = load ptr, ptr %[[RET_ADDR]], align 8 +// LLVM: ret ptr %[[TMP_RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z31test_cond_const_true_throw_truev( +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 30, ptr %[[A_ADDR]], align 4 +// OGCG: %[[EXCEPTION:.*]] = call ptr @__cxa_allocate_exception(i64 4) +// OGCG: store i32 0, ptr %[[EXCEPTION]], align 16 +// OGCG: call void @__cxa_throw(ptr %[[EXCEPTION]], ptr @_ZTIi, ptr null) +// OGCG: unreachable +// OGCG: [[NO_PRED_LABEL:.*]]: +// OGCG: ret ptr [[UNDEF:.*]] diff --git a/clang/test/CIR/CodeGenOpenACC/atomic-capture.cpp b/clang/test/CIR/CodeGenOpenACC/atomic-capture.cpp new file mode 100644 index 0000000000000..8bdffb41d1890 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenACC/atomic-capture.cpp @@ -0,0 +1,508 @@ +// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s + +struct HasOps { + operator float(); + int thing(); + int operator++(); + int operator++(int); +}; + +void use(int x, int v, float f, HasOps ops) { + // CHECK: cir.func{{.*}}(%[[X_ARG:.*]]: !s32i{{.*}}, %[[V_ARG:.*]]: !s32i{{.*}}, %[[F_ARG:.*]]: !cir.float{{.*}}){{.*}}, %[[OPS_ARG:.*]]: !rec_HasOps{{.*}}) { + // CHECK-NEXT: %[[X_ALLOCA:.*]] = cir.alloca !s32i, !cir.ptr, ["x", init] + // CHECK-NEXT: %[[V_ALLOCA:.*]] = cir.alloca !s32i, !cir.ptr, ["v", init] + // CHECK-NEXT: %[[F_ALLOCA:.*]] = cir.alloca !cir.float, !cir.ptr, ["f", init] + // CHECK-NEXT: %[[OPS_ALLOCA:.*]] = cir.alloca !rec_HasOps, !cir.ptr, ["ops", init] + // CHECK-NEXT: cir.store %[[X_ARG]], %[[X_ALLOCA]] : !s32i, !cir.ptr + // CHECK-NEXT: cir.store %[[V_ARG]], %[[V_ALLOCA]] : !s32i, !cir.ptr + // CHECK-NEXT: cir.store %[[F_ARG]], %[[F_ALLOCA]] : !cir.float, !cir.ptr + // CHECK-NEXT: cir.store %[[OPS_ARG]], %[[OPS_ALLOCA]] : !rec_HasOps, !cir.ptr + + // CHECK-NEXT: %[[X_LOAD:.*]] = cir.load{{.*}} %[[X_ALLOCA]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[V_LOAD:.*]] = cir.load{{.*}} %[[V_ALLOCA]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[CMP:.*]] = cir.cmp(ne, %[[X_LOAD]], %[[V_LOAD]]) : !s32i, !cir.bool + // CHECK-NEXT: %[[IF_COND_CAST:.*]] = builtin.unrealized_conversion_cast %[[CMP:.*]] : !cir.bool to i1 + // CHECK-NEXT: acc.atomic.capture if(%[[IF_COND_CAST]]) { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture if (x != v) + v = x++; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = ++x; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = x--; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = --x; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[MUL:.*]] = cir.binop(mul, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[X_CAST]], %[[MUL]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[ADD]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = x += f * 1; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[MUL:.*]] = cir.binop(mul, %[[X_CAST]], %[[ADD]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[MUL]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = x = x * (f + 1); + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[MUL:.*]] = cir.binop(mul, %[[ADD]], %[[X_CAST]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[MUL]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + v = x = (f + 1) * x; + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[MUL:.*]] = cir.binop(mul, %[[X_CAST]], %[[ADD]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[MUL]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; x *= f + 1; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[SUB:.*]] = cir.binop(sub, %[[X_CAST]], %[[ADD]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[SUB]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + x -= f + 1; + v = x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[DIV:.*]] = cir.binop(div, %[[X_CAST]], %[[ADD]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[DIV]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + x = x / (f + 1); + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[OPS_CONV:.*]] = cir.call @{{.*}}(%[[OPS_ALLOCA]]) : (!cir.ptr) -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[OPS_CONV]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[DIV:.*]] = cir.binop(div, %[[ADD]], %[[X_CAST]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[DIV]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + x = (f + ops) / x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[ONE_INT:.*]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: %[[ONE_CAST:.*]] = cir.cast int_to_float %[[ONE_INT]] : !s32i -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[ONE_CAST]]) : !cir.float + // CHECK-NEXT: %[[DIV:.*]] = cir.binop(div, %[[X_CAST]], %[[ADD]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[DIV]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + x = x / (f + 1); + v = x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[F_LOAD:.*]] = cir.load{{.*}} %[[F_ALLOCA]] : !cir.ptr, !cir.float + // CHECK-NEXT: %[[OPS_CONV:.*]] = cir.call @{{.*}}(%[[OPS_ALLOCA]]) : (!cir.ptr) -> !cir.float + // CHECK-NEXT: %[[ADD:.*]] = cir.binop(add, %[[F_LOAD]], %[[OPS_CONV]]) : !cir.float + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[X_CAST:.*]] = cir.cast int_to_float %[[X_VAR_LOAD]] : !s32i -> !cir.float + // CHECK-NEXT: %[[DIV:.*]] = cir.binop(div, %[[ADD]], %[[X_CAST]]) : !cir.float + // CHECK-NEXT: %[[INT_CAST:.*]] = cir.cast float_to_int %[[DIV]] : !cir.float -> !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INT_CAST]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + x = (f + ops) / x; + v = x; + } + + // CHECK-NEXT: %[[OPS_CONV:.*]] = cir.call @{{.*}}(%[[OPS_ALLOCA]]) : (!cir.ptr) -> !cir.float + // CHECK-NEXT: %[[OPS_CONV_TO_INT:.*]] = cir.cast float_to_int %[[OPS_CONV]] : !cir.float -> !s32i + // + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.write %[[X_ALLOCA]] = %[[OPS_CONV_TO_INT]] : !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + x = ops; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + x++; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + ++x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + x++; + v = x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[INC:.*]] = cir.unary(inc, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[INC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + ++x; + v = x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + x--; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: } +#pragma acc atomic capture + { + v = x; + --x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + x--; + v = x; + } + + // CHECK-NEXT: acc.atomic.capture { + // CHECK-NEXT: acc.atomic.update %[[X_ALLOCA]] : !cir.ptr { + // CHECK-NEXT: ^bb0(%[[X_VAR:.*]]: !s32i{{.*}}): + // CHECK-NEXT: %[[X_VAR_ALLOC:.*]] = cir.alloca !s32i, !cir.ptr, ["x_var", init] + // CHECK-NEXT: cir.store %[[X_VAR]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: %[[DEC:.*]] = cir.unary(dec, %[[X_VAR_LOAD]]) nsw : !s32i, !s32i + // CHECK-NEXT: cir.store{{.*}} %[[DEC]], %[[X_VAR_ALLOC]] : !s32i, !cir.ptr + // + // CHECK-NEXT: %[[X_VAR_LOAD:.*]] = cir.load{{.*}} %[[X_VAR_ALLOC]] : !cir.ptr, !s32i + // CHECK-NEXT: acc.yield %[[X_VAR_LOAD]] : !s32i + // CHECK-NEXT: } + // CHECK-NEXT: acc.atomic.read %[[V_ALLOCA]] = %[[X_ALLOCA]] : !cir.ptr, !cir.ptr, !s32i + // CHECK-NEXT: } +#pragma acc atomic capture + { + --x; + v = x; + } +} diff --git a/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp b/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp index b4d76e18bf345..e85c26718acb8 100644 --- a/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp +++ b/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp @@ -1,10 +1,6 @@ // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fopenacc -fclangir -emit-cir %s -o %t.cir -verify -void HelloWorld(int *A, int *B, int *C, int N) { - -// expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenACC Atomic Construct}} -#pragma acc atomic capture - B = A += ++N; +void HelloWorld(int *A) { // expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenACC Declare Construct}} #pragma acc declare create(A) diff --git a/clang/test/CIR/IR/eh-inflight.cir b/clang/test/CIR/IR/eh-inflight.cir new file mode 100644 index 0000000000000..d4d8d5cefb0af --- /dev/null +++ b/clang/test/CIR/IR/eh-inflight.cir @@ -0,0 +1,40 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +!u8i = !cir.int + +module { + +cir.func dso_local @inflight_exception() { + %exception_ptr, %type_id = cir.eh.inflight_exception + cir.return +} + +// CHECK: cir.func dso_local @inflight_exception() { +// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception +// CHECK: cir.return +// CHECK: } + +cir.func dso_local @inflight_exception_with_cleanup() { + %exception_ptr, %type_id = cir.eh.inflight_exception cleanup + cir.return +} + +// CHECK: cir.func dso_local @inflight_exception_with_cleanup() { +// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception cleanup +// CHECK: cir.return +// CHECK: } + +cir.global "private" constant external @_ZTIi : !cir.ptr +cir.global "private" constant external @_ZTIPKc : !cir.ptr + +cir.func dso_local @inflight_exception_with_catch_type_list() { + %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] + cir.return +} + +// CHECK: cir.func dso_local @inflight_exception_with_catch_type_list() { +// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] +// CHECK: cir.return +// CHECK:} + +} diff --git a/clang/test/CIR/Lowering/eh-inflight.cir b/clang/test/CIR/Lowering/eh-inflight.cir new file mode 100644 index 0000000000000..31e1e474a046b --- /dev/null +++ b/clang/test/CIR/Lowering/eh-inflight.cir @@ -0,0 +1,53 @@ +// RUN: cir-opt %s -cir-to-llvm -o %t.cir + +!u8i = !cir.int + +module { + +// CHECK: llvm.func @__gxx_personality_v0(...) -> i32 + +cir.func @inflight_exception() { + %exception_ptr, %type_id = cir.eh.inflight_exception + cir.return +} + +// CHECK: llvm.func @inflight_exception() attributes {personality = @__gxx_personality_v0} { +// CHECK: %[[CONST_0:.*]] = llvm.mlir.zero : !llvm.ptr +// CHECK: %[[LP:.*]] = llvm.landingpad (catch %[[CONST_0]] : !llvm.ptr) : !llvm.struct<(ptr, i32)> +// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)> +// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)> +// CHECK: llvm.return +// CHECK: } + +cir.func @inflight_exception_with_cleanup() { + %exception_ptr, %type_id = cir.eh.inflight_exception cleanup + cir.return +} + +// CHECK: llvm.func @inflight_exception_with_cleanup() attributes {personality = @__gxx_personality_v0} { +// CHECK: %[[LP:.*]] = llvm.landingpad cleanup : !llvm.struct<(ptr, i32)> +// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)> +// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)> +// CHECK: llvm.return +// CHECK: } + + +cir.global "private" constant external @_ZTIi : !cir.ptr +cir.global "private" constant external @_ZTIPKc : !cir.ptr + +cir.func @inflight_exception_with_catch_type_list() { + %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] + cir.return +} + +// CHECK: llvm.func @inflight_exception_with_catch_type_list() attributes {personality = @__gxx_personality_v0} { +// CHECK: %[[TI_1_ADDR:.*]] = llvm.mlir.addressof @_ZTIPKc : !llvm.ptr +// CHECK: %[[TI_2_ADDR:.*]] = llvm.mlir.addressof @_ZTIi : !llvm.ptr +// CHECK: %[[LP:.*]] = llvm.landingpad (catch %[[TI_2_ADDR]] : !llvm.ptr) (catch %[[TI_1_ADDR]] : !llvm.ptr) : !llvm.struct<(ptr, i32)> +// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)> +// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)> +// CHECK: llvm.return +// CHECK: } + + +} diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl index 1bba87ea07141..be30e79438831 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -3,8 +3,9 @@ // CHECK: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 // CHECK: define void @main() {{.*}} { -float4 main(float4 p : SV_Position) { +float4 main(float4 p : SV_Position) : A { // 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]]) + // CHECK: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16 return p; } diff --git a/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl new file mode 100644 index 0000000000000..2f8dc97ef762e --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic-struct-2-output.hlsl @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-DX,CHECK +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-VK,CHECK + + +struct Input { + float Idx : SV_Position0; + float Gid : SV_Position1; +}; + +struct Output { + float a : A; + float b : B; +}; + +// Make sure SV_DispatchThreadID translated into dx.thread.id. + +// CHECK-DX: define hidden void @_Z3foo5Input(ptr dead_on_unwind noalias writable sret(%struct.Output) align 1 %agg.result, ptr noundef byval(%struct.Input) align 1 %input) +// CHECK-VK: define hidden spir_func void @_Z3foo5Input(ptr dead_on_unwind noalias writable sret(%struct.Output) align 1 %agg.result, ptr noundef byval(%struct.Input) align 1 %input) + +// CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 0 +// CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1 +// CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 0 +// CHECK: store float %[[#tmp]], ptr %a, align 1 +// CHECK: %Gid = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 1 +// CHECK: %[[#tmp:]] = load float, ptr %Gid, align 1 +// CHECK: %b = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 1 +// CHECK: store float %[[#tmp]], ptr %b, align 1 + +Output foo(Input input) { + Output o; + o.a = input.Idx; + o.b = input.Gid; + return o; +} + diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl new file mode 100644 index 0000000000000..d75f4e0ca8338 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv +// RUN: %clang_cc1 -triple dxil-px-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx + +struct S0 { + float4 position[2]; + float4 color; +}; + +// CHECK-SPIRV-DAG: @A0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#METADATA_0:]] + +[shader("pixel")] +S0 main1(float4 input : A) : B { +// CHECK: %[[#ARG:]] = alloca %struct.S0, align 16 +// CHECK-SPIRV: %[[#INPUT:]] = load <4 x float>, ptr addrspace(7) @A0, align 16 +// CHECK-DXIL: %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %A0) +// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %[[#INPUT]]) + + // CHECK: %[[#ST:]] = load %struct.S0, ptr %[[#ARG]], align 16 + // CHECK: %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0 + // CHECK-SPIRV: store [2 x <4 x float>] %[[#TMP]], ptr addrspace(8) @B0, align 16 + // CHECK-DXIL: call void @llvm.dx.store.output.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, [2 x <4 x float>] %[[#TMP]]) + // CHECK: %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1 + // CHECK-SPIRV: store <4 x float> %[[#TMP]], ptr addrspace(8) @B2, align 16 + // CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]]) + + S0 output; + output.position[0] = input; + output.position[1] = input; + output.color = input; + return output; +} + +// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]} +// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0} +// | `- Location index +// `-> Decoration "Location" diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl new file mode 100644 index 0000000000000..0f2444d21724a --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-DXIL,CHECK +// RUN: %clang_cc1 -triple spirv-linux-vulkan-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK + + +struct Input { + // FIXME: change this once we have a valid system semantic as input for VS. + float Idx : B2; +}; + +struct Output { + float a : A4; + float b : A2; +}; + +// CHECK-SPIRV-DAG: @B2 = external hidden thread_local addrspace(7) externally_initialized constant float, !spirv.Decorations ![[#METADATA_0:]] +// CHECK-SPIRV-DAG: @A4 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#METADATA_0:]] +// CHECK-SPIRV-DAG: @A2 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#METADATA_2:]] + +// CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 0 +// CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1 +// CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 0 +// CHECK: store float %[[#tmp]], ptr %a, align 1 + +// CHECK: %Idx1 = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 0 +// CHECK: %[[#tmp:]] = load float, ptr %Idx1, align 1 +// CHECK: %b = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 1 +// CHECK: store float %[[#tmp]], ptr %b, align 1 + +Output main(Input input) { + Output o; + o.a = input.Idx; + o.b = input.Idx; + return o; +} + +// Code generated in the entrypoint wrapper: + +// CHECK: %[[#OUTPUT:]] = alloca %struct.Output, align 8 + +// CHECK-SPIRV: call spir_func void @_Z4main5Input(ptr %[[#OUTPUT]], ptr %[[#]]) +// CHECK-DXIL: call void @_Z4main5Input(ptr %[[#OUTPUT]], ptr %[[#]]) + +// CHECK: %[[#TMP:]] = load %struct.Output, ptr %[[#OUTPUT]], align 4 +// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 0 +// CHECK-SPIRV: store float %[[#VAL]], ptr addrspace(8) @A4, align 4 +// CHECK-DXIL: call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#VAL]]) +// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 1 +// CHECK-SPIRV: store float %[[#VAL]], ptr addrspace(8) @A2, align 4 +// CHECK-DXIL: call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#VAL]]) + +// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]} +// CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]} +// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0} +// CHECK-SPIRV-DAG: ![[#METADATA_3]] = !{i32 30, i32 1} +// | `- Location index +// `-> Decoration "Location" diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl b/clang/test/CodeGenHLSL/sret_output.hlsl index eefc9dabab517..e1aa0973fe5db 100644 --- a/clang/test/CodeGenHLSL/sret_output.hlsl +++ b/clang/test/CodeGenHLSL/sret_output.hlsl @@ -1,21 +1,33 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ -// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK-DX,CHECK +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple spirv-pc-vulkan-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK-VK,CHECK -// FIXME: add semantic to a. -// See https://github.com/llvm/llvm-project/issues/57874 struct S { - float a; + float a : A4; }; +// CHECK-VK: @A4 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#ATTR0:]] // Make sure sret parameter is generated. -// CHECK:define internal void @_Z7ps_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result) -// FIXME: change it to real value instead of poison value once semantic is add to a. -// Make sure the function with sret is called. -// CHECK:call void @_Z7ps_mainv(ptr poison) -[shader("pixel")] -S ps_main() { +// CHECK-DX: define internal void @_Z7vs_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result) +// CHECK-VK: define internal spir_func void @_Z7vs_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result) + +[shader("vertex")] +S vs_main() { S s; s.a = 0; return s; }; + +// CHECK: %[[#alloca:]] = alloca %struct.S, align 8 +// CHECK-DX: call void @_Z7vs_mainv(ptr %[[#alloca]]) +// CHECK-VK: call spir_func void @_Z7vs_mainv(ptr %[[#alloca]]) +// CHECK: %[[#a:]] = load %struct.S, ptr %[[#alloca]], align 4 +// CHECK: %[[#b:]] = extractvalue %struct.S %[[#a]], 0 +// CHECK-DX: call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#b]]) +// CHECK-VK: store float %3, ptr addrspace(8) @A4, align 4 +// CHECK: ret void + +// CHECK-VK: ![[#ATTR0]] = !{![[#ATTR1:]]} +// CHECK-VK: ![[#ATTR1]] = !{i32 30, i32 0} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index ab4153a64f028..747eb17446c87 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -102,6 +102,7 @@ // CHECK-NEXT: MIGServerRoutine (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_block) // CHECK-NEXT: MSConstexpr (SubjectMatchRule_function) // CHECK-NEXT: MSStruct (SubjectMatchRule_record) +// CHECK-NEXT: MallocSpan (SubjectMatchRule_function) // CHECK-NEXT: MaybeUndef (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: MicroMips (SubjectMatchRule_function) // CHECK-NEXT: MinSize (SubjectMatchRule_function, SubjectMatchRule_objc_method) diff --git a/clang/test/Sema/attr-malloc_span.c b/clang/test/Sema/attr-malloc_span.c new file mode 100644 index 0000000000000..9238b601c5f0d --- /dev/null +++ b/clang/test/Sema/attr-malloc_span.c @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +typedef __SIZE_TYPE__ size_t; + +typedef struct { + void *ptr; + size_t n; +} span; +span returns_span (void) __attribute((malloc_span)); // no-warning + +typedef struct { + size_t n; + void *ptr; +} span2; +span2 returns_span2 (void) __attribute((malloc_span)); // no-warning + +typedef struct { + void *ptr; + void *ptr2; +} span3; +span3 returns_span3 (void) __attribute((malloc_span)); // no-warning + +typedef struct { + void *ptr; + int n; +} span4; +span4 returns_span4 (void) __attribute((malloc_span)); // no-warning + +typedef struct incomplete_span incomplete_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned type is incomplete}} +incomplete_span returns_incomplete_span (void) __attribute((malloc_span)); + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned type is not a struct type}} +int *returns_int_ptr (void) __attribute((malloc_span)); + +typedef struct { + void *ptr; + size_t n; + size_t n2; +} too_long_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct has 3 fields, expected 2}} +too_long_span returns_too_long_span (void) __attribute((malloc_span)); + +// Function pointers are not allowed. +typedef struct { + int (*func_ptr)(void); + size_t n; +} func_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct fields are not a supported combination}} +func_span returns_func_span (void) __attribute((malloc_span)); + +// Integer should not be an enum. +enum some_enum { some_value, other_value }; +typedef struct { + void *ptr; + enum some_enum field; +} enum_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{2nd field is expected to be an integer}} +enum_span returns_enum_span (void) __attribute((malloc_span)); + +// Bit integers are also not supported. +typedef struct { + void *ptr; + _BitInt(16) n; +} bit_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{2nd field is expected to be an integer}} +bit_span returns_bit_span (void) __attribute((malloc_span)); + +// Integer must be at least as big as int. +typedef struct { + void *ptr; + short n; +} short_span; +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{2nd field of span-like type is not a wide enough integer (minimum width: 32)}} +short_span returns_short_span (void) __attribute((malloc_span)); diff --git a/clang/test/SemaCXX/attr-malloc_span.cpp b/clang/test/SemaCXX/attr-malloc_span.cpp new file mode 100644 index 0000000000000..86622f6c154ea --- /dev/null +++ b/clang/test/SemaCXX/attr-malloc_span.cpp @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +struct span_with_static { + void *ptr; + int n; + static int static_field; +}; + +span_with_static returns_span_with_static (void) __attribute((malloc_span)); // no-warning + +class SomeClass { +public: + int Data; +}; + +// Returning pointers to data members is not allowed. +struct DataMemberSpan { + int SomeClass::* member_ptr; + int n; +}; + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct fields are not a supported combination}} +DataMemberSpan returns_data_member_span(void) __attribute((malloc_span)) { + return DataMemberSpan{}; +} + +// Returning pointers to member functions is not allowed. +struct MemberFuncSpan { + void (SomeClass::*member_func_ptr)(); + int n; +}; + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct fields are not a supported combination}} +MemberFuncSpan returns_member_func_span(void) __attribute((malloc_span)) { + return MemberFuncSpan{}; +} + +template +struct Pair { + FirstType first; + SecondType second; +}; + +Pair returns_templated_span1(void) __attribute((malloc_span)) { // no-warning + return Pair{}; +} + +Pair returns_templated_span2(void) __attribute((malloc_span)) { // no-warning + return Pair{}; +} + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct fields are not a supported combination for a span-like type}} +Pair returns_templated_span3(void) __attribute((malloc_span)) { + return Pair{}; +} + +// Verify that semantic checks are done on dependent types. + +struct GoodSpan { + void *ptr; + int n; +}; + +struct BadSpan { + int n; +}; + +template +// expected-warning@+2 {{'malloc_span' attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct has 1 fields, expected 2}} +T produce_span() __attribute((malloc_span)) { + return T{}; +} + +void TestGoodBadSpan() { + produce_span(); // no-warnings + // expected-note@+1 {{in instantiation of function template specialization 'produce_span' requested here}} + produce_span(); +} + +// Ensure that trailing return types are also supported. +__attribute__((malloc_span)) auto trailing_return_type(int size) -> GoodSpan { // no-warning + return GoodSpan{}; +} + +template +// expected-warning@+2 {{'malloc_span' attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct has 1 fields, expected 2}} +__attribute__((malloc_span)) auto templated_trailing_return_type() -> T { + return T{}; +} + +void TestGoodBadTrailingReturnType() { + templated_trailing_return_type(); // no-warnings + // expected-note@+1 {{in instantiation of function template specialization 'templated_trailing_return_type' requested here}} + templated_trailing_return_type(); +} + +__attribute((malloc_span)) auto trailing_return_temmplate_good(void) -> Pair { // no-warning + return Pair{}; +} + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned struct fields are not a supported combination for a span-like type}} +__attribute((malloc_span)) auto trailing_return_temmplate_bad(void) -> Pair { + return Pair{}; +} + +struct Base { + void *other_p; +}; + +struct ChildSpan : Base { + void *p; + int n; +}; + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned type inherits from a base class}} +__attribute((malloc_span)) ChildSpan return_child_span(void); + +class VirtualBaseSpan : public virtual Base { + void *p; + int n; +}; + +// expected-warning@+2 {{attribute only applies to functions that return span-like structures}} +// expected-note@+1 {{returned type inherits from a base class}} +__attribute((malloc_span)) VirtualBaseSpan return_virtual_base_span(void); diff --git a/clang/test/SemaCXX/wmissing-noreturn-suggestion.cpp b/clang/test/SemaCXX/wmissing-noreturn-suggestion.cpp index 06db972118d1c..2520c97cd0aee 100644 --- a/clang/test/SemaCXX/wmissing-noreturn-suggestion.cpp +++ b/clang/test/SemaCXX/wmissing-noreturn-suggestion.cpp @@ -53,3 +53,26 @@ int gnu_throws() { int cxx11_throws() { throw 0; } + +namespace GH167247 { +struct S1 { + virtual ~S1() = default; + virtual void m() { + throw std::runtime_error("This method always throws"); + } +}; + +struct S2 { + virtual ~S2() = default; + + virtual void m() final { // expected-warning {{function 'm' could be declared with attribute 'noreturn'}} + throw std::runtime_error("This method always throws"); + } +}; + +struct S3 final : S1 { + void m() { // expected-warning {{function 'm' could be declared with attribute 'noreturn'}} + throw std::runtime_error("This method always throws"); + } +}; +} diff --git a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl index 2f488a8d7c357..e5e399cf490ba 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl @@ -37,7 +37,7 @@ __attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) unsigned f8(); [numthreads(4,1,1)] -int main() { +void main() { // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} unsigned A = f1(); // #f1_call @@ -63,6 +63,4 @@ int main() { unsigned G = f7(); // #f7_call unsigned H = f8(); - - return 0; } diff --git a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl index 07da116d403ce..eddba54d5ca9e 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl @@ -37,7 +37,7 @@ __attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) unsigned f8(); // #f8 [numthreads(4,1,1)] -int main() { +void main() { // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} unsigned A = f1(); // #f1_call @@ -63,6 +63,4 @@ int main() { // expected-error@#f8_call {{'f8' is only available in mesh environment on Shader Model 6.0 or newer}} // expected-note@#f8 {{'f8' has been marked as being introduced in Shader Model 6.0 in mesh environment here, but the deployment target is Shader Model 5.0 mesh environment}} unsigned H = f8(); // #f8_call - - return 0; } diff --git a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl index 7cd13e653ed5a..83c49738f8810 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl @@ -36,7 +36,7 @@ __attribute__((availability(shadermodel, introduced = 5.0, environment = compute __attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) unsigned f8(); -int main() { +int main() : A { // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} unsigned A = f1(); // #f1_call diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl index b60fba62bdb00..1424fe63242ae 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl @@ -107,7 +107,7 @@ class MyClass }; [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f); @@ -115,5 +115,4 @@ float main() { float c = C.makeF(); float d = test((float)1.0); float e = test((half)1.0); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl index 35b7c384f26cd..0c997d28ecdfc 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl @@ -162,12 +162,12 @@ namespace A { // Shader entry point without body [shader("compute")] [numthreads(4,1,1)] -float main(); +void main(); // Shader entry point with body [shader("compute")] [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f); @@ -176,5 +176,4 @@ float main() { float d = test((float)1.0); float e = test((half)1.0); exportedFunctionUsed(1.0f); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl index 4068798383930..2474a8ae2e02a 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl @@ -107,7 +107,7 @@ class MyClass }; [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f); @@ -115,5 +115,4 @@ float main() { float c = C.makeF(); float d = test((float)1.0); float e = test((half)1.0); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl index a23e91a546b16..e598bc99a4e6a 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl @@ -144,12 +144,12 @@ export void exportedFunctionUsed(float f) { // Shader entry point without body [shader("compute")] [numthreads(4,1,1)] -float main(); +void main(); // Shader entry point with body [shader("compute")] [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f); @@ -158,5 +158,4 @@ float main() { float d = test((float)1.0); float e = test((half)1.0); exportedFunctionUsed(1.0f); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl index c5d14c024d540..9cb9a32e11c73 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl @@ -117,7 +117,7 @@ class MyClass }; [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f); @@ -125,5 +125,4 @@ float main() { float c = C.makeF(); float d = test((float)1.0); float e = test((half)1.0); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl index 0fffbc96dac19..3a7efc3af80a0 100644 --- a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl +++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl @@ -180,7 +180,7 @@ namespace A { [shader("compute")] [numthreads(4,1,1)] -float main() { +void main() { float f = 3; MyClass C = { 1.0f }; float a = alive(f);float b = aliveTemp(f); // #aliveTemp_inst @@ -188,5 +188,4 @@ float main() { float d = test((float)1.0); float e = test((half)1.0); exportedFunctionUsed(1.0f); - return a * b * c; } diff --git a/clang/test/SemaHLSL/Semantics/missing-vs.hlsl b/clang/test/SemaHLSL/Semantics/missing-vs.hlsl new file mode 100644 index 0000000000000..41be9c0ab730c --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/missing-vs.hlsl @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify -verify-ignore-unexpected=note +// RUN: %clang_cc1 -triple spirv-unknown-vulkan-vertex -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify -verify-ignore-unexpected=note + +float main(unsigned GI : A) { + // expected-error@-1 {{semantic annotations must be present for all parameters of an entry function or patch constant function}} +} diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl index 7adf2a51f01c8..2d02384821d90 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -1,9 +1,13 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s -// FIXME(Keenuts): add mandatory output semantic once those are implemented. -float4 main(float4 a : SV_Position2) { +// FIXME(Keenuts): change output semantic to something valid for pixels shaders +float4 main(float4 a : SV_Position2) : A { // 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: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 + +// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 + return a; } diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl index 3186aadf19946..213a53e30155b 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.hlsl @@ -5,14 +5,17 @@ struct S { // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f0 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 0 float4 f1 : SV_Position3; -// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 f1 'float4':'vector' +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced f1 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 3 }; // FIXME(Keenuts): add mandatory output semantic once those are implemented. -float4 main(S s) { +float4 main(S s) : B { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (S)' -// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 s 'S' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:15 used s 'S' // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 3 + +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "B" 0 + return s.f1; } diff --git a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl index f12ac4df0c450..d10c817d53af2 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.struct.reuse.hlsl @@ -2,13 +2,13 @@ struct A { float4 x : A; -// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 x 'float4':'vector' +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:10 referenced x 'float4':'vector' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 }; struct Top { A f0 : B; -// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f0 'A' +// CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 referenced f0 'A' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "B" 0 A f1 : C; // CHECK: FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:5 f1 'A' @@ -17,10 +17,13 @@ struct Top { // FIXME(Keenuts): add mandatory output semantic once those are implemented. -float4 main(Top s : D) { +float4 main(Top s : D) : F4 { // CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (Top)' -// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 s 'Top' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 used s 'Top' // CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "D" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 0 // CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "D" 1 + +// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "F" 4 + return s.f0.x; } diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl index 19f781fa3757c..9d0ff285ce055 100644 --- a/clang/test/SemaHLSL/Semantics/position.vs.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl @@ -1,6 +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) { +float4 main(float4 a : SV_Position) : A { return a; } diff --git a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl index a5645d1400da7..e7cb59bea8cf5 100644 --- a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl +++ b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl @@ -3,8 +3,8 @@ [shader("compute")] [numthreads(8,8,1)] -unsigned foo() { +void foo() { // expected-error@#site {{'WaveActiveCountBits' is only available on Shader Model 6.0 or newer}} // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{'WaveActiveCountBits' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - return hlsl::WaveActiveCountBits(1); // #site + unsigned tmp = hlsl::WaveActiveCountBits(1); // #site } diff --git a/clang/test/SemaHLSL/num_threads.hlsl b/clang/test/SemaHLSL/num_threads.hlsl index 96200312bbf69..073f9bcfbe2ae 100644 --- a/clang/test/SemaHLSL/num_threads.hlsl +++ b/clang/test/SemaHLSL/num_threads.hlsl @@ -117,7 +117,7 @@ int largeZ(); #else // Vertex and Pixel only beyond here // expected-error-re@+1 {{attribute 'numthreads' is unsupported in '{{[A-Za-z]+}}' shaders, requires one of the following: compute, amplification, mesh}} [numthreads(1,1,1)] -int main() { +int main() : A { return 1; } diff --git a/clang/test/SemaHLSL/shader_type_attr.hlsl b/clang/test/SemaHLSL/shader_type_attr.hlsl index 52d3b1c9d012f..5f30a520b7255 100644 --- a/clang/test/SemaHLSL/shader_type_attr.hlsl +++ b/clang/test/SemaHLSL/shader_type_attr.hlsl @@ -31,18 +31,17 @@ static void oops() {} [shader("pixel")] // expected-note@+1 {{conflicting attribute is here}} [shader("vertex")] -int doubledUp() { +int doubledUp() : A { return 1; } // expected-note@+1 {{conflicting attribute is here}} [shader("vertex")] -int forwardDecl(); +void forwardDecl(); // expected-error@+1 {{'shader' attribute parameters do not match the previous declaration}} [shader("compute")][numthreads(8,1,1)] -int forwardDecl() { - return 1; +void forwardDecl() { } // expected-error@+1 {{'shader' attribute takes one argument}} @@ -57,22 +56,20 @@ int forwardDecl() { [shader("library")] #endif // END of FAIL -// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 8 1 1 [shader("compute")][numthreads(8,1,1)] -int entry() { - return 1; +void entry() { } // Because these two attributes match, they should both appear in the AST [shader("compute")][numthreads(8,1,1)] -// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 8 1 1 -int secondFn(); +void secondFn(); [shader("compute")][numthreads(8,1,1)] -// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute +// CHECK:HLSLShaderAttr 0x{{[0-9a-fA-F]+}} Compute // CHECK:HLSLNumThreadsAttr 0x{{[0-9a-fA-F]+}} 8 1 1 -int secondFn() { - return 1; +void secondFn() { } diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 7d07ec765c005..232bb2574a778 100755 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -1,6 +1,7 @@ # Build for the AddressSanitizer runtime support library. set(ASAN_SOURCES + asan_aix.cpp asan_allocator.cpp asan_activation.cpp asan_debugging.cpp diff --git a/compiler-rt/lib/asan/asan_aix.cpp b/compiler-rt/lib/asan/asan_aix.cpp new file mode 100644 index 0000000000000..58a79ea5e7479 --- /dev/null +++ b/compiler-rt/lib/asan/asan_aix.cpp @@ -0,0 +1,48 @@ +//===-- asan_aix.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// AIX-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_AIX +# include "asan_mapping.h" +# include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __asan { + +void TryReExecWithoutASLR() { + // Allowed to fail and do nothing. +} + +void AsanCheckIncompatibleRT() {} + +void AsanCheckDynamicRTPrereqs() {} + +void InitializePlatformExceptionHandlers() {} + +void* AsanDoesNotSupportStaticLinkage() { return 0; } + +void InitializePlatformInterceptors() {} +void AsanApplyToGlobals(globals_op_fptr op, const void* needle) {} + +uptr FindDynamicShadowStart() { + UNREACHABLE("AIX does not use dynamic shadow offset!"); + return 0; +} + +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + +} // namespace __asan + +#endif // SANITIZER_AIX diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp index fb66c871ea8a5..598a55d89bdd2 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -180,7 +180,7 @@ static void AfterFork(bool fork_child) { void InstallAtForkHandler() { # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \ - (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU + (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU || SANITIZER_AIX // While other Linux targets use clone in internal_fork which doesn't // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a // hang. diff --git a/compiler-rt/lib/asan/scripts/asan_symbolize.py b/compiler-rt/lib/asan/scripts/asan_symbolize.py index 091e9bcc9a796..dffe4dd6fc032 100755 --- a/compiler-rt/lib/asan/scripts/asan_symbolize.py +++ b/compiler-rt/lib/asan/scripts/asan_symbolize.py @@ -60,6 +60,7 @@ def is_valid_arch(s): "armv7k", "arm64", "arm64e", + "powerpc", "powerpc64", "powerpc64le", "s390x", @@ -450,7 +451,14 @@ def __init__(self, plugin_proxy=None, dsym_hint_producer=None): # E.g. in Chrome several binaries may share a single .dSYM. self.dsym_hint_producer = dsym_hint_producer self.system = os.uname()[0] - if self.system not in ["Linux", "Darwin", "FreeBSD", "NetBSD", "SunOS"]: + if self.system not in [ + "Linux", + "Darwin", + "FreeBSD", + "NetBSD", + "SunOS", + "AIX", + ]: raise Exception("Unknown system") self.llvm_symbolizers = {} self.last_llvm_symbolizer = None diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 43abc79624773..9182bf2abc655 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -446,7 +446,8 @@ if(COMPILER_RT_ARM_OPTIMIZED_FP AND BUILTIN_SUPPORTED_ARCH MATCHES "arm") if(implicit_it_flag) set(assembly_files arm/mulsf3.S - arm/divsf3.S) + arm/divsf3.S + ) set_source_files_properties(${assembly_files} PROPERTIES COMPILE_OPTIONS ${implicit_it_flag}) set(arm_or_thumb2_optimized_fp_SOURCES diff --git a/compiler-rt/test/asan/TestCases/Darwin/Inputs/check-syslog.sh b/compiler-rt/test/asan/TestCases/Darwin/Inputs/check-syslog.sh new file mode 100755 index 0000000000000..8939ca7ca1564 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Darwin/Inputs/check-syslog.sh @@ -0,0 +1,6 @@ +#!/bin/sh +for I in {1..3}; do \ + log show --debug --last $((SECONDS + 30))s --predicate "processID == $1" --style syslog > $2; \ + if grep -q "use-after-poison" $2; then break; fi; \ + sleep 5; \ +done diff --git a/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp index 5a0353bfb1b31..40a168bc15290 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp @@ -1,8 +1,8 @@ // UNSUPPORTED: ios // REQUIRES: darwin_log_cmd // RUN: %clangxx_asan -fsanitize-recover=address %s -o %t -// RUN: { %env_asan_opts=halt_on_error=0,log_to_syslog=1 %run %t > %t.process_output.txt 2>&1 & } \ -// RUN: ; export TEST_PID=$! ; wait ${TEST_PID} +// RUN: bash -c '{ %env_asan_opts=halt_on_error=0,log_to_syslog=1 %run %t > %t.process_output.txt 2>&1 & } \ +// RUN: ; export TEST_PID=$! ; wait ${TEST_PID}; echo -n ${TEST_PID} > %t.test_pid' // Check process output. // RUN: FileCheck %s --check-prefixes CHECK,CHECK-PROC -input-file=%t.process_output.txt @@ -10,11 +10,7 @@ // Check syslog output. We filter recent system logs based on PID to avoid // getting the logs of previous test runs. Make some reattempts in case there // is a delay. -// RUN: for I in {1..3}; do \ -// RUN: log show --debug --last $((SECONDS + 30))s --predicate "processID == ${TEST_PID}" --style syslog > %t.process_syslog_output.txt; \ -// RUN: if grep -q "use-after-poison" %t.process_syslog_output.txt; then break; fi; \ -// RUN: sleep 5; \ -// RUN: done +// RUN: %S/Inputs/check-syslog.sh %{readfile:%t.test_pid} %t.process_syslog_output.txt // RUN: FileCheck %s -input-file=%t.process_syslog_output.txt #include #include diff --git a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp index 145e162a21c0e..89ee7a178525a 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp @@ -14,23 +14,12 @@ // RUN: %run %t/a.out 2>&1 \ // RUN: | FileCheck %s -// RUN: MACOS_MAJOR=$(sw_vers -productVersion | cut -d'.' -f1) -// RUN: MACOS_MINOR=$(sw_vers -productVersion | cut -d'.' -f2) - -// RUN: IS_MACOS_10_11_OR_HIGHER=$([ $MACOS_MAJOR -eq 10 ] && [ $MACOS_MINOR -lt 11 ]; echo $?) - // On OS X 10.10 and lower, if the dylib is not DYLD-inserted, ASan will re-exec. -// RUN: if [ $IS_MACOS_10_11_OR_HIGHER == 0 ]; then \ -// RUN: %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-NOINSERT %s; \ -// RUN: fi +// RUN: %if mac-os-10-11-or-higher %{ %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 | FileCheck --check-prefix=CHECK-NOINSERT %s %} // On OS X 10.11 and higher, we don't need to DYLD-insert anymore, and the interceptors // still installed correctly. Let's just check that things work and we don't try to re-exec. -// RUN: if [ $IS_MACOS_10_11_OR_HIGHER == 1 ]; then \ -// RUN: %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 \ -// RUN: | FileCheck %s; \ -// RUN: fi +// RUN: %if mac-os-10-10-or-lower %{ %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 | FileCheck %s %} #include diff --git a/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp b/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp index 59dca32672901..ddf93881555f9 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp @@ -9,13 +9,17 @@ // RUN: %clangxx_asan -dead_strip -O2 %s -o %t.exe // // note: we can not use -D on Darwin. -// RUN: nm -g `%clang_asan %s -fsanitize=address -### 2>&1 | grep "libclang_rt.asan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ -// RUN: | grep " [TU] " \ -// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ -// RUN: | grep -v "__sanitizer_syscall" \ -// RUN: | grep -v "__sanitizer_weak_hook" \ -// RUN: | grep -v "__sanitizer_mz" \ -// RUN: | grep -v "__sancov_lowest_stack" \ +// RUN: %clang_asan %s -fsanitize=address -### 2>&1 \ +// RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ +// RUN: | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/' \ +// RUN: | tr -d '\n' > %t.compiler_runtime_path +// RUN: nm -g %{readfile:%t.compiler_runtime_path} \ +// RUN: | grep " [TU] " \ +// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ +// RUN: | grep -v "__sanitizer_syscall" \ +// RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | grep -v "__sanitizer_mz" \ +// RUN: | grep -v "__sancov_lowest_stack" \ // RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ // RUN: > %t.exports // diff --git a/compiler-rt/test/asan/TestCases/Darwin/lit.local.cfg.py b/compiler-rt/test/asan/TestCases/Darwin/lit.local.cfg.py index af82d30cf4de9..fc99cd78808e3 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/lit.local.cfg.py +++ b/compiler-rt/test/asan/TestCases/Darwin/lit.local.cfg.py @@ -1,3 +1,6 @@ +import subprocess + + def getRoot(config): if not config.parent: return config @@ -8,3 +11,26 @@ def getRoot(config): if root.target_os not in ["Darwin"]: config.unsupported = True + + +def get_product_version(): + try: + version_process = subprocess.run( + ["sw_vers", "-productVersion"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + version_string = version_process.stdout.decode("utf-8").split("\n")[0] + version_split = version_string.split(".") + return (int(version_split[0]), int(version_split[1])) + except: + return (0, 0) + + +macos_version_major, macos_version_minor = get_product_version() +if config.apple_platform == "osx": + if macos_version_major > 10 and macos_version_minor > 11: + config.available_features.add("mac-os-10-11-or-higher") + else: + config.available_features.add("mac-os-10-10-or-lower") diff --git a/compiler-rt/test/fuzzer/big-file-copy.test b/compiler-rt/test/fuzzer/big-file-copy.test index 9565ed4e0bca2..b92379460ac3b 100644 --- a/compiler-rt/test/fuzzer/big-file-copy.test +++ b/compiler-rt/test/fuzzer/big-file-copy.test @@ -1,6 +1,5 @@ REQUIRES: darwin UNSUPPORTED: ios RUN: %cpp_compiler %S/BigFileCopy.cpp -o %t -RUN: %run %t -runs=1 -rss_limit_mb=4096 2>big-file-out.txt; result=$? -RUN: %run rm -f big-file.txt big-file-out.txt -RUN: (exit $result) +RUN: bash -c '%run %t -runs=1 -rss_limit_mb=4096 2>big-file-out.txt; result=$? \ +RUN: %run rm -f big-file.txt big-file-out.txt && exit $result' diff --git a/compiler-rt/test/fuzzer/merge-posix.test b/compiler-rt/test/fuzzer/merge-posix.test index 5e342142216f8..6e37651e6fd29 100644 --- a/compiler-rt/test/fuzzer/merge-posix.test +++ b/compiler-rt/test/fuzzer/merge-posix.test @@ -14,10 +14,10 @@ RUN: echo ....U. > %tmp/T2/2 RUN: echo ...Z.. > %tmp/T2/3 RUN: echo ...Z.. > %tmp/T2/4 RUN: echo ....E. > %tmp/T2/5 -RUN: %python -c "print('.....R' + 'X' * 1024, end='')" > %tmp/T2/6 +RUN: %python -c "print('.....R' + 'X' * 4096, end='')" > %tmp/T2/6 # Check that we can report an error if file size exceeded -RUN: (ulimit -f 1; not %run %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ) +RUN: (ulimit -f 4; not %run %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ) SIGXFSZ: ERROR: libFuzzer: file size exceeded # Check that we honor TMPDIR diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp new file mode 100644 index 0000000000000..344005ee98141 --- /dev/null +++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/Inputs/simplified_template_names.cpp @@ -0,0 +1,272 @@ +#include +#include +template struct t1 {}; +template struct t2; +struct udt {}; +namespace ns { +struct udt {}; +namespace inner { +template struct ttp {}; +struct udt {}; +} // namespace inner +template