diff options
Diffstat (limited to 'clang')
117 files changed, 3511 insertions, 1645 deletions
diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 674eb2a..3d4d71a 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -340,7 +340,7 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv7em-none-eabi;armv8m.main-n foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" -D_LIBCPP_PRINT=1") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dfputs(string, stream)=puts(string)\" -D_LIBCPP_PRINT=1") if(NOT ${target} STREQUAL "aarch64-none-elf") set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mthumb") endif() @@ -405,7 +405,7 @@ foreach(target riscv32-unknown-elf) foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" -D_LIBCPP_PRINT=1" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dfputs(string, stream)=puts(string)\" -D_LIBCPP_PRINT=1" CACHE STRING "") endforeach() foreach(type SHARED;MODULE;EXE) set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake index ee1d681..a3f86f6 100644 --- a/clang/cmake/caches/Fuchsia.cmake +++ b/clang/cmake/caches/Fuchsia.cmake @@ -76,6 +76,9 @@ foreach(variable ${_FUCHSIA_BOOTSTRAP_PASSTHROUGH}) get_property(value CACHE ${variable} PROPERTY VALUE) get_property(type CACHE ${variable} PROPERTY TYPE) set(BOOTSTRAP_${variable} "${value}" CACHE ${type} "") + if(FUCHSIA_ENABLE_PGO) + set(BOOTSTRAP_BOOTSTRAP_${variable} "${value}" CACHE ${type} "") + endif() endif() endforeach() diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index d39ee49..7f970f6 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6400,6 +6400,14 @@ the configuration (without a prefix: ``Auto``). IF (...) vs. IF(...) <conditional-body> <conditional-body> + * ``bool AfterNot`` If ``true``, put a space between alternative operator ``not`` and the + opening parenthesis. + + .. code-block:: c++ + + true: false: + return not (a || b); vs. return not(a || b); + * ``bool AfterOverloadedOperator`` If ``true``, put a space between operator overloading and opening parentheses. diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index 406e1c8..b4a671e 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -545,37 +545,22 @@ The following restrictions imposed on user code apply to both modes: 1. Pointers to function, and all associated features, such as e.g. dynamic polymorphism, cannot be used (directly or transitively) by the user provided callable passed to an algorithm invocation; -2. Global / namespace scope / ``static`` / ``thread`` storage duration variables - cannot be used (directly or transitively) in name by the user provided - callable; - - - When executing in **HMM Mode** they can be used in address e.g.: - - .. code-block:: C++ - - namespace { int foo = 42; } - - bool never(const std::vector<int>& v) { - return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v), [](auto&& x) { - return x == foo; - }); - } - - bool only_in_hmm_mode(const std::vector<int>& v) { - return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v), - [p = &foo](auto&& x) { return x == *p; }); - } - -3. Only algorithms that are invoked with the ``parallel_unsequenced_policy`` are +2. ``static`` (except for program-wide unique ones) / ``thread`` storage + duration variables cannot be used (directly or transitively) in name by the + user provided callable; +3. User code must be compiled in ``-fgpu-rdc`` mode in order for global / + namespace scope variables / program-wide unique ``static`` storage duration + variables to be usable in name by the user provided callable; +4. Only algorithms that are invoked with the ``parallel_unsequenced_policy`` are candidates for offload; -4. Only algorithms that are invoked with iterator arguments that model +5. Only algorithms that are invoked with iterator arguments that model `random_access_iterator <https://en.cppreference.com/w/cpp/iterator/random_access_iterator>`_ are candidates for offload; -5. `Exceptions <https://en.cppreference.com/w/cpp/language/exceptions>`_ cannot +6. `Exceptions <https://en.cppreference.com/w/cpp/language/exceptions>`_ cannot be used by the user provided callable; -6. Dynamic memory allocation (e.g. ``operator new``) cannot be used by the user +7. Dynamic memory allocation (e.g. ``operator new``) cannot be used by the user provided callable; -7. Selective offload is not possible i.e. it is not possible to indicate that +8. Selective offload is not possible i.e. it is not possible to indicate that only some algorithms invoked with the ``parallel_unsequenced_policy`` are to be executed on the accelerator. @@ -585,15 +570,6 @@ additional restrictions: 1. All code that is expected to interoperate has to be recompiled with the ``--hipstdpar-interpose-alloc`` flag i.e. it is not safe to compose libraries that have been independently compiled; -2. automatic storage duration (i.e. stack allocated) variables cannot be used - (directly or transitively) by the user provided callable e.g. - - .. code-block:: c++ - - bool never(const std::vector<int>& v, int n) { - return std::any_of(std::execution::par_unseq, std::cbegin(v), std::cend(v), - [p = &n](auto&& x) { return x == *p; }); - } Current Support =============== @@ -626,17 +602,12 @@ Linux operating system. Support is synthesised in the following table: The minimum Linux kernel version for running in HMM mode is 6.4. -The forwarding header can be obtained from -`its GitHub repository <https://github.com/ROCm/roc-stdpar>`_. -It will be packaged with a future `ROCm <https://rocm.docs.amd.com/en/latest/>`_ -release. Because accelerated algorithms are provided via -`rocThrust <https://rocm.docs.amd.com/projects/rocThrust/en/latest/>`_, a -transitive dependency on -`rocPrim <https://rocm.docs.amd.com/projects/rocPRIM/en/latest/>`_ exists. Both -can be obtained either by installing their associated components of the -`ROCm <https://rocm.docs.amd.com/en/latest/>`_ stack, or from their respective -repositories. The list algorithms that can be offloaded is available -`here <https://github.com/ROCm/roc-stdpar#algorithm-support-status>`_. +The forwarding header is packaged by +`ROCm <https://rocm.docs.amd.com/en/latest/>`_, and is obtainable by installing +the `hipstdpar` packege. The list algorithms that can be offloaded is available +`here <https://github.com/ROCm/roc-stdpar#algorithm-support-status>`_. More +details are available via the dedicated blog +`<https://rocm.blogs.amd.com/software-tools-optimization/hipstdpar/README.html>`_. HIP Specific Elements --------------------- @@ -690,9 +661,8 @@ HIP Specific Elements Open Questions / Future Developments ==================================== -1. The restriction on the use of global / namespace scope / ``static`` / - ``thread`` storage duration variables in offloaded algorithms will be lifted - in the future, when running in **HMM Mode**; +1. The restriction on the use of ``static`` / ``thread`` storage duration + variables in offloaded algorithms might be lifted; 2. The restriction on the use of dynamic memory allocation in offloaded algorithms will be lifted in the future. 3. The restriction on the use of pointers to function, and associated features diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index 986aaab..fc44f4c 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -443,7 +443,7 @@ implementation. +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | Traits for default device envirable | :none:`unclaimed` | :none:`unclaimed` | | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ -| Optionally omit array length expression | :none:`unclaimed` | :none:`unclaimed` | | +| Optionally omit array length expression | :good:`done` | :none:`unclaimed` | https://github.com/llvm/llvm-project/pull/148048 | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | Canonical loop sequences | :none:`unclaimed` | :none:`unclaimed` | | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ @@ -467,6 +467,9 @@ implementation. +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | Non-const do_not_sync for nowait/nogroup | :none:`unclaimed` | :none:`unclaimed` | | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ +| need_device_addr modifier for adjust_args clause | :part:`partial` | :none:`unclaimed` | Parsing/Sema: https://github.com/llvm/llvm-project/pull/143442 | +| | | | https://github.com/llvm/llvm-project/pull/149586 | ++-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ OpenMP Extensions ================= diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4f6e9a4..ec51ffd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -34,49 +34,11 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the Potentially Breaking Changes ============================ -- The Objective-C ARC migrator (ARCMigrate) has been removed. -- Fix missing diagnostics for uses of declarations when performing typename access, - such as when performing member access on a ``[[deprecated]]`` type alias. - (#GH58547) -- For ARM targets when compiling assembly files, the features included in the selected CPU - or Architecture's FPU are included. If you wish not to use a specific feature, - the relevant ``+no`` option will need to be amended to the command line option. -- When compiling with branch target enforcement, ``asm goto`` - statements will no longer guarantee to place a ``bti`` or - ``endbr64`` instruction at the labels named as possible branch - destinations, so it is not safe to use a register-controlled branch - instruction to branch to one. (In line with gcc.) -- Added a sugar type `PredefinedSugarType` to improve diagnostic messages. (#GH143653) - C/C++ Language Potentially Breaking Changes ------------------------------------------- -- New LLVM optimizations have been implemented that optimize pointer arithmetic on - null pointers more aggressively. As part of this, clang has implemented a special - case for old-style offsetof idioms like ``((int)(&(((struct S *)0)->field)))``, to - ensure they are not caught by these optimizations. It is also possible to use - ``-fwrapv-pointer`` or ``-fno-delete-null-pointer-checks`` to make pointer arithmetic - on null pointers well-defined. (#GH130734, #GH130742, #GH130952) - C++ Specific Potentially Breaking Changes ----------------------------------------- - -- The type trait builtin ``__is_referenceable`` has been removed, since it has - very few users and all the type traits that could benefit from it in the - standard library already have their own bespoke builtins. -- A workaround for libstdc++4.7 has been removed. Note that 4.8.3 remains the oldest - supported libstdc++ version. -- Added ``!nonnull/!align`` metadata to load of references for better codegen. -- Checking for integer to enum conversions in constant expressions is more - strict; in particular, ``const E x = (E)-1;`` is not treated as a constant - if it's out of range. The Boost numeric_conversion library is impacted by - this; it was fixed in Boost 1.81. (#GH143034) - -- Fully implemented `CWG400 Using-declarations and the ` - `"struct hack" <https://wg21.link/CWG400>`_. Invalid member using-declaration - whose nested-name-specifier doesn't refer to a base class such as - ``using CurrentClass::Foo;`` is now rejected in C++98 mode. - - For C++20 modules, the Reduced BMI mode will be the default option. This may introduce regressions if your build system supports two-phase compilation model but haven't support reduced BMI or it is a compiler bug or a bug in users code. @@ -84,26 +46,14 @@ C++ Specific Potentially Breaking Changes ABI Changes in This Version --------------------------- -- Return larger CXX records in memory instead of using AVX registers. Code compiled with older clang will be incompatible with newer version of the clang unless -fclang-abi-compat=20 is provided. (#GH120670) - AST Dumping Potentially Breaking Changes ---------------------------------------- -- Added support for dumping template arguments of structural value kinds. - Clang Frontend Potentially Breaking Changes ------------------------------------------- -- The ``-Wglobal-constructors`` flag now applies to ``[[gnu::constructor]]`` and - ``[[gnu::destructor]]`` attributes. - Clang Python Bindings Potentially Breaking Changes -------------------------------------------------- -- ``Cursor.from_location`` now returns ``None`` instead of a null cursor. - This eliminates the last known source of null cursors. -- Almost all ``Cursor`` methods now assert that they are called on non-null cursors. - Most of the time null cursors were mapped to ``None``, - so no widespread breakages are expected. What's New in Clang |release|? ============================== @@ -111,45 +61,14 @@ What's New in Clang |release|? C++ Language Changes -------------------- -- Added a :ref:`__builtin_structured_binding_size <builtin_structured_binding_size-doc>` (T) - builtin that returns the number of structured bindings that would be produced by destructuring ``T``. - -- Similarly to GCC, Clang now supports constant expressions in - the strings of a GNU ``asm`` statement. - - .. code-block:: c++ - - int foo() { - asm((std::string_view("nop")) ::: (std::string_view("memory"))); - } - -- Clang now implements the changes to overload resolution proposed by section 1 and 2 of - `P3606 <https://wg21.link/P3606R0>`_. If a non-template candidate exists in an overload set that is - a perfect match (all conversion sequences are identity conversions) template candidates are not instantiated. - Diagnostics that would have resulted from the instantiation of these template candidates are no longer - produced. This aligns Clang closer to the behavior of GCC, and fixes (#GH62096), (#GH74581), and (#GH74581). - C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ -- Implemented `P1061R10 Structured Bindings can introduce a Pack <https://wg21.link/P1061R10>`_. -- Implemented `P2786R13 Trivial Relocatability <https://wg21.link/P2786R13>`_. - - -- Implemented `P0963R3 Structured binding declaration as a condition <https://wg21.link/P0963R3>`_. - -- Implemented `P3618R0 Allow attaching main to the global module <https://wg21.link/P3618>`_. - C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -- Fixed a crash with a defaulted spaceship (``<=>``) operator when the class - contains a member declaration of vector type. Vector types cannot yet be - compared directly, so this causes the operator to be deleted. (#GH137452) -- Implement constant evaluation of lambdas that capture structured bindings. - (#GH145956) C++17 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -157,565 +76,37 @@ C++17 Feature Support Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- The flag `-frelaxed-template-template-args` - and its negation have been removed, having been deprecated since the previous - two releases. The improvements to template template parameter matching implemented - in the previous release, as described in P3310 and P3579, made this flag unnecessary. - -- Implemented `CWG2918 Consideration of constraints for address of overloaded ` - `function <https://cplusplus.github.io/CWG/issues/2918.html>`_ - -- Bumped the ``__cpp_constexpr`` feature-test macro to ``202002L`` in C++20 mode as indicated in - `P2493R0 <https://wg21.link/P2493R0>`_. - -- Implemented `CWG2517 Useless restriction on use of parameter in ` - `constraint-expression <https://cplusplus.github.io/CWG/issues/2517.html>`_. -- Implemented `CWG3005 Function parameters should never be name-independent <https://wg21.link/CWG3005>`_. - -- Implemented `CWG2496 ref-qualifiers and virtual overriding <https://wg21.link/CWG2496>`_. - C Language Changes ------------------ -- Clang now allows an ``inline`` specifier on a typedef declaration of a - function type in Microsoft compatibility mode. #GH124869 -- Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847). -- Clang now diagnoses ``const``-qualified object definitions without an - initializer. If the object is a variable or field which is zero-initialized, - it will be diagnosed under the new warning ``-Wdefault-const-init-var`` or - ``-Wdefault-const-init-field``, respectively. Similarly, if the variable or - field is not zero-initialized, it will be diagnosed under the new diagnostic - ``-Wdefault-const-init-var-unsafe`` or ``-Wdefault-const-init-field-unsafe``, - respectively. The unsafe diagnostic variants are grouped under a new - diagnostic ``-Wdefault-const-init-unsafe``, which itself is grouped under the - new diagnostic ``-Wdefault-const-init``. Finally, ``-Wdefault-const-init`` is - grouped under ``-Wc++-compat`` because these constructs are not compatible - with C++. #GH19297 -- Added ``-Wimplicit-void-ptr-cast``, grouped under ``-Wc++-compat``, which - diagnoses implicit conversion from ``void *`` to another pointer type as - being incompatible with C++. (#GH17792) -- Added ``-Wc++-keyword``, grouped under ``-Wc++-compat``, which diagnoses when - a C++ keyword is used as an identifier in C. (#GH21898) -- Added ``-Wc++-hidden-decl``, grouped under ``-Wc++-compat``, which diagnoses - use of tag types which are visible in C but not visible in C++ due to scoping - rules. e.g., - - .. code-block:: c - - struct S { - struct T { - int x; - } t; - }; - struct T t; // Invalid C++, valid C, now diagnosed -- Added ``-Wimplicit-int-enum-cast``, grouped under ``-Wc++-compat``, which - diagnoses implicit conversion from integer types to an enumeration type in C, - which is not compatible with C++. #GH37027 -- Split "implicit conversion from enum type to different enum type" diagnostic - from ``-Wenum-conversion`` into its own diagnostic group, - ``-Wimplicit-enum-enum-cast``, which is grouped under both - ``-Wenum-conversion`` and ``-Wimplicit-int-enum-cast``. This conversion is an - int-to-enum conversion because the enumeration on the right-hand side is - promoted to ``int`` before the assignment. -- Added ``-Wtentative-definition-compat``, grouped under ``-Wc++-compat``, - which diagnoses tentative definitions in C with multiple declarations as - being incompatible with C++. e.g., - - .. code-block:: c - - // File scope - int i; - int i; // Vaild C, invalid C++, now diagnosed -- Added ``-Wunterminated-string-initialization``, grouped under ``-Wextra``, - which diagnoses an initialization from a string literal where only the null - terminator cannot be stored. e.g., - - .. code-block:: c - - - char buf1[3] = "foo"; // -Wunterminated-string-initialization - char buf2[3] = "flarp"; // -Wexcess-initializers - char buf3[3] = "fo\0"; // This is fine, no warning. - - This diagnostic can be suppressed by adding the new ``nonstring`` attribute - to the field or variable being initialized. #GH137705 -- Added ``-Wc++-unterminated-string-initialization``, grouped under - ``-Wc++-compat``, which also diagnoses the same cases as - ``-Wunterminated-string-initialization``. However, this diagnostic is not - silenced by the ``nonstring`` attribute as these initializations are always - incompatible with C++. -- Added ``-Wjump-misses-init``, which is off by default and grouped under - ``-Wc++-compat``. It diagnoses when a jump (``goto`` to its label, ``switch`` - to its ``case``) will bypass the initialization of a local variable, which is - invalid in C++. -- Added the existing ``-Wduplicate-decl-specifier`` diagnostic, which is on by - default, to ``-Wc++-compat`` because duplicated declaration specifiers are - not valid in C++. -- The ``[[clang::assume()]]`` attribute is now correctly recognized in C. The - ``__attribute__((assume()))`` form has always been supported, so the fix is - specific to the attribute syntax used. -- The ``clang-cl`` driver now recognizes ``/std:clatest`` and sets the language - mode to C23. (#GH147233) - C2y Feature Support ^^^^^^^^^^^^^^^^^^^ -- Implement `WG14 N3409 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3409.pdf>`_ - which removes UB around use of ``void`` expressions. In practice, this means - that ``_Generic`` selection associations may now have ``void`` type, but it - also removes UB with code like ``(void)(void)1;``. -- Implemented `WG14 N3411 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf>`_ - which allows a source file to not end with a newline character. Note, - ``-pedantic`` will no longer diagnose this in either C or C++ modes. This - feature was adopted as applying to obsolete versions of C in WG14 and as a - defect report in WG21 (CWG787). -- Implemented `WG14 N3353 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3353.htm>`_ - which adds the new ``0o`` and ``0O`` ocal literal prefixes and deprecates - octal literals other than ``0`` which do not start with the new prefix. This - feature is exposed in earlier language modes and in C++ as an extension. The - paper also introduced octal and hexadecimal delimited escape sequences (e.g., - ``"\x{12}\o{12}"``) which are also supported as an extension in older C - language modes. -- Implemented `WG14 N3369 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>`_ - which introduces the ``_Lengthof`` operator, and `WG14 N3469 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>`_ - which renamed ``_Lengthof`` to ``_Countof``. This feature is implemented as - a conforming extension in earlier C language modes, but not in C++ language - modes (``std::extent`` and ``std::size`` already provide the same - functionality but with more granularity). The feature can be tested via - ``__has_feature(c_countof)`` or ``__has_extension(c_countof)``. This also - adds the ``<stdcountof.h>`` header file which exposes the ``countof`` macro - which expands to ``_Countof``. C23 Feature Support ^^^^^^^^^^^^^^^^^^^ -- Clang now accepts ``-std=iso9899:2024`` as an alias for C23. -- Added ``__builtin_c23_va_start()`` for compatibility with GCC and to enable - better diagnostic behavior for the ``va_start()`` macro in C23 and later. - This also updates the definition of ``va_start()`` in ``<stdarg.h>`` to use - the new builtin. Fixes #GH124031. -- Implemented `WG14 N2819 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2819.pdf>`_ - which clarified that a compound literal used within a function prototype is - treated as if the compound literal were within the body rather than at file - scope. -- Fixed a bug where you could not cast a null pointer constant to type - ``nullptr_t``. Fixes #GH133644. -- Implemented `WG14 N3037 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3037.pdf>`_ - which allows tag types to be redefined within the same translation unit so - long as both definitions are structurally equivalent (same tag types, same - tag names, same tag members, etc). As a result of this paper, ``-Wvisibility`` - is no longer diagnosed in C23 if the parameter is a complete tag type (it - does still fire when the parameter is an incomplete tag type as that cannot - be completed). -- Fixed a failed assertion with an invalid parameter to the ``#embed`` - directive. Fixes #GH126940. -- Fixed a crash when a declaration of a ``constexpr`` variable with an invalid - type. Fixes #GH140887 -- Documented `WG14 N3006 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm>`_ - which clarified how Clang is handling underspecified object declarations. -- Clang now accepts single variadic parameter in type-name. It's a part of - `WG14 N2975 <https://open-std.org/JTC1/SC22/WG14/www/docs/n2975.pdf>`_ -- Fixed a bug with handling the type operand form of ``typeof`` when it is used - to specify a fixed underlying type for an enumeration. #GH146351 -- Fixed a rejects-valid bug where Clang would reject an enumeration with an - ``_Atomic`` underlying type. The underlying type is the non-atomic, - unqualified version of the specified type. Due to the perhaps surprising lack - of atomic behavior, this is diagnosed under - ``-Wunderlying-atomic-qualifier-ignored``, which defaults to an error. This - can be downgraded with ``-Wno-underlying-atomic-qualifier-ignored`` or - ``-Wno-error=underlying-atomic-qualifier-ignored``. Clang now also diagnoses - cv-qualifiers as being ignored, but that warning does not default to an error. - It can be controlled by ``-Wunderlying-cv-qualifier-ignore``. (#GH147736) - -C11 Feature Support -^^^^^^^^^^^^^^^^^^^ -- Implemented `WG14 N1285 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1285.htm>`_ - which introduces the notion of objects with a temporary lifetime. When an - expression resulting in an rvalue with structure or union type and that type - contains a member of array type, the expression result is an automatic storage - duration object with temporary lifetime which begins when the expression is - evaluated and ends at the evaluation of the containing full expression. This - functionality is also implemented for earlier C language modes because the - C99 semantics will never be implemented (it would require dynamic allocations - of memory which leaks, which users would not appreciate). Non-comprehensive list of changes in this release ------------------------------------------------- +- Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. -- Support parsing the `cc` operand modifier and alias it to the `c` modifier (#GH127719). -- Added `__builtin_elementwise_exp10`. -- For AMDPGU targets, added `__builtin_v_cvt_off_f32_i4` that maps to the `v_cvt_off_f32_i4` instruction. -- Added `__builtin_elementwise_minnum` and `__builtin_elementwise_maxnum`. -- Added `__builtin_elementwise_minnumnum` and `__builtin_elementwise_maxnumnum`. -- No longer crashing on invalid Objective-C categories and extensions when - dumping the AST as JSON. (#GH137320) -- Clang itself now uses split stacks instead of threads for allocating more - stack space when running on Apple AArch64 based platforms. This means that - stack traces of Clang from debuggers, crashes, and profilers may look - different than before. -- Fixed a crash when a VLA with an invalid size expression was used within a - ``sizeof`` or ``typeof`` expression. (#GH138444) -- ``__builtin_invoke`` has been added to improve the compile time of ``std::invoke``. -- Deprecation warning is emitted for the deprecated ``__reference_binds_to_temporary`` intrinsic. - ``__reference_constructs_from_temporary`` should be used instead. (#GH44056) -- Added `__builtin_get_vtable_pointer` to directly load the primary vtable pointer from a - polymorphic object. -- ``libclang`` receives a family of new bindings to query basic facts about - GCC-style inline assembly blocks, including whether the block is ``volatile`` - and its template string following the LLVM IR ``asm`` format. (#GH143424) -- Clang no longer rejects reinterpret_cast conversions between indirect - ARC-managed pointers and other pointer types. The prior behavior was overly - strict and inconsistent with the ARC specification. New Compiler Flags ------------------ -- New option ``-Wundef-true`` added and enabled by default to warn when `true` is used in the C preprocessor without being defined before C23. - -- New option ``-fprofile-continuous`` added to enable continuous profile syncing to file (#GH124353, `docs <https://clang.llvm.org/docs/UsersManual.html#cmdoption-fprofile-continuous>`_). - The feature has `existed <https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program>`_) - for a while and this is just a user facing option. - -- New option ``-ftime-report-json`` added which outputs the same timing data as ``-ftime-report`` but formatted as JSON. - -- New option ``-Wnrvo`` added and disabled by default to warn about missed NRVO opportunities. - -- New option ``-ignore-pch`` added to disable precompiled headers. It overrides ``-emit-pch`` and ``-include-pch``. (#GH142409, `PCHDocs <https://clang.llvm.org/docs/UsersManual.html#ignoring-a-pch-file>`_). - -- New options ``-g[no-]key-instructions`` added, disabled by default. Reduces jumpiness of debug stepping for optimized code in some debuggers (not LLDB at this time). Not recommended for use without optimizations. DWARF only. Note both the positive and negative flags imply ``-g``. - Deprecated Compiler Flags ------------------------- Modified Compiler Flags ----------------------- -- The ARM AArch32 ``-mtp`` option accepts and defaults to ``auto``, a value of ``auto`` uses the best available method of providing the frame pointer supported by the hardware. This matches - the behavior of ``-mtp`` in gcc. This changes the default behavior for ARM targets that provide the ``TPIDRURO`` register as this will be used instead of a call to the ``__aeabi_read_tp``. - Programs that use ``__aeabi_read_tp`` but do not use the ``TPIDRURO`` register must use ``-mtp=soft``. Fixes #123864 - -- The compiler flag `-fbracket-depth` default value is increased from 256 to 2048. (#GH94728) - -- `-Wpadded` option implemented for the `x86_64-windows-msvc` target. Fixes #61702 - -- The ``-mexecute-only`` and ``-mpure-code`` flags are now accepted for AArch64 targets. (#GH125688) - -- The ``-fchar8_t`` flag is no longer considered in non-C++ languages modes. (#GH55373) - -- The ``-fveclib=libmvec`` option now supports AArch64 targets (requires GLIBC 2.40 or newer). - -- The ``-Og`` optimization flag now sets ``-fextend-variable-liveness``, - reducing performance slightly while reducing the number of optimized-out - variables. (#GH118026) - Removed Compiler Flags ------------------------- Attribute Changes in Clang -------------------------- -Adding [[clang::unsafe_buffer_usage]] attribute to a method definition now turns off all -Wunsafe-buffer-usage -related warnings within the method body. - -- The ``no_sanitize`` attribute now accepts both ``gnu`` and ``clang`` names. -- The ``ext_vector_type(n)`` attribute can now be used as a generic type attribute. -- Clang now diagnoses use of declaration attributes on void parameters. (#GH108819) -- Clang now allows ``__attribute__((model("small")))`` and - ``__attribute__((model("large")))`` on non-TLS globals in x86-64 compilations. - This forces the global to be considered small or large in regards to the - x86-64 code model, regardless of the code model specified for the compilation. -- Clang now emits a warning ``-Wreserved-init-priority`` instead of a hard error - when ``__attribute__((init_priority(n)))`` is used with values of n in the - reserved range [0, 100]. The warning will be treated as an error by default. - -- There is a new ``format_matches`` attribute to complement the existing - ``format`` attribute. ``format_matches`` allows the compiler to verify that - a format string argument is equivalent to a reference format string: it is - useful when a function accepts a format string without its accompanying - arguments to format. For instance: - - .. code-block:: c - - static int status_code; - static const char *status_string; - - void print_status(const char *fmt) { - fprintf(stderr, fmt, status_code, status_string); - // ^ warning: format string is not a string literal [-Wformat-nonliteral] - } - - void stuff(void) { - print_status("%s (%#08x)\n"); - // order of %s and %x is swapped but there is no diagnostic - } - - Before the introducion of ``format_matches``, this code cannot be verified - at compile-time. ``format_matches`` plugs that hole: - - .. code-block:: c - - __attribute__((format_matches(printf, 1, "%x %s"))) - void print_status(const char *fmt) { - fprintf(stderr, fmt, status_code, status_string); - // ^ `fmt` verified as if it was "%x %s" here; no longer triggers - // -Wformat-nonliteral, would warn if arguments did not match "%x %s" - } - - void stuff(void) { - print_status("%s (%#08x)\n"); - // warning: format specifier 's' is incompatible with 'x' - // warning: format specifier 'x' is incompatible with 's' - } - - Like with ``format``, the first argument is the format string flavor and the - second argument is the index of the format string parameter. - ``format_matches`` accepts an example valid format string as its third - argument. For more information, see the Clang attributes documentation. - -- Introduced a new statement attribute ``[[clang::atomic]]`` that enables - fine-grained control over atomic code generation on a per-statement basis. - Supported options include ``[no_]remote_memory``, - ``[no_]fine_grained_memory``, and ``[no_]ignore_denormal_mode``. These are - particularly relevant for AMDGPU targets, where they map to corresponding IR - metadata. - -- Clang now disallows the use of attributes applied before an - ``extern template`` declaration (#GH79893). - -- Clang will print the "reason" string argument passed on to - ``[[clang::warn_unused_result("reason")]]`` as part of the warning diagnostic. Improvements to Clang's diagnostics ----------------------------------- - -- Improve the diagnostics for deleted default constructor errors for C++ class - initializer lists that don't explicitly list a class member and thus attempt - to implicitly default construct that member. -- The ``-Wunique-object-duplication`` warning has been added to warn about objects - which are supposed to only exist once per program, but may get duplicated when - built into a shared library. -- Fixed a bug where Clang's Analysis did not correctly model the destructor behavior of ``union`` members (#GH119415). -- A statement attribute applied to a ``case`` label no longer suppresses - 'bypassing variable initialization' diagnostics (#84072). -- The ``-Wunsafe-buffer-usage`` warning has been updated to warn - about unsafe libc function calls. Those new warnings are emitted - under the subgroup ``-Wunsafe-buffer-usage-in-libc-call``. -- Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with - ``-Wno-error=parentheses``. -- Similarly, fold expressions over a comparison operator are now an error by default. -- Clang now better preserves the sugared types of pointers to member. -- Clang now better preserves the presence of the template keyword with dependent - prefixes. -- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of - the template parameter. -- Clang now respects the current language mode when printing expressions in - diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also - a bunch of HLSL types being printed as their C++ equivalents. -- Clang now consistently quotes expressions in diagnostics. -- When printing types for diagnostics, clang now doesn't suppress the scopes of - template arguments contained within nested names. -- The ``-Wshift-bool`` warning has been added to warn about shifting a boolean. (#GH28334) -- Fixed diagnostics adding a trailing ``::`` when printing some source code - constructs, like base classes. -- The :doc:`ThreadSafetyAnalysis` now supports ``-Wthread-safety-pointer``, - which enables warning on passing or returning pointers to guarded variables - as function arguments or return value respectively. Note that - :doc:`ThreadSafetyAnalysis` still does not perform alias analysis. The - feature will be default-enabled with ``-Wthread-safety`` in a future release. -- The :doc:`ThreadSafetyAnalysis` now supports reentrant capabilities. -- Clang will now do a better job producing common nested names, when producing - common types for ternary operator, template argument deduction and multiple return auto deduction. -- The ``-Wsign-compare`` warning now treats expressions with bitwise not(~) and minus(-) as signed integers - except for the case where the operand is an unsigned integer - and throws warning if they are compared with unsigned integers (##18878). -- The ``-Wunnecessary-virtual-specifier`` warning (included in ``-Wextra``) has - been added to warn about methods which are marked as virtual inside a - ``final`` class, and hence can never be overridden. - -- Improve the diagnostics for chained comparisons to report actual expressions and operators (#GH129069). - -- Improve the diagnostics for shadows template parameter to report correct location (#GH129060). - -- Improve the ``-Wundefined-func-template`` warning when a function template is not instantiated due to being unreachable in modules. - -- Fixed an assertion when referencing an out-of-bounds parameter via a function - attribute whose argument list refers to parameters by index and the function - is variadic. e.g., - - .. code-block:: c - - __attribute__ ((__format_arg__(2))) void test (int i, ...) { } - - Fixes #GH61635 - -- Split diagnosing base class qualifiers from the ``-Wignored-Qualifiers`` diagnostic group into a new ``-Wignored-base-class-qualifiers`` diagnostic group (which is grouped under ``-Wignored-qualifiers``). Fixes #GH131935. - -- ``-Wc++98-compat`` no longer diagnoses use of ``__auto_type`` or - ``decltype(auto)`` as though it was the extension for ``auto``. (#GH47900) -- Clang now issues a warning for missing return in ``main`` in C89 mode. (#GH21650) - -- Now correctly diagnose a tentative definition of an array with static - storage duration in pedantic mode in C. (#GH50661) -- No longer diagnosing idiomatic function pointer casts on Windows under - ``-Wcast-function-type-mismatch`` (which is enabled by ``-Wextra``). Clang - would previously warn on this construct, but will no longer do so on Windows: - - .. code-block:: c - - typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); - HMODULE Lib = LoadLibrary("kernel32"); - PGNSI FnPtr = (PGNSI)GetProcAddress(Lib, "GetNativeSystemInfo"); - - -- An error is now emitted when a ``musttail`` call is made to a function marked with the ``not_tail_called`` attribute. (#GH133509). - -- ``-Whigher-precision-for-complex-divison`` warns when: - - - The divisor is complex. - - When the complex division happens in a higher precision type due to arithmetic promotion. - - When using the divide and assign operator (``/=``). - - Fixes #GH131127 - -- ``-Wuninitialized`` now diagnoses when a class does not declare any - constructors to initialize their non-modifiable members. The diagnostic is - not new; being controlled via a warning group is what's new. Fixes #GH41104 - -- Analysis-based diagnostics (like ``-Wconsumed`` or ``-Wunreachable-code``) - can now be correctly controlled by ``#pragma clang diagnostic``. #GH42199 - -- Improved Clang's error recovery for invalid function calls. - -- Improved bit-field diagnostics to consider the type specified by the - ``preferred_type`` attribute. These diagnostics are controlled by the flags - ``-Wpreferred-type-bitfield-enum-conversion`` and - ``-Wpreferred-type-bitfield-width``. These warnings are on by default as they - they're only triggered if the authors are already making the choice to use - ``preferred_type`` attribute. - -- ``-Winitializer-overrides`` and ``-Wreorder-init-list`` are now grouped under - the ``-Wc99-designator`` diagnostic group, as they also are about the - behavior of the C99 feature as it was introduced into C++20. Fixes #GH47037 -- ``-Wreserved-identifier`` now fires on reserved parameter names in a function - declaration which is not a definition. -- Clang now prints the namespace for an attribute, if any, - when emitting an unknown attribute diagnostic. - -- ``-Wvolatile`` now warns about volatile-qualified class return types - as well as volatile-qualified scalar return types. Fixes #GH133380 - -- Several compatibility diagnostics that were incorrectly being grouped under - ``-Wpre-c++20-compat`` are now part of ``-Wc++20-compat``. (#GH138775) - -- Improved the ``-Wtautological-overlap-compare`` diagnostics to warn about overlapping and non-overlapping ranges involving character literals and floating-point literals. - The warning message for non-overlapping cases has also been improved (#GH13473). - -- Fixed a duplicate diagnostic when performing typo correction on function template - calls with explicit template arguments. (#GH139226) - -- Explanatory note is printed when ``assert`` fails during evaluation of a - constant expression. Prior to this, the error inaccurately implied that assert - could not be used at all in a constant expression (#GH130458) - -- A new off-by-default warning ``-Wms-bitfield-padding`` has been added to alert to cases where bit-field - packing may differ under the MS struct ABI (#GH117428). - -- ``-Watomic-access`` no longer fires on unreachable code. e.g., - - .. code-block:: c - - _Atomic struct S { int a; } s; - void func(void) { - if (0) - s.a = 12; // Previously diagnosed with -Watomic-access, now silenced - s.a = 12; // Still diagnosed with -Watomic-access - return; - s.a = 12; // Previously diagnosed, now silenced - } - - -- A new ``-Wcharacter-conversion`` warns where comparing or implicitly converting - between different Unicode character types (``char8_t``, ``char16_t``, ``char32_t``). - This warning only triggers in C++ as these types are aliases in C. (#GH138526) - -- Fixed a crash when checking a ``__thread``-specified variable declaration - with a dependent type in C++. (#GH140509) - -- Clang now suggests corrections for unknown attribute names. - -- ``-Wswitch`` will now diagnose unhandled enumerators in switches also when - the enumerator is deprecated. Warnings about using deprecated enumerators in - switch cases have moved behind a new ``-Wdeprecated-declarations-switch-case`` - flag. - - For example: - - .. code-block:: c - - enum E { - Red, - Green, - Blue [[deprecated]] - }; - void example(enum E e) { - switch (e) { - case Red: // stuff... - case Green: // stuff... - } - } - - will result in a warning about ``Blue`` not being handled in the switch. - - The warning can be fixed either by adding a ``default:``, or by adding - ``case Blue:``. Since the enumerator is deprecated, the latter approach will - trigger a ``'Blue' is deprecated`` warning, which can be turned off with - ``-Wno-deprecated-declarations-switch-case``. - -- Split diagnosis of implicit integer comparison on negation to a new - diagnostic group ``-Wimplicit-int-comparison-on-negation``, grouped under - ``-Wimplicit-int-conversion``, so user can turn it off independently. - -- Improved the FixIts for unused lambda captures. - -- Delayed typo correction was removed from the compiler; immediate typo - correction behavior remains the same. Delayed typo correction facilities were - fragile and unmaintained, and the removal closed the following issues: - #GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308, - #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490, - #GH36703, #GH32903, #GH23312, #GH69874. - -- Clang no longer emits a spurious -Wdangling-gsl warning in C++23 when - iterating over an element of a temporary container in a range-based - for loop.(#GH109793, #GH145164) - -- Fixed false positives in ``-Wformat-truncation`` and ``-Wformat-overflow`` - diagnostics when floating-point numbers had both width field and plus or space - prefix specified. (#GH143951) - -- A warning is now emitted when ``main`` is attached to a named module, - which can be turned off with ``-Wno-main-attached-to-named-module``. (#GH146247) - -- Clang now avoids issuing `-Wreturn-type` warnings in some cases where - the final statement of a non-void function is a `throw` expression, or - a call to a function that is trivially known to always throw (i.e., its - body consists solely of a `throw` statement). This avoids certain - false positives in exception-heavy code, though only simple patterns - are currently recognized. - -- Clang now accepts ``@tparam`` comments on variable template partial - specializations. (#GH144775) - -- Fixed a bug that caused diagnostic line wrapping to not function correctly on - some systems. (#GH139499) - -- Clang now tries to avoid printing file paths that contain ``..``, instead preferring - the canonical file path if it ends up being shorter. - -- Improve the diagnostics for placement new expression when const-qualified - object was passed as the storage argument. (#GH143708) - -- Clang now does not issue a warning about returning from a function declared with - the ``[[noreturn]]`` attribute when the function body is ended with a call via - pointer, provided it can be proven that the pointer only points to - ``[[noreturn]]`` functions. - - Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic diagnostics for function effects (``[[clang::nonblocking]]`` and ``[[clang::nonallocating]]``). Moved the warning for a missing (though implied) attribute on a redeclaration into this group. @@ -730,287 +121,30 @@ Improvements to Coverage Mapping Bug Fixes in This Version ------------------------- - -- Clang now outputs correct values when #embed data contains bytes with negative - signed char values (#GH102798). -- Fixed a crash when merging named enumerations in modules (#GH114240). -- Fixed rejects-valid problem when #embed appears in std::initializer_list or - when it can affect template argument deduction (#GH122306). -- Fix crash on code completion of function calls involving partial order of function templates - (#GH125500). -- Fixed clang crash when #embed data does not fit into an array - (#GH128987). -- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer incorrectly - considered an error in C23 mode and are allowed as an extension in earlier language modes. - -- Remove the ``static`` specifier for the value of ``_FUNCTION_`` for static functions, in MSVC compatibility mode. -- Fixed a modules crash where exception specifications were not propagated properly (#GH121245, relanded in #GH129982) -- Fixed a problematic case with recursive deserialization within ``FinishedDeserializing()`` where - ``PassInterestingDeclsToConsumer()`` was called before the declarations were safe to be passed. (#GH129982) -- Fixed a modules crash where an explicit Constructor was deserialized. (#GH132794) -- Defining an integer literal suffix (e.g., ``LL``) before including - ``<stdint.h>`` in a freestanding build no longer causes invalid token pasting - when using the ``INTn_C`` macros. (#GH85995) -- Fixed an assertion failure in the expansion of builtin macros like ``__has_embed()`` with line breaks before the - closing paren. (#GH133574) -- Fixed a crash in error recovery for expressions resolving to templates. (#GH135621) -- Clang no longer accepts invalid integer constants which are too large to fit - into any (standard or extended) integer type when the constant is unevaluated. - Merely forming the token is sufficient to render the program invalid. Code - like this was previously accepted and is now rejected (#GH134658): - .. code-block:: c - - #if 1 ? 1 : 999999999999999999999 - #endif -- ``#embed`` directive now diagnoses use of a non-character file (device file) - such as ``/dev/urandom`` as an error. This restriction may be relaxed in the - future. See (#GH126629). -- Fixed a clang 20 regression where diagnostics attached to some calls to member functions - using C++23 "deducing this" did not have a diagnostic location (#GH135522) - -- Fixed a crash when a ``friend`` function is redefined as deleted. (#GH135506) -- Fixed a crash when ``#embed`` appears as a part of a failed constant - evaluation. The crashes were happening during diagnostics emission due to - unimplemented statement printer. (#GH132641) -- Fixed visibility calculation for template functions. (#GH103477) -- Fixed a bug where an attribute before a ``pragma clang attribute`` or - ``pragma clang __debug`` would cause an assertion. Instead, this now diagnoses - the invalid attribute location appropriately. (#GH137861) -- Fixed a crash when a malformed ``_Pragma`` directive appears as part of an - ``#include`` directive. (#GH138094) -- Fixed a crash during constant evaluation involving invalid lambda captures - (#GH138832) -- Fixed compound literal is not constant expression inside initializer list - (#GH87867) -- Fixed a crash when instantiating an invalid dependent friend template specialization. - (#GH139052) -- Fixed a crash with an invalid member function parameter list with a default - argument which contains a pragma. (#GH113722) -- Fixed assertion failures when generating name lookup table in modules. (#GH61065, #GH134739) -- Fixed an assertion failure in constant compound literal statements. (#GH139160) -- Fix crash due to unknown references and pointer implementation and handling of - base classes. (GH139452) -- Fixed an assertion failure in serialization of constexpr structs containing unions. (#GH140130) -- Fixed duplicate entries in TableGen that caused the wrong attribute to be selected. (GH#140701) -- Fixed type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed. (#GH141397) -- Constant evaluation now correctly runs the destructor of a variable declared in - the second clause of a C-style ``for`` loop. (#GH139818) -- Fixed a bug with constexpr evaluation for structs containing unions in case of C++ modules. (#GH143168) -- Fixed incorrect token location when emitting diagnostics for tokens expanded from macros. (#GH143216) -- Fixed an infinite recursion when checking constexpr destructors. (#GH141789) -- Fixed a crash when a malformed using declaration appears in a ``constexpr`` function. (#GH144264) -- Fixed a bug when use unicode character name in macro concatenation. (#GH145240) -- Clang doesn't erroneously inject a ``static_assert`` macro in ms-compatibility and - -std=c99 mode. This resulted in deletion of ``-W/Wno-microsoft-static-assert`` - flag and diagnostic because the macro injection was used to emit this warning. - Unfortunately there is no other good way to diagnose usage of ``static_assert`` - macro without inclusion of ``<assert.h>``. -- In C23, something like ``[[/*possible attributes*/]];`` is an attribute - declaration, not a statement. So it is not allowed by the syntax in places - where a statement is required, specifically as the secondary block of a - selection or iteration statement. This differs from C++, since C++ allows - declaration statements. Clang now emits a warning for these patterns. (#GH141659) -- Fixed false positives for redeclaration errors of using enum in - nested scopes. (#GH147495) -- Fixed a failed assertion with an operator call expression which comes from a - macro expansion when performing analysis for nullability attributes. (#GH138371) -- Fixed a concept equivalent checking crash due to untransformed constraint expressions. (#GH146614) -- Fixed a crash in `clang-scan-deps` when a module with the same name is found - in different locations (#GH134404, #GH146976). - Fix a crash when marco name is empty in ``#pragma push_macro("")`` or - ``#pragma pop_macro("")``. (GH149762). + ``#pragma pop_macro("")``. (#GH149762). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- The behaviour of ``__add_pointer`` and ``__remove_pointer`` for Objective-C++'s ``id`` and interfaces has been fixed. - -- The signature for ``__builtin___clear_cache`` was changed from - ``void(char *, char *)`` to ``void(void *, void *)`` to match GCC's signature - for the same builtin. (#GH47833) - -- ``__has_unique_object_representations(Incomplete[])`` is no longer accepted, per - `LWG4113 <https://cplusplus.github.io/LWG/issue4113>`_. - -- ``__builtin_is_cpp_trivially_relocatable``, ``__builtin_is_replaceable`` and - ``__builtin_trivially_relocate`` have been added to support standard C++26 relocation. - -- ``__is_trivially_relocatable`` has been deprecated, and uses should be replaced by - ``__builtin_is_cpp_trivially_relocatable``. - Note that, it is generally unsafe to ``memcpy`` non-trivially copyable types that - are ``__builtin_is_cpp_trivially_relocatable``. It is recommended to use - ``__builtin_trivially_relocate`` instead. - -- ``__reference_binds_to_temporary``, ``__reference_constructs_from_temporary`` - and ``__reference_converts_from_temporary`` intrinsics no longer consider - function references can bind to temporary objects. (#GH114344) - -- ``__reference_constructs_from_temporary`` and - ``__reference_converts_from_temporary`` intrinsics detect reference binding - to prvalue instead of xvalue now if the second operand is an object type, per - `LWG3819 <https://cplusplus.github.io/LWG/issue3819>`_. - Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Fixed crash when a parameter to the ``clang::annotate`` attribute evaluates to ``void``. See #GH119125 - -- Clang now emits a warning instead of an error when using the one or two - argument form of GCC 11's ``__attribute__((malloc(deallocator)))`` - or ``__attribute__((malloc(deallocator, ptr-index)))`` - (`#51607 <https://github.com/llvm/llvm-project/issues/51607>`_). - -- Corrected the diagnostic for the ``callback`` attribute when passing too many - or too few attribute argument indicies for the specified callback function. - (#GH47451) - -- No longer crashing on ``__attribute__((align_value(N)))`` during template - instantiation when the function parameter type is not a pointer or reference. - (#GH26612) -- Now allowing the ``[[deprecated]]``, ``[[maybe_unused]]``, and - ``[[nodiscard]]`` to be applied to a redeclaration after a definition in both - C and C++ mode for the standard spellings (other spellings, such as - ``__attribute__((unused))`` are still ignored after the definition, though - this behavior may be relaxed in the future). (#GH135481) - -- Clang will warn if a complete type specializes a deprecated partial specialization. - (#GH44496) Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ - -- Clang now supports implicitly defined comparison operators for friend declarations. (#GH132249) -- Clang now diagnoses copy constructors taking the class by value in template instantiations. (#GH130866) -- Clang is now better at keeping track of friend function template instance contexts. (#GH55509) -- Clang now prints the correct instantiation context for diagnostics suppressed - by template argument deduction. -- Errors that occur during evaluation of certain type traits and builtins are - no longer incorrectly emitted when they are used in an SFINAE context. The - type traits are: - - - ``__is_constructible`` and variants, - - ``__is_convertible`` and variants, - - ``__is_assignable`` and variants, - - ``__reference_binds_to_temporary``, - ``__reference_constructs_from_temporary``, - ``__reference_converts_from_temporary``, - - ``__is_trivially_equality_comparable``. - - The builtin is ``__builtin_common_type``. (#GH132044) -- Clang is now better at instantiating the function definition after its use inside - of a constexpr lambda. (#GH125747) -- Fixed a local class member function instantiation bug inside dependent lambdas. (#GH59734), (#GH132208) -- Clang no longer crashes when trying to unify the types of arrays with - certain differences in qualifiers (this could happen during template argument - deduction or when building a ternary operator). (#GH97005) -- Fixed type alias CTAD issues involving default template arguments. (#GH133132), (#GH134471) -- Fixed CTAD issues when initializing anonymous fields with designated initializers. (#GH67173) -- The initialization kind of elements of structured bindings - direct-list-initialized from an array is corrected to direct-initialization. -- Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327) -- Clang now uses the parameter location for abbreviated function templates in ``extern "C"``. (#GH46386) -- Clang will emit an error instead of crash when use co_await or co_yield in - C++26 braced-init-list template parameter initialization. (#GH78426) -- Improved fix for an issue with pack expansions of type constraints, where this - now also works if the constraint has non-type or template template parameters. - (#GH131798) -- Fixes to partial ordering of non-type template parameter packs. (#GH132562) -- Fix crash when evaluating the trailing requires clause of generic lambdas which are part of - a pack expansion. -- Fixes matching of nested template template parameters. (#GH130362) -- Correctly diagnoses template template parameters which have a pack parameter - not in the last position. -- Disallow overloading on struct vs class on dependent types, which is IFNDR, as - this makes the problem diagnosable. -- Improved preservation of the presence or absence of typename specifier when - printing types in diagnostics. -- Clang now correctly parses ``if constexpr`` expressions in immediate function context. (#GH123524) -- Fixed an assertion failure affecting code that uses C++23 "deducing this". (#GH130272) -- Clang now properly instantiates destructors for initialized members within non-delegating constructors. (#GH93251) -- Correctly diagnoses if unresolved using declarations shadows template parameters (#GH129411) -- Fixed C++20 aggregate initialization rules being incorrectly applied in certain contexts. (#GH131320) -- Clang was previously coalescing volatile writes to members of volatile base class subobjects. - The issue has been addressed by propagating qualifiers during derived-to-base conversions in the AST. (#GH127824) -- Correctly propagates the instantiated array type to the ``DeclRefExpr`` that refers to it. (#GH79750), (#GH113936), (#GH133047) -- Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892) -- Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused - and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810) -- Fixed ``static_cast`` not performing access or ambiguity checks when converting to an rvalue reference to a base class. (#GH121429) -- Declarations using class template argument deduction with redundant - parentheses around the declarator are no longer rejected. (#GH39811) -- Fixed a crash caused by invalid declarations of ``std::initializer_list``. (#GH132256) -- Clang no longer crashes when establishing subsumption between some constraint expressions. (#GH122581) -- Clang now issues an error when placement new is used to modify a const-qualified variable - in a ``constexpr`` function. (#GH131432) -- Fixed an incorrect TreeTransform for calls to ``consteval`` functions if a conversion template is present. (#GH137885) -- Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806) -- Fixed a missed initializer instantiation bug for variable templates. (#GH134526), (#GH138122) -- Fix a crash when checking the template template parameters of a dependent lambda appearing in an alias declaration. - (#GH136432), (#GH137014), (#GH138018) -- Fixed an assertion when trying to constant-fold various builtins when the argument - referred to a reference to an incomplete type. (#GH129397) -- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880) -- No longer crashes when instantiating invalid variable template specialization - whose type depends on itself. (#GH51347), (#GH55872) -- Improved parser recovery of invalid requirement expressions. In turn, this - fixes crashes from follow-on processing of the invalid requirement. (#GH138820) -- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255) -- Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107) -- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852) -- Fixed a function declaration mismatch that caused inconsistencies between concepts and variable template declarations. (#GH139476) -- Fixed an out-of-line declaration mismatch involving nested template parameters. (#GH145521) -- Clang no longer segfaults when there is a configuration mismatch between modules and their users (http://crbug.com/400353616). -- Fix an incorrect deduction when calling an explicit object member function template through an overload set address. -- Fixed bug in constant evaluation that would allow using the value of a - reference in its own initializer in C++23 mode (#GH131330). -- Clang could incorrectly instantiate functions in discarded contexts (#GH140449) -- Fix instantiation of default-initialized variable template specialization. (#GH140632) (#GH140622) -- Clang modules now allow a module and its user to differ on TrivialAutoVarInit* -- Fixed an access checking bug when initializing non-aggregates in default arguments (#GH62444), (#GH83608) -- Fixed a pack substitution bug in deducing class template partial specializations. (#GH53609) -- Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835) -- Fixed an access checking bug when substituting into concepts (#GH115838) -- Fix a bug where private access specifier of overloaded function not respected. (#GH107629) -- Correctly handles calling an explicit object member function template overload set - through its address (``(&Foo::bar<baz>)()``). -- Fix a crash when using an explicit object parameter in a non-member function. (#GH113185) -- Fix a crash when forming an invalid call to an operator with an explicit object member. (#GH147121) -- Correctly handle allocations in the condition of a ``if constexpr``.(#GH120197) (#GH134820) -- Fixed a crash when handling invalid member using-declaration in C++20+ mode. (#GH63254) -- Fixed parsing of lambda expressions that appear after ``*`` or ``&`` in contexts where a declaration can appear. (#GH63880) -- Fix name lookup in lambda appearing in the body of a requires expression. (#GH147650) -- Fix a crash when trying to instantiate an ambiguous specialization. (#GH51866) -- Improved handling of variables with ``consteval`` constructors, to - consistently treat the initializer as manifestly constant-evaluated. - (#GH135281) -- Fix a crash in the presence of invalid base classes. (#GH147186) -- Fix a crash with NTTP when instantiating local class. -- Fixed a crash involving list-initialization of an empty class with a - non-empty initializer list. (#GH147949) -- Fixed constant evaluation of equality comparisons of constexpr-unknown references. (#GH147663) - Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) +- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293) +- Fix a crash when deleting a pointer to an incomplete array (#GH150359). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ -- Fixed type checking when a statement expression ends in an l-value of atomic type. (#GH106576) -- Fixed uninitialized use check in a lambda within CXXOperatorCallExpr. (#GH129198) -- Fixed a malformed printout of ``CXXParenListInitExpr`` in certain contexts. -- Fixed a malformed printout of certain calling convention function attributes. (#GH143160) -- Fixed dependency calculation for TypedefTypes (#GH89774) -- The ODR checker now correctly hashes the names of conversion operators. (#GH143152) -- Fixed the right parenthesis source location of ``CXXTemporaryObjectExpr``. (#GH143711) -- Fixed a crash when performing an ``IgnoreUnlessSpelledInSource`` traversal of ASTs containing ``catch(...)`` statements. (#GH146103) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ -- HTML tags in comments that span multiple lines are now parsed correctly by Clang's comment parser. (#GH120843) - Miscellaneous Clang Crashes Fixed ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Fixed crash when ``-print-stats`` is enabled in compiling IR files. (#GH131608) -- Fix code completion crash involving PCH serialized templates. (#GH139019) - OpenACC Specific Changes ------------------------ @@ -1020,123 +154,30 @@ Target Specific Changes AMDGPU Support ^^^^^^^^^^^^^^ -- Bump the default code object version to 6. ROCm 6.3 is required to run any program compiled with COV6. - NVPTX Support ^^^^^^^^^^^^^^ -Hexagon Support -^^^^^^^^^^^^^^^ - -- The default compilation target has been changed from V60 to V68. - X86 Support ^^^^^^^^^^^ -- The 256-bit maximum vector register size control was removed from - `AVX10 whitepaper <https://cdrdv2.intel.com/v1/dl/getContent/784343>_`. - * Re-target ``m[no-]avx10.1`` to enable AVX10.1 with 512-bit maximum vector register size. - * Emit warning for ``mavx10.x-256``, noting AVX10/256 is not supported. - * Emit warning for ``mavx10.x-512``, noting to use ``m[no-]avx10.x`` instead. - * Emit warning for ``m[no-]evex512``, noting AVX10/256 is not supported. - * The features avx10.x-256/512 keep unchanged and will be removed in the next release. - Arm and AArch64 Support ^^^^^^^^^^^^^^^^^^^^^^^ -- Implementation of modal 8-bit floating point intrinsics in accordance with - the Arm C Language Extensions (ACLE) - `as specified here <https://github.com/ARM-software/acle/blob/main/main/acle.md#modal-8-bit-floating-point-extensions>`_ - is now available. -- Support has been added for the following processors (command-line identifiers in parentheses): - - - Arm Cortex-A320 (``cortex-a320``) - -- For ARM targets, cc1as now considers the FPU's features for the selected CPU or Architecture. -- The ``+nosimd`` attribute is now fully supported for ARM. Previously, this had no effect when being used with - ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is - also now printed when the ``--print-supported-extensions`` option is used. -- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled. -- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled. - -- Pointer authentication - - - Support for __ptrauth type qualifier has been added. - - Objective-C adoption of pointer authentication - - - ``isa`` and ``super`` pointers are protected with address diversity and separate - usage specific discriminators. - - methodlist pointers and content are protected with address diversity and methodlist - pointers have a usage specific discriminator. - - ``class_ro_t`` pointers are protected with address diversity and usage specific - discriminators. - - ``SEL`` typed ivars are protected with address diversity and usage specific - discriminators. - -- For AArch64, added support for generating executable-only code sections by using the - ``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688) -- Added ``-msve-streaming-vector-bits=`` flag, which allows specifying the - SVE vector width in streaming mode. - Android Support ^^^^^^^^^^^^^^^ Windows Support ^^^^^^^^^^^^^^^ -- Clang now defines ``_CRT_USE_BUILTIN_OFFSETOF`` macro in MSVC-compatible mode, - which makes ``offsetof`` provided by Microsoft's ``<stddef.h>`` to be defined - correctly. (#GH59689) - -- Clang now can process the `i128` and `ui128` integral suffixes when MSVC - extensions are enabled. This allows for properly processing ``intsafe.h`` in - the Windows SDK. - LoongArch Support ^^^^^^^^^^^^^^^^^ -- Add support for OHOS on loongarch64. - -- Add target attribute support for function. Supported formats include: - * `arch=<arch>` strings - specifies architecture features for a function (equivalent to `-march=<arch>`). - * `tune=<cpu>` strings - specifies the tune CPU for a function (equivalent to `-mtune`). - * `<feature>`/`no-<feature>` - enables/disables specific features. - -- Add support for the `_Float16` type. And fix incorrect ABI lowering of `_Float16` - in the case of structs containing fp16 that are eligible for passing via `GPR+FPR` - or `FPR+FPR`. Also fix `int16` -> `__fp16` conversion code gen, which uses generic LLVM - IR rather than `llvm.convert.to.fp16` intrinsics. - -- Add support for the `__bf16` type. - -- Fix incorrect _BitInt(N>64) alignment. Now consistently uses 16-byte alignment for all - `_BitInt(N)` where N > 64. - RISC-V Support ^^^^^^^^^^^^^^ -- Add support for `-mtune=generic-ooo` (a generic out-of-order model). -- Adds support for `__attribute__((interrupt("SiFive-CLIC-preemptible")))` and - `__attribute__((interrupt("SiFive-CLIC-stack-swap")))`. The former - automatically saves some interrupt CSRs before re-enabling interrupts in the - function prolog, the latter swaps `sp` with the value in a CSR before it is - used or modified. These two can also be combined, and can be combined with - `interrupt("machine")`. - -- Adds support for `__attribute__((interrupt("qci-nest")))` and - `__attribute__((interrupt("qci-nonest")))`. These use instructions from - Qualcomm's `Xqciint` extension to save and restore some GPRs in interrupt - service routines. - -- `Zicsr` / `Zifencei` are allowed to be duplicated in the presence of `g` in `-march`. - -- Add support for the `__builtin_riscv_pause()` intrinsic from the `Zihintpause` extension. - CUDA/HIP Language Changes ^^^^^^^^^^^^^^^^^^^^^^^^^ -* Provide a __device__ version of std::__glibcxx_assert_fail() in a header wrapper. - CUDA Support ^^^^^^^^^^^^ @@ -1163,164 +204,54 @@ Fixed Point Support in Clang AST Matchers ------------ - - Ensure ``hasBitWidth`` doesn't crash on bit widths that are dependent on template parameters. -- Ensure ``isDerivedFrom`` matches the correct base in case more than one alias exists. -- Extend ``templateArgumentCountIs`` to support function and variable template - specialization. clang-format ------------ -- Adds ``BreakBeforeTemplateCloser`` option. -- Adds ``BinPackLongBracedList`` option to override bin packing options in - long (20 item or more) braced list initializer lists. -- Add the C language instead of treating it like C++. -- Allow specifying the language (C, C++, or Objective-C) for a ``.h`` file by - adding a special comment (e.g. ``// clang-format Language: ObjC``) near the - top of the file. -- Add ``EnumTrailingComma`` option for inserting/removing commas at the end of - ``enum`` enumerator lists. -- Add ``OneLineFormatOffRegex`` option for turning formatting off for one line. -- Add ``SpaceAfterOperatorKeyword`` option. -- Add ``MacrosSkippedByRemoveParentheses`` option so that their invocations are - skipped by ``RemoveParentheses``. - -clang-refactor --------------- -- Reject `0` as column or line number in 1-based command-line source locations. - Fixes crash caused by `0` input in `-selection=<file>:<line>:<column>[-<line>:<column>]`. (#GH139457) - libclang -------- -- Fixed a bug in ``clang_File_isEqual`` that sometimes led to different - in-memory files to be considered as equal. -- Added ``clang_visitCXXMethods``, which allows visiting the methods - of a class. -- Added ``clang_getFullyQualifiedName``, which provides fully qualified type names as - instructed by a PrintingPolicy. - -- Fixed a buffer overflow in ``CXString`` implementation. The fix may result in - increased memory allocation. - -- Deprecate ``clang_Cursor_GetBinaryOpcode`` and ``clang_Cursor_getBinaryOpcodeStr`` - implementations, which are duplicates of ``clang_getCursorBinaryOperatorKind`` - and ``clang_getBinaryOperatorKindSpelling`` respectively. Code Completion --------------- -- Reject `0` as column or line number in 1-based command-line source locations. - Fixes crash caused by `0` input in `-code-completion-at=<file>:<line>:<column>`. (#GH139457) Static Analyzer --------------- -- Fixed a crash when C++20 parenthesized initializer lists are used. This issue - was causing a crash in clang-tidy. (#GH136041) - The Clang Static Analyzer now handles parenthesized initialization. (#GH148875) New features ^^^^^^^^^^^^ -- A new flag - `-static-libclosure` was introduced to support statically linking - the runtime for the Blocks extension on Windows. This flag currently only - changes the code generation, and even then, only on Windows. This does not - impact the linker behaviour like the other `-static-*` flags. -- OpenACC support, enabled via `-fopenacc` has reached a level of completeness - to finally be at least notionally usable. Currently, the OpenACC 3.4 - specification has been completely implemented for Sema and AST creation, so - nodes will show up in the AST after having been properly checked. Lowering is - currently a work in progress, with compute, loop, and combined constructs - partially implemented, plus a handful of data and executable constructs - implemented. Lowering will only work in Clang-IR mode (so only with a compiler - built with Clang-IR enabled, and with `-fclangir` used on the command line). - However, note that the Clang-IR implementation status is also quite partial, - so frequent 'not yet implemented' diagnostics should be expected. Also, the - ACC MLIR dialect does not currently implement any lowering to LLVM-IR, so no - code generation is possible for OpenACC. -- Implemented `P2719R5 Type-aware allocation and deallocation functions <https://wg21.link/P2719>`_ - as an extension in all C++ language modes. - - Crash and bug fixes ^^^^^^^^^^^^^^^^^^^ -- Fixed a crash in ``UnixAPIMisuseChecker`` and ``MallocChecker`` when analyzing - code with non-standard ``getline`` or ``getdelim`` function signatures. (#GH144884) - Improvements ^^^^^^^^^^^^ -- The checker option ``optin.cplusplus.VirtualCall:PureOnly`` was removed, - because it had been deprecated since 2019 and it is completely useless (it - was kept only for compatibility with pre-2019 versions, setting it to true is - equivalent to completely disabling the checker). - Moved checkers ^^^^^^^^^^^^^^ -- After lots of improvements, the checker ``alpha.security.ArrayBoundV2`` is - renamed to ``security.ArrayBound``. As this checker is stable now, the old - checker ``alpha.security.ArrayBound`` (which was searching for the same kind - of bugs with an different, simpler and less accurate algorithm) is removed. - .. _release-notes-sanitizers: Sanitizers ---------- -- ``-fsanitize=vptr`` is no longer a part of ``-fsanitize=undefined``. -- Sanitizer ignorelists now support the syntax ``src:*=sanitize``, - ``type:*=sanitize``, ``fun:*=sanitize``, ``global:*=sanitize``, - and ``mainfile:*=sanitize``. - Python Binding Changes ---------------------- -- Made ``Cursor`` hashable. -- Added ``Cursor.has_attrs``, a binding for ``clang_Cursor_hasAttrs``, to check - whether a cursor has any attributes. -- Added ``Cursor.specialized_template``, a binding for - ``clang_getSpecializedCursorTemplate``, to retrieve the primary template that - the cursor is a specialization of. -- Added ``Type.get_methods``, a binding for ``clang_visitCXXMethods``, which - allows visiting the methods of a class. -- Added ``Type.get_fully_qualified_name``, which provides fully qualified type names as - instructed by a PrintingPolicy. -- Add equality comparison operators for ``File`` type OpenMP Support -------------- -- Added support 'no_openmp_constructs' assumption clause. -- Added support for 'self_maps' in map and requirement clause. -- Added support for 'omp stripe' directive. -- Fixed a crashing bug with ``omp unroll partial`` if the argument to - ``partial`` was an invalid expression. (#GH139267) -- Fixed a crashing bug with ``omp tile sizes`` if the argument to ``sizes`` was - an invalid expression. (#GH139073) -- Fixed a crashing bug with ``omp simd collapse`` if the argument to - ``collapse`` was an invalid expression. (#GH138493) -- Fixed a crashing bug with a malformed ``cancel`` directive. (#GH139360) -- Fixed a crashing bug with ``omp distribute dist_schedule`` if the argument to - ``dist_schedule`` was not strictly positive. (#GH139266) -- Fixed two crashing bugs with a malformed ``metadirective`` directive. One was - a crash if the next token after ``metadirective`` was a paren, bracket, or - brace. The other was if the next token after the meta directive was not an - open parenthesis. (#GH139665) -- An error is now emitted when OpenMP ``collapse`` and ``ordered`` clauses have - an argument larger than what can fit within a 64-bit integer. -- Added support for private variable reduction. -- Fixed mapping of arrays of structs containing nested structs with user defined - mappers, by using compiler-generated default mappers for the outer structs for - such maps. -- Deprecation warning has been emitted for deprecated delimited form of ``declare target``. +- Added parsing and semantic analysis support for the ``need_device_addr`` + modifier in the ``adjust_args`` clause. +- Allow array length to be omitted in array section subscript expression. Improvements ^^^^^^^^^^^^ Additional Information - -=================== +====================== A wide variety of additional information is available on the `Clang web page <https://clang.llvm.org/>`_. The web page contains versions of the diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 26c5028..4e8b318 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1103,7 +1103,16 @@ To override this threshold to e.g. 4 bytes, use the optin.portability.UnixAPI """"""""""""""""""""""""" -Finds implementation-defined behavior in UNIX/Posix functions. +Reports situations where 0 is passed as the "size" argument of various +allocation functions ( ``calloc``, ``malloc``, ``realloc``, ``reallocf``, +``alloca``, ``__builtin_alloca``, ``__builtin_alloca_with_align``, ``valloc``). + +Note that similar functionality is also supported by :ref:`unix-Malloc` which +reports code that *uses* memory allocated with size zero. + +(The name of this checker is motivated by the fact that it was originally +introduced with the vague goal that it "Finds implementation-defined behavior +in UNIX/Posix functions.") optin.taint diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 17cbfb2..c099e75 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -634,6 +634,8 @@ public: void setRelocationInfoForCXXRecord(const CXXRecordDecl *, CXXRecordDeclRelocationInfo); + void initSanitizers(const LangOptions &LangOpts, SourceManager &SM); + /// Examines a given type, and returns whether the type itself /// is address discriminated, or any transitively embedded types /// contain data that is address discriminated. This includes diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 8785435..945e11b 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -642,6 +642,16 @@ TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_f16_f32, "V2hV2hfUiIb", "nc", "f32-to-f16 // GFX1250+ only builtins. //===----------------------------------------------------------------------===// +TARGET_BUILTIN(__builtin_amdgcn_flat_prefetch, "vvC*0Ii", "nc", "vmem-pref-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_prefetch, "vvC*1Ii", "nc", "vmem-pref-insts") + +TARGET_BUILTIN(__builtin_amdgcn_global_load_monitor_b32, "ii*1Ii", "nc", "gfx1250-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_load_monitor_b64, "V2iV2i*1Ii", "nc", "gfx1250-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_load_monitor_b128, "V4iV4i*1Ii", "nc", "gfx1250-insts") +TARGET_BUILTIN(__builtin_amdgcn_flat_load_monitor_b32, "ii*0Ii", "nc", "gfx1250-insts") +TARGET_BUILTIN(__builtin_amdgcn_flat_load_monitor_b64, "V2iV2i*0Ii", "nc", "gfx1250-insts") +TARGET_BUILTIN(__builtin_amdgcn_flat_load_monitor_b128, "V4iV4i*0Ii", "nc", "gfx1250-insts") + TARGET_BUILTIN(__builtin_amdgcn_tensor_load_to_lds, "vV4iV8iV4iV4iIi", "nc", "gfx1250-insts") TARGET_BUILTIN(__builtin_amdgcn_tensor_load_to_lds_d2, "vV4iV8iIi", "nc", "gfx1250-insts") TARGET_BUILTIN(__builtin_amdgcn_tensor_store_from_lds, "vV4iV8iV4iV4iIi", "nc", "gfx1250-insts") diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 759ba04..230698d 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -252,13 +252,13 @@ def err_drv_invalid_argument_to_option : Error< def err_drv_missing_sanitizer_ignorelist : Error< "missing sanitizer ignorelist: '%0'">; def err_drv_malformed_sanitizer_ignorelist : Error< - "malformed sanitizer ignorelist: '%0'">; + "failed to %select{load|parse}0 malformed sanitizer ignorelist: '%1'">; def err_drv_malformed_sanitizer_coverage_allowlist : Error< - "malformed sanitizer coverage allowlist: '%0'">; + "failed to %select{load|parse}0 malformed sanitizer coverage allowlist: '%1'">; def err_drv_malformed_sanitizer_coverage_ignorelist : Error< - "malformed sanitizer coverage ignorelist: '%0'">; + "failed to %select{load|parse}0 malformed sanitizer coverage ignorelist: '%1'">; def err_drv_malformed_sanitizer_metadata_ignorelist : Error< - "malformed sanitizer metadata ignorelist: '%0'">; + "failed to %select{load|parse}0 malformed sanitizer metadata ignorelist: '%1'">; def err_drv_unsupported_static_sanitizer_darwin : Error< "static %0 runtime is not supported on darwin">; def err_drv_duplicate_config : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a8db27..1f0b454 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -370,6 +370,8 @@ def warn_profile_data_misexpect : Warning< "potential performance regression from use of __builtin_expect(): " "annotation was correct on %0 of profiled executions">, BackendInfo, InGroup<MisExpect>; +def err_sanitize_ignorelist_failure : Error< + "failed to %select{load|parse}0 sanitizer ignorelist file: '%1'">; } // end of instrumentation issue category def err_extract_api_ignores_file_not_found : diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 35903af..165f015 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1594,6 +1594,9 @@ def err_omp_unknown_adjust_args_op def err_omp_declare_variant_wrong_clause : Error< "expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause " "on 'omp declare variant' directive">; +def err_omp_non_by_ref_need_device_addr_modifier_argument + : Error<"expected reference type argument on 'adjust_args' clause with " + "'need_device_addr' modifier">; def err_omp_declare_variant_duplicate_nested_trait : Error< "nested OpenMP context selector contains duplicated trait '%0'" " in selector '%1' and set '%2' with different score">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b2ea65a..4a21321 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13438,13 +13438,13 @@ def note_acc_atomic_mismatch_operand : Note<"left hand side of assignment operation(%0) must match one side " "of the sub-operation on the right hand side(%1 and %2)">; def note_acc_atomic_mismatch_compound_operand - : Note<"variable %select{|in unary expression|on right hand side of " + : Note<"sub-expression %select{|in unary expression|on right hand side of " "assignment|on left hand side of assignment|on left hand side of " "compound assignment|on left hand side of assignment}2(%3) must " - "match variable used %select{|in unary expression|on right hand " - "side of assignment|<not possible>|on left hand side of compound " - "assignment|on left hand side of assignment}0(%1) from the first " - "statement">; + "match sub-expression used %select{|in unary expression|on right " + "hand side of assignment|<not possible>|on left hand side of " + "compound assignment|on left hand side of assignment}0(%1) from the " + "first statement">; def err_acc_declare_required_clauses : Error<"no valid clauses specified in OpenACC 'declare' directive">; def err_acc_declare_clause_at_global diff --git a/clang/include/clang/Basic/NoSanitizeList.h b/clang/include/clang/Basic/NoSanitizeList.h index a7a7a29..b6f341d 100644 --- a/clang/include/clang/Basic/NoSanitizeList.h +++ b/clang/include/clang/Basic/NoSanitizeList.h @@ -33,9 +33,10 @@ class NoSanitizeList { StringRef Category) const; public: - NoSanitizeList(const std::vector<std::string> &NoSanitizeListPaths, - SourceManager &SM); + NoSanitizeList(SourceManager &SM); ~NoSanitizeList(); + bool init(const std::vector<std::string> &Paths, + std::pair<unsigned, std::string> &Error); bool containsGlobal(SanitizerMask Mask, StringRef GlobalName, StringRef Category = StringRef()) const; bool containsType(SanitizerMask Mask, StringRef MangledTypeName, diff --git a/clang/include/clang/Basic/SanitizerSpecialCaseList.h b/clang/include/clang/Basic/SanitizerSpecialCaseList.h index cf74859..d7253ec 100644 --- a/clang/include/clang/Basic/SanitizerSpecialCaseList.h +++ b/clang/include/clang/Basic/SanitizerSpecialCaseList.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H #define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Sanitizers.h" #include "llvm/ADT/StringRef.h" @@ -34,11 +35,7 @@ class SanitizerSpecialCaseList : public llvm::SpecialCaseList { public: static std::unique_ptr<SanitizerSpecialCaseList> create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS, - std::string &Error); - - static std::unique_ptr<SanitizerSpecialCaseList> - createOrDie(const std::vector<std::string> &Paths, - llvm::vfs::FileSystem &VFS); + std::pair<unsigned, std::string> &Error); // Query ignorelisted entries if any bit in Mask matches the entry's section. bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 698fd9d..005f261 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -120,7 +120,7 @@ namespace clang { /// A C++ access specifier (public, private, protected), plus the /// special value "none" which means different things in different contexts. - enum AccessSpecifier { + enum AccessSpecifier : uint8_t { AS_public, AS_protected, AS_private, diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td index 0daef4a..ef19610 100644 --- a/clang/include/clang/Basic/arm_neon.td +++ b/clang/include/clang/Basic/arm_neon.td @@ -964,11 +964,11 @@ def SLI_N : WInst<"vsli_n", "...I", "PlQPl", [ImmCheck<2, ImmCheckShiftLeft, 0>] // Right shift narrow high def SHRN_HIGH_N : IOpInst<"vshrn_high_n", "<(<q).I", "HsHiHlHUsHUiHUl", OP_NARROW_HI>; -def QSHRUN_HIGH_N : SOpInst<"vqshrun_high_n", "<(<q).I", +def QSHRUN_HIGH_N : SOpInst<"vqshrun_high_n", "(<U)(<Uq).I", "HsHiHl", OP_NARROW_HI>; def RSHRN_HIGH_N : IOpInst<"vrshrn_high_n", "<(<q).I", "HsHiHlHUsHUiHUl", OP_NARROW_HI>; -def QRSHRUN_HIGH_N : SOpInst<"vqrshrun_high_n", "<(<q).I", +def QRSHRUN_HIGH_N : SOpInst<"vqrshrun_high_n", "(<U)(<Uq).I", "HsHiHl", OP_NARROW_HI>; def QSHRN_HIGH_N : SOpInst<"vqshrn_high_n", "<(<q).I", "HsHiHlHUsHUiHUl", OP_NARROW_HI>; diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 25baf27..5c04d59 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -75,6 +75,12 @@ public: return getConstant(loc, cir::IntAttr::get(ty, value)); } + mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, + unsigned numBits) { + auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/false); + return getConstAPInt(loc, type, llvm::APInt(numBits, val)); + } + // Creates constant null value for integral type ty. cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) { return getConstant(loc, getZeroInitAttr(ty)); diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 694e369..32bb900 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -128,12 +128,12 @@ def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [ // CK_BlockPointerToObjCPointerCast // CK_AnyPointerToBlockPointerCast // CK_ObjCObjectLValueCast - // I32EnumAttrCase<"float_to_complex", 44>, - // I32EnumAttrCase<"float_complex_to_real", 45>, - // I32EnumAttrCase<"float_complex_to_bool", 46>, + I32EnumAttrCase<"float_to_complex", 44>, + I32EnumAttrCase<"float_complex_to_real", 45>, + I32EnumAttrCase<"float_complex_to_bool", 46>, I32EnumAttrCase<"float_complex", 47>, - // I32EnumAttrCase<"float_complex_to_int_complex", 48>, - // I32EnumAttrCase<"int_to_complex", 49>, + I32EnumAttrCase<"float_complex_to_int_complex", 48>, + I32EnumAttrCase<"int_to_complex", 49>, I32EnumAttrCase<"int_complex_to_real", 50>, I32EnumAttrCase<"int_complex_to_bool", 51>, I32EnumAttrCase<"int_complex", 52>, @@ -607,7 +607,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [ //===----------------------------------------------------------------------===// defvar CIR_YieldableScopes = [ - "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp", "SwitchOp", + "ArrayCtor", "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp" ]; @@ -2229,6 +2229,50 @@ def CIR_TrapOp : CIR_Op<"trap", [Terminator]> { } //===----------------------------------------------------------------------===// +// ArrayCtor +//===----------------------------------------------------------------------===// + +class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> { + let arguments = (ins + Arg<CIR_PtrToArray, "array address", [MemWrite, MemRead]>:$addr + ); + + let regions = (region SizedRegion<1>:$body); + let assemblyFormat = [{ + $addr `:` qualified(type($addr)) $body attr-dict + }]; + + let builders = [ + OpBuilder<(ins "mlir::Value":$addr, + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$regionBuilder), [{ + assert(regionBuilder && "builder callback expected"); + mlir::OpBuilder::InsertionGuard guard($_builder); + mlir::Region *r = $_state.addRegion(); + $_state.addOperands(ValueRange{addr}); + $_builder.createBlock(r); + regionBuilder($_builder, $_state.location); + }]> + ]; +} + +def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> { + let summary = "Initialize array elements with C++ constructors"; + let description = [{ + Initialize each array element using the same C++ constructor. This + operation has one region, with one single block. The block has an + incoming argument for the current array index to initialize. + + ```mlir + cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } + ``` + }]; +} + +//===----------------------------------------------------------------------===// // VecCreate //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 2bf7758..d7d55df 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -166,6 +166,12 @@ def CIR_AnyIntOrFloatType : AnyTypeOf<[CIR_AnyFloatType, CIR_AnyIntType], def CIR_AnyComplexType : CIR_TypeBase<"::cir::ComplexType", "complex type">; //===----------------------------------------------------------------------===// +// Array Type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyArrayType : CIR_TypeBase<"::cir::ArrayType", "array type">; + +//===----------------------------------------------------------------------===// // Pointer Type predicates //===----------------------------------------------------------------------===// @@ -216,6 +222,8 @@ def CIR_PtrToIntOrFloatType : CIR_PtrToType<CIR_AnyIntOrFloatType>; def CIR_PtrToComplexType : CIR_PtrToType<CIR_AnyComplexType>; +def CIR_PtrToArray : CIR_PtrToType<CIR_AnyArrayType>; + //===----------------------------------------------------------------------===// // Vector Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h index 02210ec..7a202b1 100644 --- a/clang/include/clang/CIR/Dialect/Passes.h +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -25,6 +25,7 @@ std::unique_ptr<Pass> createCIRFlattenCFGPass(); std::unique_ptr<Pass> createCIRSimplifyPass(); std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createLoweringPreparePass(); +std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx); void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 37e0a4c..e1a5c3d 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -196,6 +196,8 @@ struct MissingFeatures { static bool cxxRecordStaticMembers() { return false; } static bool dataLayoutTypeAllocSize() { return false; } static bool deferredCXXGlobalInit() { return false; } + static bool ehCleanupFlags() { return false; } + static bool ehstackBranches() { return false; } static bool emitCheckedInBoundsGEP() { return false; } static bool emitCondLikelihoodViaExpectIntrinsic() { return false; } static bool emitLifetimeMarkers() { return false; } @@ -254,6 +256,7 @@ struct MissingFeatures { static bool dtorCleanups() { return false; } static bool vtableInitialization() { return false; } static bool msvcBuiltins() { return false; } + static bool vlas() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 78a4c57..4d32552 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -337,6 +337,10 @@ private: /// "clang" as it's first argument. const char *PrependArg; + /// The default value of -fuse-ld= option. An empty string means the default + /// system linker. + std::string PreferredLinker; + /// Whether to check that input files exist when constructing compilation /// jobs. LLVM_PREFERRED_TYPE(bool) @@ -449,6 +453,11 @@ public: return ClangExecutable.c_str(); } + StringRef getPreferredLinker() const { return PreferredLinker; } + void setPreferredLinker(std::string Value) { + PreferredLinker = std::move(Value); + } + bool isSaveTempsEnabled() const { return SaveTemps != SaveTempsNone; } bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; } diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 7677604..a54ab19 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4704,6 +4704,13 @@ struct FormatStyle { /// <conditional-body> <conditional-body> /// \endcode bool AfterIfMacros; + /// If ``true``, put a space between alternative operator ``not`` and the + /// opening parenthesis. + /// \code + /// true: false: + /// return not (a || b); vs. return not(a || b); + /// \endcode + bool AfterNot; /// If ``true``, put a space between operator overloading and opening /// parentheses. /// \code @@ -4752,9 +4759,9 @@ struct FormatStyle { : AfterControlStatements(false), AfterForeachMacros(false), AfterFunctionDeclarationName(false), AfterFunctionDefinitionName(false), AfterIfMacros(false), - AfterOverloadedOperator(false), AfterPlacementOperator(true), - AfterRequiresInClause(false), AfterRequiresInExpression(false), - BeforeNonEmptyParentheses(false) {} + AfterNot(false), AfterOverloadedOperator(false), + AfterPlacementOperator(true), AfterRequiresInClause(false), + AfterRequiresInExpression(false), BeforeNonEmptyParentheses(false) {} bool operator==(const SpaceBeforeParensCustom &Other) const { return AfterControlStatements == Other.AfterControlStatements && @@ -4763,6 +4770,7 @@ struct FormatStyle { Other.AfterFunctionDeclarationName && AfterFunctionDefinitionName == Other.AfterFunctionDefinitionName && AfterIfMacros == Other.AfterIfMacros && + AfterNot == Other.AfterNot && AfterOverloadedOperator == Other.AfterOverloadedOperator && AfterPlacementOperator == Other.AfterPlacementOperator && AfterRequiresInClause == Other.AfterRequiresInClause && diff --git a/clang/include/clang/Lex/DependencyDirectivesScanner.h b/clang/include/clang/Lex/DependencyDirectivesScanner.h index acdc9e2..f9fec39 100644 --- a/clang/include/clang/Lex/DependencyDirectivesScanner.h +++ b/clang/include/clang/Lex/DependencyDirectivesScanner.h @@ -47,11 +47,10 @@ struct Token { bool is(tok::TokenKind K) const { return Kind == K; } bool isNot(tok::TokenKind K) const { return Kind != K; } - bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { - return is(K1) || is(K2); - } - template <typename... Ts> bool isOneOf(tok::TokenKind K1, Ts... Ks) const { - return is(K1) || isOneOf(Ks...); + template <typename... Ts> bool isOneOf(Ts... Ks) const { + static_assert(sizeof...(Ts) > 0, + "requires at least one tok::TokenKind specified"); + return (is(Ks) || ...); } }; diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index ad66a26..a49bdfd 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -30,7 +30,6 @@ namespace hlsl { class RootSignatureParser { public: RootSignatureParser(llvm::dxbc::RootSignatureVersion Version, - SmallVector<RootSignatureElement> &Elements, StringLiteral *Signature, Preprocessor &PP); /// Consumes tokens from the Lexer and constructs the in-memory @@ -40,6 +39,9 @@ public: /// Returns true if a parsing error is encountered. bool parse(); + /// Return all elements that have been parsed. + ArrayRef<RootSignatureElement> getElements() { return Elements; } + private: DiagnosticsEngine &getDiags() { return PP.getDiagnostics(); } @@ -226,7 +228,7 @@ private: private: llvm::dxbc::RootSignatureVersion Version; - SmallVector<RootSignatureElement> &Elements; + SmallVector<RootSignatureElement> Elements; StringLiteral *Signature; RootSignatureLexer Lexer; Preprocessor &PP; diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 2234143..38584c9 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1656,8 +1656,8 @@ def CloneChecker : Checker<"CloneChecker">, let ParentPackage = PortabilityOptIn in { def UnixAPIPortabilityChecker : Checker<"UnixAPI">, - HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">, - Documentation<NotDocumented>; + HelpText<"Finds dynamic memory allocation with size zero">, + Documentation<HasDocumentation>; } // end optin.portability diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6b6275f..c451c87 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -50,6 +50,7 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CommentOptions.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" @@ -944,7 +945,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), DeducedTemplates(this_()), ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), - NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), + NoSanitizeL(new NoSanitizeList(SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, LangOpts.XRayAttrListFiles, SM)), @@ -1697,6 +1698,15 @@ ASTContext::getRelocationInfoForCXXRecord(const CXXRecordDecl *RD) const { return std::nullopt; } +void ASTContext::initSanitizers(const LangOptions &LangOpts, + SourceManager &SM) { + std::pair<unsigned, std::string> Error; + if (!NoSanitizeL->init(LangOpts.NoSanitizeFiles, Error)) { + SM.getDiagnostics().Report(diag::err_sanitize_ignorelist_failure) + << Error.first << Error.second; + } +} + void ASTContext::setRelocationInfoForCXXRecord( const CXXRecordDecl *RD, CXXRecordDeclRelocationInfo Info) { assert(RD); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0d12161..9808298 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14636,7 +14636,9 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && IsRelational) { bool WasArrayIndex; unsigned Mismatch = FindDesignatorMismatch( - getType(LHSValue.Base), LHSDesignator, RHSDesignator, WasArrayIndex); + LHSValue.Base.isNull() ? QualType() + : getType(LHSValue.Base).getNonReferenceType(), + LHSDesignator, RHSDesignator, WasArrayIndex); // At the point where the designators diverge, the comparison has a // specified value if: // - we are comparing array indices @@ -14680,7 +14682,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // compare pointers within the object in question; otherwise, the result // depends on where the object is located in memory. if (!LHSValue.Base.isNull() && IsRelational) { - QualType BaseTy = getType(LHSValue.Base); + QualType BaseTy = getType(LHSValue.Base).getNonReferenceType(); if (BaseTy->isIncompleteType()) return Error(E); CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); diff --git a/clang/lib/Basic/NoSanitizeList.cpp b/clang/lib/Basic/NoSanitizeList.cpp index 96f79fb..dc9ab83 100644 --- a/clang/lib/Basic/NoSanitizeList.cpp +++ b/clang/lib/Basic/NoSanitizeList.cpp @@ -19,11 +19,7 @@ using namespace clang; -NoSanitizeList::NoSanitizeList(const std::vector<std::string> &NoSanitizePaths, - SourceManager &SM) - : SSCL(SanitizerSpecialCaseList::createOrDie( - NoSanitizePaths, SM.getFileManager().getVirtualFileSystem())), - SM(SM) {} +NoSanitizeList::NoSanitizeList(SourceManager &SM) : SM(SM) {} NoSanitizeList::~NoSanitizeList() = default; @@ -42,6 +38,13 @@ bool NoSanitizeList::containsPrefix(SanitizerMask Mask, StringRef Prefix, return San == llvm::SpecialCaseList::NotFound || NoSan > San; } +bool NoSanitizeList::init(const std::vector<std::string> &Paths, + std::pair<unsigned, std::string> &Error) { + SSCL = SanitizerSpecialCaseList::create( + Paths, SM.getFileManager().getVirtualFileSystem(), Error); + return SSCL != nullptr; +} + bool NoSanitizeList::containsGlobal(SanitizerMask Mask, StringRef GlobalName, StringRef Category) const { return containsPrefix(Mask, "global", GlobalName, Category); diff --git a/clang/lib/Basic/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp index 8481def..2b9f88eb 100644 --- a/clang/lib/Basic/ProfileList.cpp +++ b/clang/lib/Basic/ProfileList.cpp @@ -26,7 +26,7 @@ class ProfileSpecialCaseList : public llvm::SpecialCaseList { public: static std::unique_ptr<ProfileSpecialCaseList> create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS, - std::string &Error); + std::pair<unsigned, std::string> &Error); static std::unique_ptr<ProfileSpecialCaseList> createOrDie(const std::vector<std::string> &Paths, @@ -44,7 +44,8 @@ public: std::unique_ptr<ProfileSpecialCaseList> ProfileSpecialCaseList::create(const std::vector<std::string> &Paths, - llvm::vfs::FileSystem &VFS, std::string &Error) { + llvm::vfs::FileSystem &VFS, + std::pair<unsigned, std::string> &Error) { auto PSCL = std::make_unique<ProfileSpecialCaseList>(); if (PSCL->createInternal(Paths, VFS, Error)) return PSCL; @@ -54,10 +55,11 @@ ProfileSpecialCaseList::create(const std::vector<std::string> &Paths, std::unique_ptr<ProfileSpecialCaseList> ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS) { - std::string Error; + std::pair<unsigned, std::string> Error; if (auto PSCL = create(Paths, VFS, Error)) return PSCL; - llvm::report_fatal_error(llvm::Twine(Error)); + // TODO: add init function and use diagnose instead fo report_fatal_error + llvm::report_fatal_error(llvm::Twine(Error.second)); } } // namespace clang diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp index f7bc1d5..c3729e9 100644 --- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp +++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -18,7 +18,7 @@ using namespace clang; std::unique_ptr<SanitizerSpecialCaseList> SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS, - std::string &Error) { + std::pair<unsigned, std::string> &Error) { std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL( new SanitizerSpecialCaseList()); if (SSCL->createInternal(Paths, VFS, Error)) { @@ -28,15 +28,6 @@ SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, return nullptr; } -std::unique_ptr<SanitizerSpecialCaseList> -SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths, - llvm::vfs::FileSystem &VFS) { - std::string Error; - if (auto SSCL = create(Paths, VFS, Error)) - return SSCL; - llvm::report_fatal_error(StringRef(Error)); -} - void SanitizerSpecialCaseList::createSanitizerSections() { for (auto &S : Sections) { SanitizerMask Mask; diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index fbf53db..50cca0e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -12,6 +12,7 @@ #include "CIRGenCXXABI.h" #include "CIRGenFunction.h" +#include "CIRGenValue.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -311,6 +312,116 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs, assert(!cir::MissingFeatures::requiresCleanups()); } +/// Emit a loop to call a particular constructor for each of several members +/// of an array. +/// +/// \param ctor the constructor to call for each element +/// \param arrayType the type of the array to initialize +/// \param arrayBegin an arrayType* +/// \param zeroInitialize true if each element should be +/// zero-initialized before it is constructed +void CIRGenFunction::emitCXXAggrConstructorCall( + const CXXConstructorDecl *ctor, const clang::ArrayType *arrayType, + Address arrayBegin, const CXXConstructExpr *e, bool newPointerIsChecked, + bool zeroInitialize) { + QualType elementType; + mlir::Value numElements = emitArrayLength(arrayType, elementType, arrayBegin); + emitCXXAggrConstructorCall(ctor, numElements, arrayBegin, e, + newPointerIsChecked, zeroInitialize); +} + +/// Emit a loop to call a particular constructor for each of several members +/// of an array. +/// +/// \param ctor the constructor to call for each element +/// \param numElements the number of elements in the array; +/// may be zero +/// \param arrayBase a T*, where T is the type constructed by ctor +/// \param zeroInitialize true if each element should be +/// zero-initialized before it is constructed +void CIRGenFunction::emitCXXAggrConstructorCall( + const CXXConstructorDecl *ctor, mlir::Value numElements, Address arrayBase, + const CXXConstructExpr *e, bool newPointerIsChecked, bool zeroInitialize) { + // It's legal for numElements to be zero. This can happen both + // dynamically, because x can be zero in 'new A[x]', and statically, + // because of GCC extensions that permit zero-length arrays. There + // are probably legitimate places where we could assume that this + // doesn't happen, but it's not clear that it's worth it. + + // Optimize for a constant count. + auto constantCount = dyn_cast<cir::ConstantOp>(numElements.getDefiningOp()); + if (constantCount) { + auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue()); + // Just skip out if the constant count is zero. + if (constIntAttr && constIntAttr.getUInt() == 0) + return; + } else { + // Otherwise, emit the check. + cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); + } + + auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType()); + mlir::Type elementType = arrayTy.getElementType(); + cir::PointerType ptrToElmType = builder.getPointerTo(elementType); + + // Tradional LLVM codegen emits a loop here. CIR lowers to a loop as part of + // LoweringPrepare. + + // The alignment of the base, adjusted by the size of a single element, + // provides a conservative estimate of the alignment of every element. + // (This assumes we never start tracking offsetted alignments.) + // + // Note that these are complete objects and so we don't need to + // use the non-virtual size or alignment. + QualType type = getContext().getTypeDeclType(ctor->getParent()); + CharUnits eltAlignment = arrayBase.getAlignment().alignmentOfArrayElement( + getContext().getTypeSizeInChars(type)); + + // Zero initialize the storage, if requested. + if (zeroInitialize) + emitNullInitialization(*currSrcLoc, arrayBase, type); + + // C++ [class.temporary]p4: + // There are two contexts in which temporaries are destroyed at a different + // point than the end of the full-expression. The first context is when a + // default constructor is called to initialize an element of an array. + // If the constructor has one or more default arguments, the destruction of + // every temporary created in a default argument expression is sequenced + // before the construction of the next array element, if any. + { + assert(!cir::MissingFeatures::runCleanupsScope()); + + // Evaluate the constructor and its arguments in a regular + // partial-destroy cleanup. + if (getLangOpts().Exceptions && + !ctor->getParent()->hasTrivialDestructor()) { + cgm.errorNYI(e->getSourceRange(), "partial array cleanups"); + } + + // Emit the constructor call that will execute for every array element. + mlir::Value arrayOp = + builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); + builder.create<cir::ArrayCtor>( + *currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) { + mlir::BlockArgument arg = + b.getInsertionBlock()->addArgument(ptrToElmType, loc); + Address curAddr = Address(arg, elementType, eltAlignment); + assert(!cir::MissingFeatures::sanitizers()); + auto currAVS = AggValueSlot::forAddr( + curAddr, type.getQualifiers(), AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap, + AggValueSlot::IsNotZeroed); + emitCXXConstructorCall(ctor, Ctor_Complete, + /*ForVirtualBase=*/false, + /*Delegating=*/false, currAVS, e); + builder.create<cir::YieldOp>(loc); + }); + } + + if (constantCount.use_empty()) + constantCount.erase(); +} + void CIRGenFunction::emitDelegateCXXConstructorCall( const CXXConstructorDecl *ctor, CXXCtorType ctorType, const FunctionArgList &args, SourceLocation loc) { @@ -369,6 +480,19 @@ void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) { s->getStmtClassName()); } +void CIRGenFunction::destroyCXXObject(CIRGenFunction &cgf, Address addr, + QualType type) { + const RecordType *rtype = type->castAs<RecordType>(); + const CXXRecordDecl *record = cast<CXXRecordDecl>(rtype->getDecl()); + const CXXDestructorDecl *dtor = record->getDestructor(); + // TODO(cir): Unlike traditional codegen, CIRGen should actually emit trivial + // dtors which shall be removed on later CIR passes. However, only remove this + // assertion after we have a test case to exercise this path. + assert(!dtor->isTrivial()); + cgf.emitCXXDestructorCall(dtor, Dtor_Complete, /*forVirtualBase*/ false, + /*delegating=*/false, addr, type); +} + void CIRGenFunction::emitDelegatingCXXConstructorCall( const CXXConstructorDecl *ctor, const FunctionArgList &args) { assert(ctor->isDelegatingConstructor()); diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp new file mode 100644 index 0000000..be21ce9 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp @@ -0,0 +1,69 @@ +//===--- CIRGenCleanup.cpp - Bookkeeping and code emission for cleanups ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains code dealing with the IR generation for cleanups +// and related information. +// +// A "cleanup" is a piece of code which needs to be executed whenever +// control transfers out of a particular scope. This can be +// conditionalized to occur only on exceptional control flow, only on +// normal control flow, or both. +// +//===----------------------------------------------------------------------===// + +#include "CIRGenFunction.h" + +#include "clang/CIR/MissingFeatures.h" + +using namespace clang; +using namespace clang::CIRGen; + +//===----------------------------------------------------------------------===// +// CIRGenFunction cleanup related +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// EHScopeStack +//===----------------------------------------------------------------------===// + +void EHScopeStack::Cleanup::anchor() {} + +static mlir::Block *getCurCleanupBlock(CIRGenFunction &cgf) { + mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder()); + mlir::Block *cleanup = + cgf.curLexScope->getOrCreateCleanupBlock(cgf.getBuilder()); + return cleanup; +} + +/// Pops a cleanup block. If the block includes a normal cleanup, the +/// current insertion point is threaded through the cleanup, as are +/// any branch fixups on the cleanup. +void CIRGenFunction::popCleanupBlock() { + assert(!ehStack.cleanupStack.empty() && "cleanup stack is empty!"); + mlir::OpBuilder::InsertionGuard guard(builder); + std::unique_ptr<EHScopeStack::Cleanup> cleanup = + ehStack.cleanupStack.pop_back_val(); + + assert(!cir::MissingFeatures::ehCleanupFlags()); + mlir::Block *cleanupEntry = getCurCleanupBlock(*this); + builder.setInsertionPointToEnd(cleanupEntry); + cleanup->emit(*this); +} + +/// Pops cleanup blocks until the given savepoint is reached. +void CIRGenFunction::popCleanupBlocks(size_t oldCleanupStackDepth) { + assert(!cir::MissingFeatures::ehstackBranches()); + + assert(ehStack.getStackDepth() >= oldCleanupStackDepth); + + // Pop cleanup blocks until we reach the base stack depth for the + // current scope. + while (ehStack.getStackDepth() > oldCleanupStackDepth) { + popCleanupBlock(); + } +} diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index afbe92a..a28ac3c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -183,8 +183,8 @@ void CIRGenFunction::emitAutoVarCleanups( const VarDecl &d = *emission.Variable; // Check the type for a cleanup. - if (d.needsDestruction(getContext())) - cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: type cleanup"); + if (QualType::DestructionKind dtorKind = d.needsDestruction(getContext())) + emitAutoVarTypeCleanup(emission, dtorKind); assert(!cir::MissingFeatures::opAllocaPreciseLifetime()); @@ -648,3 +648,96 @@ void CIRGenFunction::emitNullabilityCheck(LValue lhs, mlir::Value rhs, assert(!cir::MissingFeatures::sanitizers()); } + +/// Immediately perform the destruction of the given object. +/// +/// \param addr - the address of the object; a type* +/// \param type - the type of the object; if an array type, all +/// objects are destroyed in reverse order +/// \param destroyer - the function to call to destroy individual +/// elements +void CIRGenFunction::emitDestroy(Address addr, QualType type, + Destroyer *destroyer) { + if (getContext().getAsArrayType(type)) + cgm.errorNYI("emitDestroy: array type"); + + return destroyer(*this, addr, type); +} + +CIRGenFunction::Destroyer * +CIRGenFunction::getDestroyer(QualType::DestructionKind kind) { + switch (kind) { + case QualType::DK_none: + llvm_unreachable("no destroyer for trivial dtor"); + case QualType::DK_cxx_destructor: + return destroyCXXObject; + case QualType::DK_objc_strong_lifetime: + case QualType::DK_objc_weak_lifetime: + case QualType::DK_nontrivial_c_struct: + cgm.errorNYI("getDestroyer: other destruction kind"); + return nullptr; + } + llvm_unreachable("Unknown DestructionKind"); +} + +namespace { +struct DestroyObject final : EHScopeStack::Cleanup { + DestroyObject(Address addr, QualType type, + CIRGenFunction::Destroyer *destroyer) + : addr(addr), type(type), destroyer(destroyer) {} + + Address addr; + QualType type; + CIRGenFunction::Destroyer *destroyer; + + void emit(CIRGenFunction &cgf) override { + cgf.emitDestroy(addr, type, destroyer); + } +}; +} // namespace + +/// Enter a destroy cleanup for the given local variable. +void CIRGenFunction::emitAutoVarTypeCleanup( + const CIRGenFunction::AutoVarEmission &emission, + QualType::DestructionKind dtorKind) { + assert(dtorKind != QualType::DK_none); + + // Note that for __block variables, we want to destroy the + // original stack object, not the possibly forwarded object. + Address addr = emission.getObjectAddress(*this); + + const VarDecl *var = emission.Variable; + QualType type = var->getType(); + + CleanupKind cleanupKind = NormalAndEHCleanup; + CIRGenFunction::Destroyer *destroyer = nullptr; + + switch (dtorKind) { + case QualType::DK_none: + llvm_unreachable("no cleanup for trivially-destructible variable"); + + case QualType::DK_cxx_destructor: + // If there's an NRVO flag on the emission, we need a different + // cleanup. + if (emission.NRVOFlag) { + cgm.errorNYI(var->getSourceRange(), "emitAutoVarTypeCleanup: NRVO"); + return; + } + // Otherwise, this is handled below. + break; + + case QualType::DK_objc_strong_lifetime: + case QualType::DK_objc_weak_lifetime: + case QualType::DK_nontrivial_c_struct: + cgm.errorNYI(var->getSourceRange(), + "emitAutoVarTypeCleanup: other dtor kind"); + return; + } + + // If we haven't chosen a more specific destroyer, use the default. + if (!destroyer) + destroyer = getDestroyer(dtorKind); + + assert(!cir::MissingFeatures::ehCleanupFlags()); + ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 1f64801..7ff5f26 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1657,37 +1657,38 @@ void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, return; } - if (getContext().getAsArrayType(e->getType())) { - cgm.errorNYI(e->getSourceRange(), "emitCXXConstructExpr: array type"); - return; - } + if (const ArrayType *arrayType = getContext().getAsArrayType(e->getType())) { + assert(!cir::MissingFeatures::sanitizers()); + emitCXXAggrConstructorCall(cd, arrayType, dest.getAddress(), e, false); + } else { - clang::CXXCtorType type = Ctor_Complete; - bool forVirtualBase = false; - bool delegating = false; - - switch (e->getConstructionKind()) { - case CXXConstructionKind::Complete: - type = Ctor_Complete; - break; - case CXXConstructionKind::Delegating: - // We should be emitting a constructor; GlobalDecl will assert this - type = curGD.getCtorType(); - delegating = true; - break; - case CXXConstructionKind::VirtualBase: - // This should just set 'forVirtualBase' to true and fall through, but - // virtual base class support is otherwise missing, so this needs to wait - // until it can be tested. - cgm.errorNYI(e->getSourceRange(), - "emitCXXConstructExpr: virtual base constructor"); - return; - case CXXConstructionKind::NonVirtualBase: - type = Ctor_Base; - break; - } + clang::CXXCtorType type = Ctor_Complete; + bool forVirtualBase = false; + bool delegating = false; - emitCXXConstructorCall(cd, type, forVirtualBase, delegating, dest, e); + switch (e->getConstructionKind()) { + case CXXConstructionKind::Complete: + type = Ctor_Complete; + break; + case CXXConstructionKind::Delegating: + // We should be emitting a constructor; GlobalDecl will assert this + type = curGD.getCtorType(); + delegating = true; + break; + case CXXConstructionKind::VirtualBase: + // This should just set 'forVirtualBase' to true and fall through, but + // virtual base class support is otherwise missing, so this needs to wait + // until it can be tested. + cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: virtual base constructor"); + return; + case CXXConstructionKind::NonVirtualBase: + type = Ctor_Base; + break; + } + + emitCXXConstructorCall(cd, type, forVirtualBase, delegating, dest, e); + } } RValue CIRGenFunction::emitReferenceBindingToExpr(const Expr *e) { diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 6756a7c..7f2e2ce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -34,11 +34,20 @@ public: } mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc); + /// Store the specified real/imag parts into the /// specified value pointer. void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv, bool isInit); + /// Emit a cast from complex value Val to DestType. + mlir::Value emitComplexToComplexCast(mlir::Value value, QualType srcType, + QualType destType, SourceLocation loc); + + /// Emit a cast from scalar value Val to DestType. + mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType, + QualType destType, SourceLocation loc); + mlir::Value VisitAbstractConditionalOperator(const AbstractConditionalOperator *e); mlir::Value VisitArraySubscriptExpr(Expr *e); @@ -164,14 +173,110 @@ LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, QualType destTy) { switch (ck) { + case CK_Dependent: + llvm_unreachable("dependent type must be resolved before the CIR codegen"); + case CK_NoOp: case CK_LValueToRValue: return Visit(op); - default: - break; + + case CK_AtomicToNonAtomic: + case CK_NonAtomicToAtomic: + case CK_UserDefinedConversion: { + cgf.cgm.errorNYI( + "ComplexExprEmitter::emitCast Atmoic & UserDefinedConversion"); + return {}; } - cgf.cgm.errorNYI("ComplexType Cast"); - return {}; + + case CK_LValueBitCast: { + cgf.cgm.errorNYI("ComplexExprEmitter::emitCast CK_LValueBitCast"); + return {}; + } + + case CK_LValueToRValueBitCast: { + LValue sourceLVal = cgf.emitLValue(op); + Address addr = sourceLVal.getAddress().withElementType( + builder, cgf.convertTypeForMem(destTy)); + LValue destLV = cgf.makeAddrLValue(addr, destTy); + assert(!cir::MissingFeatures::opTBAA()); + return emitLoadOfLValue(destLV, op->getExprLoc()); + } + + case CK_BitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_BooleanToSignedIntegral: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: + case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: + case CK_ZeroToOCLOpaqueType: + case CK_AddressSpaceConversion: + case CK_IntToOCLSampler: + case CK_FloatingToFixedPoint: + case CK_FixedPointToFloating: + case CK_FixedPointCast: + case CK_FixedPointToBoolean: + case CK_FixedPointToIntegral: + case CK_IntegralToFixedPoint: + case CK_MatrixCast: + case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: + case CK_HLSLElementwiseCast: + case CK_HLSLAggregateSplatCast: + llvm_unreachable("invalid cast kind for complex value"); + + case CK_FloatingRealToComplex: + case CK_IntegralRealToComplex: { + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + return emitScalarToComplexCast(cgf.emitScalarExpr(op), op->getType(), + destTy, op->getExprLoc()); + } + + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: { + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + return emitComplexToComplexCast(Visit(op), op->getType(), destTy, + op->getExprLoc()); + } + } + + llvm_unreachable("unknown cast resulting in complex value"); } mlir::Value ComplexExprEmitter::emitConstant( @@ -207,6 +312,49 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, builder.createStore(loc, val, destAddr); } +mlir::Value ComplexExprEmitter::emitComplexToComplexCast(mlir::Value val, + QualType srcType, + QualType destType, + SourceLocation loc) { + if (srcType == destType) + return val; + + // Get the src/dest element type. + QualType srcElemTy = srcType->castAs<ComplexType>()->getElementType(); + QualType destElemTy = destType->castAs<ComplexType>()->getElementType(); + + cir::CastKind castOpKind; + if (srcElemTy->isFloatingType() && destElemTy->isFloatingType()) + castOpKind = cir::CastKind::float_complex; + else if (srcElemTy->isFloatingType() && destElemTy->isIntegerType()) + castOpKind = cir::CastKind::float_complex_to_int_complex; + else if (srcElemTy->isIntegerType() && destElemTy->isFloatingType()) + castOpKind = cir::CastKind::int_complex_to_float_complex; + else if (srcElemTy->isIntegerType() && destElemTy->isIntegerType()) + castOpKind = cir::CastKind::int_complex; + else + llvm_unreachable("unexpected src type or dest type"); + + return builder.createCast(cgf.getLoc(loc), castOpKind, val, + cgf.convertType(destType)); +} + +mlir::Value ComplexExprEmitter::emitScalarToComplexCast(mlir::Value val, + QualType srcType, + QualType destType, + SourceLocation loc) { + cir::CastKind castOpKind; + if (srcType->isFloatingType()) + castOpKind = cir::CastKind::float_to_complex; + else if (srcType->isIntegerType()) + castOpKind = cir::CastKind::int_to_complex; + else + llvm_unreachable("unexpected src type"); + + return builder.createCast(cgf.getLoc(loc), castOpKind, val, + cgf.convertType(destType)); +} + mlir::Value ComplexExprEmitter::VisitAbstractConditionalOperator( const AbstractConditionalOperator *e) { mlir::Value condValue = Visit(e->getCond()); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index eba6bff..2523b0f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -88,6 +88,10 @@ public: // Utilities //===--------------------------------------------------------------------===// + mlir::Value emitComplexToScalarConversion(mlir::Location loc, + mlir::Value value, CastKind kind, + QualType destTy); + mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) { return builder.createFloatingCast(result, cgf.convertType(promotionType)); } @@ -1125,7 +1129,7 @@ LValue ScalarExprEmitter::emitCompoundAssignLValue( // 'An assignment expression has the value of the left operand after the // assignment...'. if (lhsLV.isBitField()) - cgf.cgm.errorNYI(e->getSourceRange(), "store through bitfield lvalue"); + cgf.emitStoreThroughBitfieldLValue(RValue::get(result), lhsLV); else cgf.emitStoreThroughLValue(RValue::get(result), lhsLV); @@ -1135,6 +1139,31 @@ LValue ScalarExprEmitter::emitCompoundAssignLValue( return lhsLV; } +mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov, + mlir::Value value, + CastKind kind, + QualType destTy) { + cir::CastKind castOpKind; + switch (kind) { + case CK_FloatingComplexToReal: + castOpKind = cir::CastKind::float_complex_to_real; + break; + case CK_IntegralComplexToReal: + castOpKind = cir::CastKind::int_complex_to_real; + break; + case CK_FloatingComplexToBoolean: + castOpKind = cir::CastKind::float_complex_to_bool; + break; + case CK_IntegralComplexToBoolean: + castOpKind = cir::CastKind::int_complex_to_bool; + break; + default: + llvm_unreachable("invalid complex-to-scalar cast kind"); + } + + return builder.createCast(lov, castOpKind, value, cgf.convertType(destTy)); +} + mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e, QualType promotionType) { e = e->IgnoreParens(); @@ -1758,6 +1787,15 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { ce->getExprLoc(), opts); } + case CK_FloatingComplexToReal: + case CK_IntegralComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: { + mlir::Value value = cgf.emitComplexExpr(subExpr); + return emitComplexToScalarConversion(cgf.getLoc(ce->getExprLoc()), value, + kind, destTy); + } + case CK_FloatingRealToComplex: case CK_FloatingComplexCast: case CK_IntegralRealToComplex: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 3e69e56..b4b95d6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -26,7 +26,11 @@ namespace clang::CIRGen { CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext) - : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {} + : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) { + ehStack.setCGF(this); + currentCleanupStackDepth = 0; + assert(ehStack.getStackDepth() == 0); +} CIRGenFunction::~CIRGenFunction() {} @@ -227,6 +231,14 @@ void CIRGenFunction::LexicalScope::cleanup() { CIRGenBuilderTy &builder = cgf.builder; LexicalScope *localScope = cgf.curLexScope; + auto applyCleanup = [&]() { + if (performCleanup) { + // ApplyDebugLocation + assert(!cir::MissingFeatures::generateDebugInfo()); + forceCleanup(); + } + }; + if (returnBlock != nullptr) { // Write out the return block, which loads the value from `__retval` and // issues the `cir.return`. @@ -235,32 +247,42 @@ void CIRGenFunction::LexicalScope::cleanup() { (void)emitReturn(*returnLoc); } - mlir::Block *curBlock = builder.getBlock(); - if (isGlobalInit() && !curBlock) - return; - if (curBlock->mightHaveTerminator() && curBlock->getTerminator()) - return; - - // Get rid of any empty block at the end of the scope. - bool entryBlock = builder.getInsertionBlock()->isEntryBlock(); - if (!entryBlock && curBlock->empty()) { - curBlock->erase(); - if (returnBlock != nullptr && returnBlock->getUses().empty()) - returnBlock->erase(); - return; - } - - // Reached the end of the scope. - { + auto insertCleanupAndLeave = [&](mlir::Block *insPt) { mlir::OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToEnd(curBlock); + builder.setInsertionPointToEnd(insPt); + + // If we still don't have a cleanup block, it means that `applyCleanup` + // below might be able to get us one. + mlir::Block *cleanupBlock = localScope->getCleanupBlock(builder); + + // Leverage and defers to RunCleanupsScope's dtor and scope handling. + applyCleanup(); + + // If we now have one after `applyCleanup`, hook it up properly. + if (!cleanupBlock && localScope->getCleanupBlock(builder)) { + cleanupBlock = localScope->getCleanupBlock(builder); + builder.create<cir::BrOp>(insPt->back().getLoc(), cleanupBlock); + if (!cleanupBlock->mightHaveTerminator()) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToEnd(cleanupBlock); + builder.create<cir::YieldOp>(localScope->endLoc); + } + } if (localScope->depth == 0) { // Reached the end of the function. if (returnBlock != nullptr) { - if (returnBlock->getUses().empty()) + if (returnBlock->getUses().empty()) { returnBlock->erase(); - else { + } else { + // Thread return block via cleanup block. + if (cleanupBlock) { + for (mlir::BlockOperand &blockUse : returnBlock->getUses()) { + cir::BrOp brOp = mlir::cast<cir::BrOp>(blockUse.getOwner()); + brOp.setSuccessor(cleanupBlock); + } + } + builder.create<cir::BrOp>(*returnLoc, returnBlock); return; } @@ -268,13 +290,50 @@ void CIRGenFunction::LexicalScope::cleanup() { emitImplicitReturn(); return; } - // Reached the end of a non-function scope. Some scopes, such as those - // used with the ?: operator, can return a value. - if (!localScope->isTernary() && !curBlock->mightHaveTerminator()) { + + // End of any local scope != function + // Ternary ops have to deal with matching arms for yielding types + // and do return a value, it must do its own cir.yield insertion. + if (!localScope->isTernary() && !insPt->mightHaveTerminator()) { !retVal ? builder.create<cir::YieldOp>(localScope->endLoc) : builder.create<cir::YieldOp>(localScope->endLoc, retVal); } + }; + + // If a cleanup block has been created at some point, branch to it + // and set the insertion point to continue at the cleanup block. + // Terminators are then inserted either in the cleanup block or + // inline in this current block. + mlir::Block *cleanupBlock = localScope->getCleanupBlock(builder); + if (cleanupBlock) + insertCleanupAndLeave(cleanupBlock); + + // Now deal with any pending block wrap up like implicit end of + // scope. + + mlir::Block *curBlock = builder.getBlock(); + if (isGlobalInit() && !curBlock) + return; + if (curBlock->mightHaveTerminator() && curBlock->getTerminator()) + return; + + // Get rid of any empty block at the end of the scope. + bool entryBlock = builder.getInsertionBlock()->isEntryBlock(); + if (!entryBlock && curBlock->empty()) { + curBlock->erase(); + if (returnBlock != nullptr && returnBlock->getUses().empty()) + returnBlock->erase(); + return; } + + // If there's a cleanup block, branch to it, nothing else to do. + if (cleanupBlock) { + builder.create<cir::BrOp>(curBlock->back().getLoc(), cleanupBlock); + return; + } + + // No pre-existent cleanup block, emit cleanup code and yield/return. + insertCleanupAndLeave(curBlock); } cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) { @@ -408,7 +467,19 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType, } } -void CIRGenFunction::finishFunction(SourceLocation endLoc) {} +void CIRGenFunction::finishFunction(SourceLocation endLoc) { + // Pop any cleanups that might have been associated with the + // parameters. Do this in whatever block we're currently in; it's + // important to do this before we enter the return block or return + // edges will be *really* confused. + // TODO(cir): Use prologueCleanupDepth here. + bool hasCleanups = ehStack.getStackDepth() != currentCleanupStackDepth; + if (hasCleanups) { + assert(!cir::MissingFeatures::generateDebugInfo()); + // FIXME(cir): should we clearInsertionPoint? breaks many testcases + popCleanupBlocks(currentCleanupStackDepth); + } +} mlir::LogicalResult CIRGenFunction::emitFunctionBody(const clang::Stmt *body) { auto result = mlir::LogicalResult::success(); @@ -808,4 +879,48 @@ bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) { return true; } +/// Computes the length of an array in elements, as well as the base +/// element type and a properly-typed first element pointer. +mlir::Value +CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, + QualType &baseType, Address &addr) { + const clang::ArrayType *arrayType = origArrayType; + + // If it's a VLA, we have to load the stored size. Note that + // this is the size of the VLA in bytes, not its size in elements. + if (isa<VariableArrayType>(arrayType)) { + assert(cir::MissingFeatures::vlas()); + cgm.errorNYI(*currSrcLoc, "VLAs"); + return builder.getConstInt(*currSrcLoc, SizeTy, 0); + } + + uint64_t countFromCLAs = 1; + QualType eltType; + + auto cirArrayType = mlir::dyn_cast<cir::ArrayType>(addr.getElementType()); + + while (cirArrayType) { + assert(isa<ConstantArrayType>(arrayType)); + countFromCLAs *= cirArrayType.getSize(); + eltType = arrayType->getElementType(); + + cirArrayType = + mlir::dyn_cast<cir::ArrayType>(cirArrayType.getElementType()); + + arrayType = getContext().getAsArrayType(arrayType->getElementType()); + assert((!cirArrayType || arrayType) && + "CIR and Clang types are out-of-sync"); + } + + if (arrayType) { + // From this point onwards, the Clang array type has been emitted + // as some other type (probably a packed struct). Compute the array + // size, and just emit the 'begin' expression as a bitcast. + cgm.errorNYI(*currSrcLoc, "length for non-array underlying types"); + } + + baseType = eltType; + return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 2aceeef..4891c74 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -18,6 +18,7 @@ #include "CIRGenModule.h" #include "CIRGenTypeCache.h" #include "CIRGenValue.h" +#include "EHScopeStack.h" #include "Address.h" @@ -61,6 +62,9 @@ public: /// The compiler-generated variable that holds the return value. std::optional<mlir::Value> fnRetAlloca; + /// Tracks function scope overall cleanup handling. + EHScopeStack ehStack; + /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *cxxabiThisDecl = nullptr; @@ -595,14 +599,65 @@ public: FunctionArgList args, clang::SourceLocation loc, clang::SourceLocation startLoc); + /// Takes the old cleanup stack size and emits the cleanup blocks + /// that have been added. + void popCleanupBlocks(size_t oldCleanupStackDepth); + void popCleanupBlock(); + + /// Enters a new scope for capturing cleanups, all of which + /// will be executed once the scope is exited. + class RunCleanupsScope { + size_t cleanupStackDepth, oldCleanupStackDepth; + + protected: + bool performCleanup; + + private: + RunCleanupsScope(const RunCleanupsScope &) = delete; + void operator=(const RunCleanupsScope &) = delete; + + protected: + CIRGenFunction &cgf; + + /// Enter a new cleanup scope. + explicit RunCleanupsScope(CIRGenFunction &cgf) + : performCleanup(true), cgf(cgf) { + cleanupStackDepth = cgf.ehStack.getStackDepth(); + oldCleanupStackDepth = cgf.currentCleanupStackDepth; + cgf.currentCleanupStackDepth = cleanupStackDepth; + } + + /// Exit this cleanup scope, emitting any accumulated cleanups. + ~RunCleanupsScope() { + if (performCleanup) + forceCleanup(); + } + + /// Force the emission of cleanups now, instead of waiting + /// until this object is destroyed. + void forceCleanup() { + assert(performCleanup && "Already forced cleanup"); + { + mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder()); + cgf.popCleanupBlocks(cleanupStackDepth); + performCleanup = false; + cgf.currentCleanupStackDepth = oldCleanupStackDepth; + } + } + }; + + // Cleanup stack depth of the RunCleanupsScope that was pushed most recently. + size_t currentCleanupStackDepth; + +public: /// Represents a scope, including function bodies, compound statements, and /// the substatements of if/while/do/for/switch/try statements. This class /// handles any automatic cleanup, along with the return value. - struct LexicalScope { + struct LexicalScope : public RunCleanupsScope { private: - // TODO(CIR): This will live in the base class RunCleanupScope once that - // class is upstreamed. - CIRGenFunction &cgf; + // Block containing cleanup code for things initialized in this + // lexical context (scope). + mlir::Block *cleanupBlock = nullptr; // Points to the scope entry block. This is useful, for instance, for // helping to insert allocas before finalizing any recursive CodeGen from @@ -632,8 +687,8 @@ public: unsigned depth = 0; LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb) - : cgf(cgf), entryBlock(eb), parentScope(cgf.curLexScope), beginLoc(loc), - endLoc(loc) { + : RunCleanupsScope(cgf), entryBlock(eb), parentScope(cgf.curLexScope), + beginLoc(loc), endLoc(loc) { assert(entryBlock && "LexicalScope requires an entry block"); cgf.curLexScope = this; @@ -671,6 +726,27 @@ public: void setAsSwitch() { scopeKind = Kind::Switch; } void setAsTernary() { scopeKind = Kind::Ternary; } + // Lazy create cleanup block or return what's available. + mlir::Block *getOrCreateCleanupBlock(mlir::OpBuilder &builder) { + if (cleanupBlock) + return cleanupBlock; + cleanupBlock = createCleanupBlock(builder); + return cleanupBlock; + } + + mlir::Block *getCleanupBlock(mlir::OpBuilder &builder) { + return cleanupBlock; + } + + mlir::Block *createCleanupBlock(mlir::OpBuilder &builder) { + // Create the cleanup block but dont hook it up around just yet. + mlir::OpBuilder::InsertionGuard guard(builder); + mlir::Region *r = builder.getBlock() ? builder.getBlock()->getParent() + : &cgf.curFn->getRegion(0); + cleanupBlock = builder.createBlock(r); + return cleanupBlock; + } + // --- // Return handling. // --- @@ -721,6 +797,12 @@ public: LexicalScope *curLexScope = nullptr; + typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty); + + static Destroyer destroyCXXObject; + + Destroyer *getDestroyer(clang::QualType::DestructionKind kind); + /// ---------------------- /// CIR emit functions /// ---------------------- @@ -766,6 +848,8 @@ public: /// even if no aggregate location is provided. RValue emitAnyExprToTemp(const clang::Expr *e); + mlir::Value emitArrayLength(const clang::ArrayType *arrayType, + QualType &baseType, Address &addr); LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e); Address emitArrayToPointerDecay(const Expr *array); @@ -779,6 +863,8 @@ public: void emitAutoVarCleanups(const AutoVarEmission &emission); void emitAutoVarInit(const AutoVarEmission &emission); + void emitAutoVarTypeCleanup(const AutoVarEmission &emission, + clang::QualType::DestructionKind dtorKind); void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl, CXXCtorInitializer *baseInit); @@ -836,6 +922,9 @@ public: LValue emitCompoundLiteralLValue(const CompoundLiteralExpr *e); void emitConstructorBody(FunctionArgList &args); + + void emitDestroy(Address addr, QualType type, Destroyer *destroyer); + void emitDestructorBody(FunctionArgList &args); mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s); @@ -843,6 +932,16 @@ public: void emitCXXConstructExpr(const clang::CXXConstructExpr *e, AggValueSlot dest); + void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, + const clang::ArrayType *arrayType, + Address arrayBegin, const CXXConstructExpr *e, + bool newPointerIsChecked, + bool zeroInitialize = false); + void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, + mlir::Value numElements, Address arrayBase, + const CXXConstructExpr *e, + bool newPointerIsChecked, + bool zeroInitialize); void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, clang::CXXCtorType type, bool forVirtualBase, bool delegating, AggValueSlot thisAVS, diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 6577f5f..e5e4c68 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -113,8 +113,6 @@ static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, GlobalDecl aliasDecl; if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) { - // The assignment is correct here, but other support for this is NYI. - cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: dtor"); aliasDecl = GlobalDecl(dd, Dtor_Complete); } else { const auto *cd = cast<CXXConstructorDecl>(md); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 9193f6f..21bee33 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -409,7 +409,10 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) { } auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc); + // This should emit a branch through the cleanup block if one exists. builder.create<cir::BrOp>(loc, retBlock); + if (ehStack.getStackDepth() != currentCleanupStackDepth) + cgm.errorNYI(s.getSourceRange(), "return with cleanup stack"); builder.createBlock(builder.getBlock()->getParent()); return mlir::success(); diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 03ea60c..ca3a329 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangCIR CIRGenBuilder.cpp CIRGenCall.cpp CIRGenClass.cpp + CIRGenCleanup.cpp CIRGenCXX.cpp CIRGenCXXABI.cpp CIRGenCXXExpr.cpp diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h b/clang/lib/CIR/CodeGen/EHScopeStack.h new file mode 100644 index 0000000..22750ac --- /dev/null +++ b/clang/lib/CIR/CodeGen/EHScopeStack.h @@ -0,0 +1,99 @@ +//===-- EHScopeStack.h - Stack for cleanup CIR generation -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// These classes should be the minimum interface required for other parts of +// CIR CodeGen to emit cleanups. The implementation is in CIRGenCleanup.cpp and +// other implemenentation details that are not widely needed are in +// CIRGenCleanup.h. +// +// TODO(cir): this header should be shared between LLVM and CIR codegen. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H +#define CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang::CIRGen { + +class CIRGenFunction; + +enum CleanupKind : unsigned { + /// Denotes a cleanup that should run when a scope is exited using exceptional + /// control flow (a throw statement leading to stack unwinding, ). + EHCleanup = 0x1, + + /// Denotes a cleanup that should run when a scope is exited using normal + /// control flow (falling off the end of the scope, return, goto, ...). + NormalCleanup = 0x2, + + NormalAndEHCleanup = EHCleanup | NormalCleanup, + + LifetimeMarker = 0x8, + NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup, +}; + +/// A stack of scopes which respond to exceptions, including cleanups +/// and catch blocks. +class EHScopeStack { +public: + /// Information for lazily generating a cleanup. Subclasses must be + /// POD-like: cleanups will not be destructed, and they will be + /// allocated on the cleanup stack and freely copied and moved + /// around. + /// + /// Cleanup implementations should generally be declared in an + /// anonymous namespace. + class Cleanup { + // Anchor the construction vtable. + virtual void anchor(); + + public: + Cleanup(const Cleanup &) = default; + Cleanup(Cleanup &&) {} + Cleanup() = default; + + virtual ~Cleanup() = default; + + /// Emit the cleanup. For normal cleanups, this is run in the + /// same EH context as when the cleanup was pushed, i.e. the + /// immediately-enclosing context of the cleanup scope. For + /// EH cleanups, this is run in a terminate context. + /// + // \param flags cleanup kind. + virtual void emit(CIRGenFunction &cgf) = 0; + }; + + // Classic codegen has a finely tuned custom allocator and a complex stack + // management scheme. We'll probably eventually want to find a way to share + // that implementation. For now, we will use a very simplified implementation + // to get cleanups working. + llvm::SmallVector<std::unique_ptr<Cleanup>, 8> cleanupStack; + +private: + /// The CGF this Stack belong to + CIRGenFunction *cgf = nullptr; + +public: + EHScopeStack() = default; + ~EHScopeStack() = default; + + /// Push a lazily-created cleanup on the stack. + template <class T, class... As> void pushCleanup(CleanupKind kind, As... a) { + cleanupStack.push_back(std::make_unique<T>(a...)); + } + + void setCGF(CIRGenFunction *inCGF) { cgf = inCGF; } + + size_t getStackDepth() const { return cleanupStack.size(); } +}; + +} // namespace clang::CIRGen + +#endif // CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index f0416b6..cd77166 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -489,6 +489,104 @@ LogicalResult cir::CastOp::verify() { return emitOpError() << "requires two types differ in addrspace only"; return success(); } + case cir::CastKind::float_to_complex: { + if (!mlir::isa<cir::FPTypeInterface>(srcType)) + return emitOpError() << "requires !cir.float type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy) + return emitOpError() << "requires !cir.complex type for result"; + if (srcType != resComplexTy.getElementType()) + return emitOpError() << "requires source type match result element type"; + return success(); + } + case cir::CastKind::int_to_complex: { + if (!mlir::isa<cir::IntType>(srcType)) + return emitOpError() << "requires !cir.int type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy) + return emitOpError() << "requires !cir.complex type for result"; + if (srcType != resComplexTy.getElementType()) + return emitOpError() << "requires source type match result element type"; + return success(); + } + case cir::CastKind::float_complex_to_real: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy) + return emitOpError() << "requires !cir.complex type for source"; + if (!mlir::isa<cir::FPTypeInterface>(resType)) + return emitOpError() << "requires !cir.float type for result"; + if (srcComplexTy.getElementType() != resType) + return emitOpError() << "requires source element type match result type"; + return success(); + } + case cir::CastKind::int_complex_to_real: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy) + return emitOpError() << "requires !cir.complex type for source"; + if (!mlir::isa<cir::IntType>(resType)) + return emitOpError() << "requires !cir.int type for result"; + if (srcComplexTy.getElementType() != resType) + return emitOpError() << "requires source element type match result type"; + return success(); + } + case cir::CastKind::float_complex_to_bool: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + if (!mlir::isa<cir::BoolType>(resType)) + return emitOpError() << "requires !cir.bool type for result"; + return success(); + } + case cir::CastKind::int_complex_to_bool: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + if (!mlir::isa<cir::BoolType>(resType)) + return emitOpError() << "requires !cir.bool type for result"; + return success(); + } + case cir::CastKind::float_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for result"; + return success(); + } + case cir::CastKind::float_complex_to_int_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for result"; + return success(); + } + case cir::CastKind::int_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for result"; + return success(); + } + case cir::CastKind::int_complex_to_float_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for result"; + return success(); + } default: llvm_unreachable("Unknown CastOp kind?"); } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 8f848c7..cef83ea 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -8,11 +8,14 @@ #include "PassDetail.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h" +#include "clang/CIR/MissingFeatures.h" +#include <iostream> #include <memory> using namespace mlir; @@ -24,11 +27,106 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOperation() override; void runOnOp(mlir::Operation *op); + void lowerCastOp(cir::CastOp op); void lowerUnaryOp(cir::UnaryOp op); + void lowerArrayCtor(ArrayCtor op); + + /// + /// AST related + /// ----------- + + clang::ASTContext *astCtx; + + void setASTContext(clang::ASTContext *c) { astCtx = c; } }; } // namespace +static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, + cir::CastOp op) { + cir::CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + mlir::Value imag = builder.getNullValue(src.getType(), op.getLoc()); + return builder.createComplexCreate(op.getLoc(), src, imag); +} + +static mlir::Value lowerComplexToScalarCast(mlir::MLIRContext &ctx, + cir::CastOp op, + cir::CastKind elemToBoolKind) { + cir::CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + if (!mlir::isa<cir::BoolType>(op.getType())) + return builder.createComplexReal(op.getLoc(), src); + + // Complex cast to bool: (bool)(a+bi) => (bool)a || (bool)b + mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); + mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src); + + cir::BoolType boolTy = builder.getBoolTy(); + mlir::Value srcRealToBool = + builder.createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy); + mlir::Value srcImagToBool = + builder.createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy); + return builder.createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool); +} + +static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, + cir::CastOp op, + cir::CastKind scalarCastKind) { + CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + auto dstComplexElemTy = + mlir::cast<cir::ComplexType>(op.getType()).getElementType(); + + mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); + mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src); + + mlir::Value dstReal = builder.createCast(op.getLoc(), scalarCastKind, srcReal, + dstComplexElemTy); + mlir::Value dstImag = builder.createCast(op.getLoc(), scalarCastKind, srcImag, + dstComplexElemTy); + return builder.createComplexCreate(op.getLoc(), dstReal, dstImag); +} + +void LoweringPreparePass::lowerCastOp(cir::CastOp op) { + mlir::MLIRContext &ctx = getContext(); + mlir::Value loweredValue = [&]() -> mlir::Value { + switch (op.getKind()) { + case cir::CastKind::float_to_complex: + case cir::CastKind::int_to_complex: + return lowerScalarToComplexCast(ctx, op); + case cir::CastKind::float_complex_to_real: + case cir::CastKind::int_complex_to_real: + return lowerComplexToScalarCast(ctx, op, op.getKind()); + case cir::CastKind::float_complex_to_bool: + return lowerComplexToScalarCast(ctx, op, cir::CastKind::float_to_bool); + case cir::CastKind::int_complex_to_bool: + return lowerComplexToScalarCast(ctx, op, cir::CastKind::int_to_bool); + case cir::CastKind::float_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::floating); + case cir::CastKind::float_complex_to_int_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::float_to_int); + case cir::CastKind::int_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::integral); + case cir::CastKind::int_complex_to_float_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::int_to_float); + default: + return nullptr; + } + }(); + + if (loweredValue) { + op.replaceAllUsesWith(loweredValue); + op.erase(); + } +} + void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { mlir::Type ty = op.getType(); if (!mlir::isa<cir::ComplexType>(ty)) @@ -71,8 +169,85 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { op.erase(); } +static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, + clang::ASTContext *astCtx, + mlir::Operation *op, mlir::Type eltTy, + mlir::Value arrayAddr, + uint64_t arrayLen) { + // Generate loop to call into ctor/dtor for every element. + mlir::Location loc = op->getLoc(); + + // TODO: instead of fixed integer size, create alias for PtrDiffTy and unify + // with CIRGen stuff. + const unsigned sizeTypeSize = + astCtx->getTypeSize(astCtx->getSignedSizeType()); + auto ptrDiffTy = + cir::IntType::get(builder.getContext(), sizeTypeSize, /*isSigned=*/false); + mlir::Value numArrayElementsConst = builder.getUnsignedInt(loc, arrayLen, 64); + + auto begin = builder.create<cir::CastOp>( + loc, eltTy, cir::CastKind::array_to_ptrdecay, arrayAddr); + mlir::Value end = builder.create<cir::PtrStrideOp>(loc, eltTy, begin, + numArrayElementsConst); + + mlir::Value tmpAddr = builder.createAlloca( + loc, /*addr type*/ builder.getPointerTo(eltTy), + /*var type*/ eltTy, "__array_idx", builder.getAlignmentAttr(1)); + builder.createStore(loc, begin, tmpAddr); + + cir::DoWhileOp loop = builder.createDoWhile( + loc, + /*condBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = b.create<cir::LoadOp>(loc, eltTy, tmpAddr); + mlir::Type boolTy = cir::BoolType::get(b.getContext()); + auto cmp = builder.create<cir::CmpOp>(loc, boolTy, cir::CmpOpKind::ne, + currentElement, end); + builder.createCondition(cmp); + }, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = b.create<cir::LoadOp>(loc, eltTy, tmpAddr); + + cir::CallOp ctorCall; + op->walk([&](cir::CallOp c) { ctorCall = c; }); + assert(ctorCall && "expected ctor call"); + + auto one = builder.create<cir::ConstantOp>( + loc, ptrDiffTy, cir::IntAttr::get(ptrDiffTy, 1)); + + ctorCall->moveAfter(one); + ctorCall->setOperand(0, currentElement); + + // Advance pointer and store them to temporary variable + auto nextElement = + builder.create<cir::PtrStrideOp>(loc, eltTy, currentElement, one); + builder.createStore(loc, nextElement, tmpAddr); + builder.createYield(loc); + }); + + op->replaceAllUsesWith(loop); + op->erase(); +} + +void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { + cir::CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op.getOperation()); + + mlir::Type eltTy = op->getRegion(0).getArgument(0).getType(); + assert(!cir::MissingFeatures::vlas()); + auto arrayLen = + mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); + lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), + arrayLen); +} + void LoweringPreparePass::runOnOp(mlir::Operation *op) { - if (auto unary = dyn_cast<cir::UnaryOp>(op)) + if (auto arrayCtor = dyn_cast<ArrayCtor>(op)) + lowerArrayCtor(arrayCtor); + else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) + lowerCastOp(cast); + else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); } @@ -82,7 +257,7 @@ void LoweringPreparePass::runOnOperation() { llvm::SmallVector<mlir::Operation *> opsToTransform; op->walk([&](mlir::Operation *op) { - if (mlir::isa<cir::UnaryOp>(op)) + if (mlir::isa<cir::ArrayCtor, cir::CastOp, cir::UnaryOp>(op)) opsToTransform.push_back(op); }); @@ -93,3 +268,10 @@ void LoweringPreparePass::runOnOperation() { std::unique_ptr<Pass> mlir::createLoweringPreparePass() { return std::make_unique<LoweringPreparePass>(); } + +std::unique_ptr<Pass> +mlir::createLoweringPreparePass(clang::ASTContext *astCtx) { + auto pass = std::make_unique<LoweringPreparePass>(); + pass->setASTContext(astCtx); + return std::move(pass); +} diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp index 5607abc..bb9781b 100644 --- a/clang/lib/CIR/Lowering/CIRPasses.cpp +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -31,7 +31,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, if (enableCIRSimplify) pm.addPass(mlir::createCIRSimplifyPass()); - pm.addPass(mlir::createLoweringPreparePass()); + pm.addPass(mlir::createLoweringPreparePass(&astContext)); pm.enableVerifier(enableVerifier); (void)mlir::applyPassManagerCLOptions(pm); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 0bceece..d9bd443 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2852,20 +2852,28 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, if (AI.getInReg()) Attrs.addAttribute(llvm::Attribute::InReg); - // Depending on the ABI, this may be either a byval or a dead_on_return - // argument. - if (AI.getIndirectByVal()) { - Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); - } else { - // Add dead_on_return when the object's lifetime ends in the callee. - // This includes trivially-destructible objects, as well as objects - // whose destruction / clean-up is carried out within the callee (e.g., - // Obj-C ARC-managed structs, MSVC callee-destroyed objects). - if (!ParamType.isDestructedType() || !ParamType->isRecordType() || - ParamType->castAs<RecordType>() - ->getDecl() - ->isParamDestroyedInCallee()) - Attrs.addAttribute(llvm::Attribute::DeadOnReturn); + // HLSL out and inout parameters must not be marked with ByVal or + // DeadOnReturn attributes because stores to these parameters by the + // callee are visible to the caller. + if (auto ParamABI = FI.getExtParameterInfo(ArgNo).getABI(); + ParamABI != ParameterABI::HLSLOut && + ParamABI != ParameterABI::HLSLInOut) { + + // Depending on the ABI, this may be either a byval or a dead_on_return + // argument. + if (AI.getIndirectByVal()) { + Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); + } else { + // Add dead_on_return when the object's lifetime ends in the callee. + // This includes trivially-destructible objects, as well as objects + // whose destruction / clean-up is carried out within the callee + // (e.g., Obj-C ARC-managed structs, MSVC callee-destroyed objects). + if (!ParamType.isDestructedType() || !ParamType->isRecordType() || + ParamType->castAs<RecordType>() + ->getDecl() + ->isParamDestroyedInCallee()) + Attrs.addAttribute(llvm::Attribute::DeadOnReturn); + } } auto *Decl = ParamType->getAsRecordDecl(); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 359e30c..b8238a4 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -2146,30 +2146,9 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { return; } - // We might be deleting a pointer to array. If so, GEP down to the - // first non-array element. - // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*) - if (DeleteTy->isConstantArrayType()) { - llvm::Value *Zero = Builder.getInt32(0); - SmallVector<llvm::Value*,8> GEP; - - GEP.push_back(Zero); // point at the outermost array - - // For each layer of array type we're pointing at: - while (const ConstantArrayType *Arr - = getContext().getAsConstantArrayType(DeleteTy)) { - // 1. Unpeel the array type. - DeleteTy = Arr->getElementType(); - - // 2. GEP to the first element of the array. - GEP.push_back(Zero); - } - - Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, ConvertTypeForMem(DeleteTy), - Ptr.getAlignment(), "del.first"); - } - - assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); + // We might be deleting a pointer to array. + DeleteTy = getContext().getBaseElementType(DeleteTy); + Ptr = Ptr.withElementType(ConvertTypeForMem(DeleteTy)); if (E->isArrayForm()) { EmitArrayDelete(*this, E, Ptr, DeleteTy); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index ce2dd4d..91237cf 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -7080,6 +7080,110 @@ private: return ConstLength.getSExtValue() != 1; } + /// A helper class to copy structures with overlapped elements, i.e. those + /// which have mappings of both "s" and "s.mem". Consecutive elements that + /// are not explicitly copied have mapping nodes synthesized for them, + /// taking care to avoid generating zero-sized copies. + class CopyOverlappedEntryGaps { + CodeGenFunction &CGF; + MapCombinedInfoTy &CombinedInfo; + OpenMPOffloadMappingFlags Flags = OpenMPOffloadMappingFlags::OMP_MAP_NONE; + const ValueDecl *MapDecl = nullptr; + const Expr *MapExpr = nullptr; + Address BP = Address::invalid(); + bool IsNonContiguous = false; + uint64_t DimSize = 0; + // These elements track the position as the struct is iterated over + // (in order of increasing element address). + const RecordDecl *LastParent = nullptr; + uint64_t Cursor = 0; + unsigned LastIndex = -1u; + Address LB = Address::invalid(); + + public: + CopyOverlappedEntryGaps(CodeGenFunction &CGF, + MapCombinedInfoTy &CombinedInfo, + OpenMPOffloadMappingFlags Flags, + const ValueDecl *MapDecl, const Expr *MapExpr, + Address BP, Address LB, bool IsNonContiguous, + uint64_t DimSize) + : CGF(CGF), CombinedInfo(CombinedInfo), Flags(Flags), MapDecl(MapDecl), + MapExpr(MapExpr), BP(BP), IsNonContiguous(IsNonContiguous), + DimSize(DimSize), LB(LB) {} + + void processField( + const OMPClauseMappableExprCommon::MappableComponent &MC, + const FieldDecl *FD, + llvm::function_ref<LValue(CodeGenFunction &, const MemberExpr *)> + EmitMemberExprBase) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); + uint64_t FieldOffset = RL.getFieldOffset(FD->getFieldIndex()); + uint64_t FieldSize = + CGF.getContext().getTypeSize(FD->getType().getCanonicalType()); + Address ComponentLB = Address::invalid(); + + if (FD->getType()->isLValueReferenceType()) { + const auto *ME = cast<MemberExpr>(MC.getAssociatedExpression()); + LValue BaseLVal = EmitMemberExprBase(CGF, ME); + ComponentLB = + CGF.EmitLValueForFieldInitialization(BaseLVal, FD).getAddress(); + } else { + ComponentLB = + CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()).getAddress(); + } + + if (!LastParent) + LastParent = RD; + if (FD->getParent() == LastParent) { + if (FD->getFieldIndex() != LastIndex + 1) + copyUntilField(FD, ComponentLB); + } else { + LastParent = FD->getParent(); + if (((int64_t)FieldOffset - (int64_t)Cursor) > 0) + copyUntilField(FD, ComponentLB); + } + Cursor = FieldOffset + FieldSize; + LastIndex = FD->getFieldIndex(); + LB = CGF.Builder.CreateConstGEP(ComponentLB, 1); + } + + void copyUntilField(const FieldDecl *FD, Address ComponentLB) { + llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF); + llvm::Value *LBPtr = LB.emitRawPointer(CGF); + llvm::Value *Size = + CGF.Builder.CreatePtrDiff(CGF.Int8Ty, ComponentLBPtr, LBPtr); + copySizedChunk(LBPtr, Size); + } + + void copyUntilEnd(Address HB) { + if (LastParent) { + const ASTRecordLayout &RL = + CGF.getContext().getASTRecordLayout(LastParent); + if ((uint64_t)CGF.getContext().toBits(RL.getSize()) <= Cursor) + return; + } + llvm::Value *LBPtr = LB.emitRawPointer(CGF); + llvm::Value *Size = CGF.Builder.CreatePtrDiff( + CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), + LBPtr); + copySizedChunk(LBPtr, Size); + } + + void copySizedChunk(llvm::Value *Base, llvm::Value *Size) { + CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); + CombinedInfo.DevicePtrDecls.push_back(nullptr); + CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); + CombinedInfo.Pointers.push_back(Base); + CombinedInfo.Sizes.push_back( + CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true)); + CombinedInfo.Types.push_back(Flags); + CombinedInfo.Mappers.push_back(nullptr); + CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1); + } + }; + /// Generate the base pointers, section pointers, sizes, map type bits, and /// user-defined mappers (all included in \a CombinedInfo) for the provided /// map type, map or motion modifiers, and expression components. @@ -7570,63 +7674,22 @@ private: getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit, /*AddPtrFlag=*/false, /*AddIsTargetParamFlag=*/false, IsNonContiguous); - llvm::Value *Size = nullptr; + CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, MapDecl, + MapExpr, BP, LB, IsNonContiguous, + DimSize); // Do bitcopy of all non-overlapped structure elements. for (OMPClauseMappableExprCommon::MappableExprComponentListRef Component : OverlappedElements) { - Address ComponentLB = Address::invalid(); for (const OMPClauseMappableExprCommon::MappableComponent &MC : Component) { if (const ValueDecl *VD = MC.getAssociatedDeclaration()) { - const auto *FD = dyn_cast<FieldDecl>(VD); - if (FD && FD->getType()->isLValueReferenceType()) { - const auto *ME = - cast<MemberExpr>(MC.getAssociatedExpression()); - LValue BaseLVal = EmitMemberExprBase(CGF, ME); - ComponentLB = - CGF.EmitLValueForFieldInitialization(BaseLVal, FD) - .getAddress(); - } else { - ComponentLB = - CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()) - .getAddress(); + if (const auto *FD = dyn_cast<FieldDecl>(VD)) { + CopyGaps.processField(MC, FD, EmitMemberExprBase); } - llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF); - llvm::Value *LBPtr = LB.emitRawPointer(CGF); - Size = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, ComponentLBPtr, - LBPtr); - break; } } - assert(Size && "Failed to determine structure size"); - CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); - CombinedInfo.DevicePtrDecls.push_back(nullptr); - CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); - CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( - Size, CGF.Int64Ty, /*isSigned=*/true)); - CombinedInfo.Types.push_back(Flags); - CombinedInfo.Mappers.push_back(nullptr); - CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize - : 1); - LB = CGF.Builder.CreateConstGEP(ComponentLB, 1); } - CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); - CombinedInfo.DevicePtrDecls.push_back(nullptr); - CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); - llvm::Value *LBPtr = LB.emitRawPointer(CGF); - Size = CGF.Builder.CreatePtrDiff( - CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), - LBPtr); - CombinedInfo.Sizes.push_back( - CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true)); - CombinedInfo.Types.push_back(Flags); - CombinedInfo.Mappers.push_back(nullptr); - CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize - : 1); + CopyGaps.copyUntilEnd(HB); break; } llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression()); diff --git a/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp b/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp index 7dccf82..70f510a 100644 --- a/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp @@ -274,7 +274,7 @@ llvm::Value *CodeGenFunction::EmitScalarOrConstFoldImmArg(unsigned ICEArguments, void CodeGenFunction::AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst, const CallExpr *E) { - constexpr const char *Tag = "amdgpu-as"; + constexpr const char *Tag = "amdgpu-synchronize-as"; LLVMContext &Ctx = Inst->getContext(); SmallVector<MMRAMetadata::TagT, 3> MMRAs; @@ -633,6 +633,41 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(IID, {LoadTy}); return Builder.CreateCall(F, {Addr}); } + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b32: + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b64: + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b128: + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b32: + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b64: + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b128: { + + Intrinsic::ID IID; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b32: + IID = Intrinsic::amdgcn_global_load_monitor_b32; + break; + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b64: + IID = Intrinsic::amdgcn_global_load_monitor_b64; + break; + case AMDGPU::BI__builtin_amdgcn_global_load_monitor_b128: + IID = Intrinsic::amdgcn_global_load_monitor_b128; + break; + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b32: + IID = Intrinsic::amdgcn_flat_load_monitor_b32; + break; + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b64: + IID = Intrinsic::amdgcn_flat_load_monitor_b64; + break; + case AMDGPU::BI__builtin_amdgcn_flat_load_monitor_b128: + IID = Intrinsic::amdgcn_flat_load_monitor_b128; + break; + } + + llvm::Type *LoadTy = ConvertType(E->getType()); + llvm::Value *Addr = EmitScalarExpr(E->getArg(0)); + llvm::Value *Val = EmitScalarExpr(E->getArg(1)); + llvm::Function *F = CGM.getIntrinsic(IID, {LoadTy}); + return Builder.CreateCall(F, {Addr, Val}); + } case AMDGPU::BI__builtin_amdgcn_load_to_lds: { // Should this have asan instrumentation? return emitBuiltinWithOneOverloadedType<5>(*this, E, diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e3d220d..853f694 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -209,8 +209,8 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, CCLogDiagnostics(false), CCGenDiagnostics(false), CCPrintProcessStats(false), CCPrintInternalStats(false), TargetTriple(TargetTriple), Saver(Alloc), PrependArg(nullptr), - CheckInputsExist(true), ProbePrecompiled(true), - SuppressMissingInputWarning(false) { + PreferredLinker(CLANG_DEFAULT_LINKER), CheckInputsExist(true), + ProbePrecompiled(true), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) this->VFS = llvm::vfs::getRealFileSystem(); @@ -908,7 +908,7 @@ getSystemOffloadArchs(Compilation &C, Action::OffloadKind Kind) { StringRef Program = C.getArgs().getLastArgValue( options::OPT_offload_arch_tool_EQ, "offload-arch"); - SmallVector<std::string, 1> GPUArchs; + SmallVector<std::string> GPUArchs; if (llvm::ErrorOr<std::string> Executable = llvm::sys::findProgramByName(Program)) { llvm::SmallVector<StringRef> Args{*Executable}; @@ -4886,7 +4886,13 @@ Action *Driver::BuildOffloadingActions(Compilation &C, // Compiling HIP in device-only non-RDC mode requires linking each action // individually. for (Action *&A : DeviceActions) { - if ((A->getType() != types::TY_Object && + // Special handling for the HIP SPIR-V toolchain because it doesn't use + // the SPIR-V backend yet doesn't report the output as an object. + bool IsAMDGCNSPIRV = A->getOffloadingToolChain() && + A->getOffloadingToolChain()->getTriple().getOS() == + llvm::Triple::OSType::AMDHSA && + A->getOffloadingToolChain()->getTriple().isSPIRV(); + if ((A->getType() != types::TY_Object && !IsAMDGCNSPIRV && A->getType() != types::TY_LTO_BC) || !HIPNoRDC || !offloadDeviceOnly()) continue; @@ -4942,8 +4948,9 @@ Action *Driver::BuildOffloadingActions(Compilation &C, // fatbinary for each translation unit, linking each input individually. Action *FatbinAction = C.MakeAction<LinkJobAction>(OffloadActions, types::TY_HIP_FATBIN); - DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_HIP>(), - nullptr, Action::OFK_HIP); + DDep.add(*FatbinAction, + *C.getOffloadToolChains<Action::OFK_HIP>().first->second, nullptr, + Action::OFK_HIP); } else { // Package all the offloading actions into a single output that can be // embedded in the host and linked. @@ -5098,7 +5105,10 @@ Action *Driver::ConstructPhaseAction( false) || (Args.hasFlag(options::OPT_offload_new_driver, options::OPT_no_offload_new_driver, false) && - !offloadDeviceOnly())) || + (!offloadDeviceOnly() || + (Input->getOffloadingToolChain() && + TargetDeviceOffloadKind == Action::OFK_HIP && + Input->getOffloadingToolChain()->getTriple().isSPIRV())))) || TargetDeviceOffloadKind == Action::OFK_OpenMP))) { types::ID Output = Args.hasArg(options::OPT_S) && diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 21e4cff..aa767ae3 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -181,11 +181,11 @@ static void validateSpecialCaseListFormat(const Driver &D, if (SCLFiles.empty()) return; - std::string BLError; + std::pair<unsigned, std::string> BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( llvm::SpecialCaseList::create(SCLFiles, D.getVFS(), BLError)); if (!SCL && DiagnoseErrors) - D.Diag(MalformedSCLErrorDiagID) << BLError; + D.Diag(MalformedSCLErrorDiagID) << BLError.first << BLError.second; } static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 47f93fa1..1d7dad0 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1087,7 +1087,7 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { // Get -fuse-ld= first to prevent -Wunused-command-line-argument. -fuse-ld= is // considered as the linker flavor, e.g. "bfd", "gold", or "lld". const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ); - StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + StringRef UseLinker = A ? A->getValue() : getDriver().getPreferredLinker(); // --ld-path= takes precedence over -fuse-ld= and specifies the executable // name. -B, COMPILER_PATH and PATH and consulted if the value does not diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp index 3333135..94a94f1 100644 --- a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -37,6 +37,13 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, .Case("niagara4", "-Av9d") .Default(DefV9CPU); } else { + const char *DefV8CPU; + + if (Triple.isOSSolaris()) + DefV8CPU = "-Av8plus"; + else + DefV8CPU = "-Av8"; + return llvm::StringSwitch<const char *>(Name) .Case("v8", "-Av8") .Case("supersparc", "-Av8") @@ -72,7 +79,7 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, .Case("gr712rc", "-Aleon") .Case("leon4", "-Aleon") .Case("gr740", "-Aleon") - .Default("-Av8"); + .Default(DefV8CPU); } } @@ -160,6 +167,8 @@ void sparc::getSparcTargetFeatures(const Driver &D, const llvm::Triple &Triple, (Triple.getArch() == llvm::Triple::sparcv9) && (Triple.isOSLinux() || Triple.isOSFreeBSD() || Triple.isOSOpenBSD()); bool IsSparcV9BTarget = Triple.isOSSolaris(); + bool IsSparcV8PlusTarget = + Triple.getArch() == llvm::Triple::sparc && Triple.isOSSolaris(); if (Arg *A = Args.getLastArg(options::OPT_mvis, options::OPT_mno_vis)) { if (A->getOption().matches(options::OPT_mvis)) Features.push_back("+vis"); @@ -196,6 +205,8 @@ void sparc::getSparcTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Arg *A = Args.getLastArg(options::OPT_mv8plus, options::OPT_mno_v8plus)) { if (A->getOption().matches(options::OPT_mv8plus)) Features.push_back("+v8plus"); + } else if (IsSparcV8PlusTarget) { + Features.push_back("+v8plus"); } if (Args.hasArg(options::OPT_ffixed_g1)) diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 7d31eea..bb469ff 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -279,8 +279,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); } - StringRef Linker = - Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); + StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, + TC.getDriver().getPreferredLinker()); if (Linker.empty()) Linker = "link"; // We need to translate 'lld' into 'lld-link'. diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index b2e36ae..6abd0c0 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -548,7 +548,7 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, getFilePaths().push_back(Base + "lib"); NativeLLVMSupport = - Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) + Args.getLastArgValue(options::OPT_fuse_ld_EQ, D.getPreferredLinker()) .equals_insensitive("lld"); } diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index a3574e1..02aa598 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -39,7 +39,7 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) { // Only used if targetting Solaris. const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); - StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + StringRef UseLinker = A ? A->getValue() : TC.getDriver().getPreferredLinker(); return UseLinker == "bfd" || UseLinker == "gld"; } @@ -52,7 +52,7 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) { TC.isPIEDefault(Args)); } -// FIXME: Need to handle CLANG_DEFAULT_LINKER here? +// FIXME: Need to handle PreferredLinker here? std::string solaris::Linker::getLinkerPath(const ArgList &Args) const { const ToolChain &ToolChain = getToolChain(); if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { @@ -345,7 +345,7 @@ SanitizerMask Solaris::getSupportedSanitizers() const { const char *Solaris::getDefaultLinker() const { // FIXME: Only handle Solaris ld and GNU ld here. - return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER) + return llvm::StringSwitch<const char *>(getDriver().getPreferredLinker()) .Cases("bfd", "gld", "/usr/gnu/bin/ld") .Default("/usr/bin/ld"); } diff --git a/clang/lib/Driver/ToolChains/UEFI.cpp b/clang/lib/Driver/ToolChains/UEFI.cpp index ac6668e..2b41173 100644 --- a/clang/lib/Driver/ToolChains/UEFI.cpp +++ b/clang/lib/Driver/ToolChains/UEFI.cpp @@ -83,8 +83,8 @@ void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA, // This should ideally be handled by ToolChain::GetLinkerPath but we need // to special case some linker paths. In the case of lld, we need to // translate 'lld' into 'lld-link'. - StringRef Linker = - Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); + StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, + TC.getDriver().getPreferredLinker()); if (Linker.empty() || Linker == "lld") Linker = "lld-link"; diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index bf67f9e..9a10403 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1725,7 +1725,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, } if (Previous && (Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) || (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) && - !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)))) { + !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr, + TT_CtorInitializerColon)))) { CurrentState.NestedBlockInlined = !Newline && hasNestedBlockInlined(Previous, Current, Style); } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 62feb3d..1cfa3d1 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -731,6 +731,7 @@ template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> { IO.mapOptional("AfterFunctionDeclarationName", Spacing.AfterFunctionDeclarationName); IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); + IO.mapOptional("AfterNot", Spacing.AfterNot); IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); IO.mapOptional("AfterPlacementOperator", Spacing.AfterPlacementOperator); IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause); @@ -2643,13 +2644,14 @@ private: for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { if (Tok->isNot(TT_PointerOrReference)) continue; - // Don't treat space in `void foo() &&` as evidence. + // Don't treat space in `void foo() &&` or `void() &&` as evidence. if (const auto *Prev = Tok->getPreviousNonComment()) { if (Prev->is(tok::r_paren) && Prev->MatchingParen) { if (const auto *Func = Prev->MatchingParen->getPreviousNonComment()) { if (Func->isOneOf(TT_FunctionDeclarationName, TT_StartOfName, - TT_OverloadedOperator)) { + TT_OverloadedOperator) || + Func->isTypeName(LangOpts)) { continue; } } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 581bfba..d28d2fd 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5478,7 +5478,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.TokenText == "!") return Style.SpaceAfterLogicalNot; assert(Left.TokenText == "not"); - return Right.isOneOf(tok::coloncolon, TT_UnaryOperator); + return Right.isOneOf(tok::coloncolon, TT_UnaryOperator) || + (Right.is(tok::l_paren) && Style.SpaceBeforeParensOptions.AfterNot); } // If the next token is a binary operator or a selector name, we have diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c7b82db..bbb856b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -554,6 +554,7 @@ void CompilerInstance::createASTContext() { PP.getBuiltinInfo(), PP.TUKind); Context->InitBuiltinTypes(getTarget(), getAuxTarget()); setASTContext(Context); + Context->initSanitizers(getLangOpts(), PP.getSourceManager()); } // ExternalASTSource diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 893ef02..e47caeb 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5695,11 +5695,10 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { Scope::CompoundStmtScope); TopLevelStmtDecl *TLSD = Actions.ActOnStartTopLevelStmtDecl(getCurScope()); StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get()); if (!R.isUsable()) R = Actions.ActOnNullStmt(Tok.getLocation()); - Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get()); - if (Tok.is(tok::annot_repl_input_end) && Tok.getAnnotationValue() != nullptr) { ConsumeAnnotationToken(); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 31392d1d..bc8841c 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4940,9 +4940,8 @@ void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) { // signature string and construct the in-memory elements if (!Found) { // Invoke the root signature parser to construct the in-memory constructs - SmallVector<hlsl::RootSignatureElement> RootElements; - hlsl::RootSignatureParser Parser(getLangOpts().HLSLRootSigVer, RootElements, - Signature, PP); + hlsl::RootSignatureParser Parser(getLangOpts().HLSLRootSigVer, Signature, + PP); if (Parser.parse()) { T.consumeClose(); return; @@ -4950,7 +4949,7 @@ void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) { // Construct the declaration. Actions.HLSL().ActOnFinishRootSignatureDecl(RootSignatureLoc, DeclIdent, - RootElements); + Parser.getElements()); } // Create the arg for the ParsedAttr diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index db9ed83..98dc458 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -27,11 +27,10 @@ static const TokenKind RootElementKeywords[] = { }; RootSignatureParser::RootSignatureParser( - llvm::dxbc::RootSignatureVersion Version, - SmallVector<RootSignatureElement> &Elements, StringLiteral *Signature, + llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature, Preprocessor &PP) - : Version(Version), Elements(Elements), Signature(Signature), - Lexer(Signature->getString()), PP(PP), CurToken(0) {} + : Version(Version), Signature(Signature), Lexer(Signature->getString()), + PP(PP), CurToken(0) {} bool RootSignatureParser::parse() { // Iterate as many RootSignatureElements as possible, until we hit the diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 8c6a173..68a698f 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -547,6 +547,12 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, return; } case AR_Deprecated: + // Suppress -Wdeprecated-declarations in implicit + // functions. + if (const auto *FD = dyn_cast_or_null<FunctionDecl>(S.getCurFunctionDecl()); + FD && FD->isImplicit()) + return; + if (ObjCPropertyAccess) diag = diag::warn_property_method_deprecated; else if (S.currentEvaluationContext().IsCaseExpr) diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 5205ca0b..044cf5c 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -588,6 +588,9 @@ static bool CheckConstraintSatisfaction( return true; for (const AssociatedConstraint &AC : AssociatedConstraints) { + if (AC.isNull()) + return true; + Sema::ArgPackSubstIndexRAII _(S, AC.ArgPackSubstIndex); ExprResult Res = calculateConstraintSatisfaction( S, Template, TemplateIDRange.getBegin(), TemplateArgsLists, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fd22e01..d7420bd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3267,6 +3267,14 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, if (isa<UsedAttr>(I) || isa<RetainAttr>(I)) continue; + if (isa<InferredNoReturnAttr>(I)) { + if (auto *FD = dyn_cast<FunctionDecl>(New)) { + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + continue; // Don't propagate inferred noreturn attributes to explicit + // specializations. + } + } + if (mergeDeclAttribute(*this, New, I, LocalAMK)) foundAny = true; } @@ -20573,7 +20581,8 @@ TopLevelStmtDecl *Sema::ActOnStartTopLevelStmtDecl(Scope *S) { } void Sema::ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement) { - D->setStmt(Statement); + if (Statement) + D->setStmt(Statement); PopCompoundScope(); PopFunctionScopeInfo(); PopDeclContext(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 9a2950c..a4e8de4 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1970,6 +1970,13 @@ void clang::inferNoReturnAttr(Sema &S, const Decl *D) { if (!FD) return; + // Skip explicit specializations here as they may have + // a user-provided definition that may deliberately differ from the primary + // template. If an explicit specialization truly never returns, the user + // should explicitly mark it with [[noreturn]]. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + auto *NonConstFD = const_cast<FunctionDecl *>(FD); DiagnosticsEngine &Diags = S.getDiagnostics(); if (Diags.isIgnored(diag::warn_falloff_nonvoid, FD->getLocation()) && @@ -2034,7 +2041,8 @@ bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { if (AL.isRegularKeywordAttribute()) - Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target); + Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target) + << AL << AL.getRange(); else DiagnoseUnknownAttribute(AL); AL.setInvalid(); diff --git a/clang/lib/Sema/SemaOpenACCAtomic.cpp b/clang/lib/Sema/SemaOpenACCAtomic.cpp index 9c8c8d1..a9319dc 100644 --- a/clang/lib/Sema/SemaOpenACCAtomic.cpp +++ b/clang/lib/Sema/SemaOpenACCAtomic.cpp @@ -576,6 +576,11 @@ class AtomicOperandChecker { return AssocStmt; } + const Expr *IgnoreBeforeCompare(const Expr *E) { + return E->IgnoreParenImpCasts()->IgnoreParenNoopCasts( + SemaRef.getASTContext()); + } + bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind, const Expr *FirstX, IDACInfo::ExprKindTy SecondKind, const Expr *SecondX) { llvm::FoldingSetNodeID First_ID, Second_ID; @@ -648,8 +653,10 @@ class AtomicOperandChecker { if (CheckOperandVariable(AssignRes->RHS, PD)) return getRecoveryExpr(); - if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var, - IDACInfo::SimpleAssign, AssignRes->RHS)) + if (CheckVarRefsSame(FirstExprResults.ExprKind, + IgnoreBeforeCompare(FirstExprResults.X_Var), + IDACInfo::SimpleAssign, + IgnoreBeforeCompare(AssignRes->RHS))) return getRecoveryExpr(); break; } @@ -660,9 +667,10 @@ class AtomicOperandChecker { if (SecondExprResults.Failed) return getRecoveryExpr(); - if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var, + if (CheckVarRefsSame(FirstExprResults.ExprKind, + IgnoreBeforeCompare(FirstExprResults.X_Var), SecondExprResults.ExprKind, - SecondExprResults.X_Var)) + IgnoreBeforeCompare(SecondExprResults.X_Var))) return getRecoveryExpr(); break; } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 4ecc9b0..2c5d97c 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2829,7 +2829,7 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack, continue; } for (Expr *Ref : RC->varlist()) { - assert(Ref && "NULL expr in OpenMP nontemporal clause."); + assert(Ref && "NULL expr in OpenMP reduction clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = Ref; @@ -7612,6 +7612,23 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( return; } + // OpenMP 6.0 [9.6.2 (page 332, line 31-33, adjust_args clause, Restrictions] + // If the `need_device_addr` adjust-op modifier is present, each list item + // that appears in the clause must refer to an argument in the declaration of + // the function variant that has a reference type + if (getLangOpts().OpenMP >= 60) { + for (Expr *E : AdjustArgsNeedDeviceAddr) { + E = E->IgnoreParenImpCasts(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (!VD->getType()->isReferenceType()) + Diag(E->getExprLoc(), + diag::err_omp_non_by_ref_need_device_addr_modifier_argument); + } + } + } + } + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( getASTContext(), VariantRef, &TI, const_cast<Expr **>(AdjustArgsNothing.data()), AdjustArgsNothing.size(), @@ -18344,7 +18361,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); + assert(RefExpr && "NULL expr in OpenMP shared clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -19991,7 +20008,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAlignedClause( SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP linear clause."); + assert(RefExpr && "NULL expr in OpenMP aligned clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -20167,7 +20184,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP linear clause."); + assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -20526,7 +20543,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDependClause( TotalDepCount = VarOffset.TotalDepCount; } else { for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP depend clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -23737,7 +23754,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAllocateClause( // Analyze and build list of variables. SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP private clause."); + assert(RefExpr && "NULL expr in OpenMP allocate clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -23829,7 +23846,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + assert(RefExpr && "NULL expr in OpenMP inclusive clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -23870,7 +23887,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + assert(RefExpr && "NULL expr in OpenMP exclusive clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -24063,7 +24080,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAffinityClause( SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : Locators) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP affinity clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -24375,7 +24392,7 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr( return ExprError(); } } - } else if (ColonLocFirst.isValid() && + } else if (SemaRef.getLangOpts().OpenMP < 60 && ColonLocFirst.isValid() && (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && !OriginalTy->isVariableArrayType()))) { // OpenMP 5.0, [2.1.5 Array Sections] diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index e1a975b..9e56e697 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5523,6 +5523,15 @@ static TemplateDeductionResult CheckDeductionConsistency( // FIXME: A substitution can be incomplete on a non-structural part of the // type. Use the canonical type for now, until the TemplateInstantiator can // deal with that. + + // Workaround: Implicit deduction guides use InjectedClassNameTypes, whereas + // the explicit guides don't. The substitution doesn't transform these types, + // so let it transform their specializations instead. + bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl()); + if (IsDeductionGuide) { + if (auto *Injected = P->getAs<InjectedClassNameType>()) + P = Injected->getInjectedSpecializationType(); + } QualType InstP = S.SubstType(P.getCanonicalType(), MLTAL, FTD->getLocation(), FTD->getDeclName(), &IsIncompleteSubstitution); if (InstP.isNull() && !IsIncompleteSubstitution) @@ -5537,9 +5546,15 @@ static TemplateDeductionResult CheckDeductionConsistency( if (auto *PA = dyn_cast<PackExpansionType>(A); PA && !isa<PackExpansionType>(InstP)) A = PA->getPattern(); - if (!S.Context.hasSameType( - S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()), - S.Context.getUnqualifiedArrayType(A.getNonReferenceType()))) + auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()); + auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType()); + if (IsDeductionGuide) { + if (auto *Injected = T1->getAs<InjectedClassNameType>()) + T1 = Injected->getInjectedSpecializationType(); + if (auto *Injected = T2->getAs<InjectedClassNameType>()) + T2 = Injected->getInjectedSpecializationType(); + } + if (!S.Context.hasSameType(T1, T2)) return TemplateDeductionResult::NonDeducedMismatch; return TemplateDeductionResult::Success; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 68efdba..a7704da 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -3730,13 +3730,15 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, return nullptr; } - // Save the first destructor/function as release point. - assert(!ReleaseFunctionLC && "There should be only one release point"); + // Record the stack frame that is _responsible_ for this memory release + // event. This will be used by the false positive suppression heuristics + // that recognize the release points of reference-counted objects. + // + // Usually (e.g. in C) we say that the _responsible_ stack frame is the + // current innermost stack frame: ReleaseFunctionLC = CurrentLC->getStackFrame(); - - // See if we're releasing memory while inlining a destructor that - // decrement reference counters (or one of its callees). - // This turns on various common false positive suppressions. + // ...but if the stack contains a destructor call, then we say that the + // outermost destructor stack frame is the _responsible_ one: for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) { if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) { if (isReferenceCountingPointerDestructor(DD)) { diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index 27a04ff..a9828cf 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/test/Analysis/malloc.c @@ -1954,9 +1954,23 @@ int conjure(void); void testExtent(void) { int x = conjure(); clang_analyzer_dump(x); - // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}} + // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC[[:digit:]]+, S[[:digit:]]+, #1}}}}}} int *p = (int *)malloc(x); clang_analyzer_dumpExtent(p); - // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}} + // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC[[:digit:]]+, S[[:digit:]]+, #1}}}}}} free(p); } + +void gh149754(void *p) { + // This testcase demonstrates an unusual situation where a certain symbol + // (the value of `p`) is released (more precisely, transitions from + // untracked state to Released state) twice within the same bug path because + // the `EvalAssume` callback resets it to untracked state after the first + // time when it is released. This caused the failure of an assertion, which + // was since then removed for the codebase. + if (!realloc(p, 8)) { + realloc(p, 8); + free(p); // expected-warning {{Attempt to free released memory}} + } + // expected-warning@+1 {{Potential memory leak}} +} diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp new file mode 100644 index 0000000..b3d81a8 --- /dev/null +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o - 2>&1 | FileCheck --check-prefixes=CIR-BEFORE-LPP %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct S { + S(); +}; + +void foo() { + S s[42]; +} + +// CIR-BEFORE-LPP: cir.func dso_local @_Z3foov() +// CIR-BEFORE-LPP: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] +// CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>> { +// CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>): +// CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: cir.return +// CIR-BEFORE-LPP: } + +// CIR: cir.func dso_local @_Z3foov() +// CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] +// CIR: %[[CONST42:.*]] = cir.const #cir.int<42> : !u64i +// CIR: %[[DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>>), !cir.ptr<!rec_S> +// CIR: %[[END_PTR:.*]] = cir.ptr_stride(%[[DECAY]] : !cir.ptr<!rec_S>, %[[CONST42]] : !u64i), !cir.ptr<!rec_S> +// CIR: %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"] +// CIR: cir.store %[[DECAY]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.do { +// CIR: %[[CURRENT:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i +// CIR: cir.call @_ZN1SC1Ev(%[[CURRENT]]) : (!cir.ptr<!rec_S>) -> () +// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CURRENT]] : !cir.ptr<!rec_S>, %[[CONST1]] : !u64i), !cir.ptr<!rec_S> +// CIR: cir.store %[[NEXT]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CURRENT2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CURRENT2]], %[[END_PTR]]) : !cir.ptr<!rec_S>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define dso_local void @_Z3foov() +// LLVM: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// LLVM: %[[START:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.S, ptr %[[START]], i64 42 +// LLVM: %[[ITER:.*]] = alloca ptr +// LLVM: store ptr %[[START]], ptr %[[ITER]] +// LLVM: br label %[[LOOP:.*]] +// LLVM: [[COND:.*]]: +// LLVM: %[[CURRENT_CHECK:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[DONE:.*]] = icmp ne ptr %[[CURRENT_CHECK]], %[[END]] +// LLVM: br i1 %[[DONE]], label %[[LOOP]], label %[[EXIT:.*]] +// LLVM: [[LOOP]]: +// LLVM: %[[CURRENT:.*]] = load ptr, ptr %[[ITER]] +// LLVM: call void @_ZN1SC1Ev(ptr %[[CURRENT]]) +// LLVM: %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CURRENT]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[ITER]] +// LLVM: br label %[[COND]] +// LLVM: [[EXIT]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z3foov() +// OGCG: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// OGCG: %[[START:.*]] = getelementptr{{.*}} %struct.S{{.*}} +// OGCG: %[[END:.*]] = getelementptr{{.*}} %struct.S{{.*}} i64 42 +// OGCG: br label %[[LOOP:.*]] +// OGCG: [[LOOP]]: +// OGCG: %[[CURRENT:.*]] = phi ptr [ %[[START]], %{{.*}} ], [ %[[NEXT:.*]], %[[LOOP]] ] +// OGCG: call void @_ZN1SC1Ev(ptr{{.*}}) +// OGCG: %[[NEXT]] = getelementptr{{.*}} %struct.S{{.*}} i64 1 +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]] +// OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] +// OGCG: [[EXIT]]: +// OGCG: ret void + +void zero_sized() { + S s[0]; +} + +// CIR-BEFORE-LPP: cir.func dso_local @_Z10zero_sizedv() +// CIR-BEFORE-LPP: cir.alloca !cir.array<!rec_S x 0>, !cir.ptr<!cir.array<!rec_S x 0>>, ["s"] +// CIR-BEFORE-LPP-NOT: cir.array.ctor +// CIR-BEFORE-LPP: cir.return + +// CIR: cir.func dso_local @_Z10zero_sizedv() +// CIR: cir.alloca !cir.array<!rec_S x 0>, !cir.ptr<!cir.array<!rec_S x 0>>, ["s"] +// CIR-NOT: cir.do +// CIR-NOT: cir.call @_ZN1SC1Ev +// CIR: cir.return + +// LLVM: define dso_local void @_Z10zero_sizedv() +// LLVM: alloca [0 x %struct.S] +// LLVM-NOT: call void @_ZN1SC1Ev +// LLVM: ret void + +// OGCG: define dso_local void @_Z10zero_sizedv() +// OGCG: alloca [0 x %struct.S] +// OGCG-NOT: call void @_ZN1SC1Ev +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index a73c076..869a7c9 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -315,3 +315,51 @@ void unOp(S* s) { // OGCG: [[TMP12:%.*]] = shl i64 [[TMP8]], 62 // OGCG: [[TMP13:%.*]] = ashr i64 [[TMP12]], 62 // OGCG: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 + +void binOp(S* s) { + s->d |= 42; +} + +// CIR: cir.func {{.*@binOp}} +// CIR: [[TMP0:%.*]] = cir.const #cir.int<42> : !s32i +// CIR: [[TMP1:%.*]] = cir.get_member {{.*}}[0] {name = "d"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i> +// CIR: [[TMP2:%.*]] = cir.get_bitfield align(4) (#bfi_d, [[TMP1]] : !cir.ptr<!u64i>) -> !s32i +// CIR: [[TMP3:%.*]] = cir.binop(or, [[TMP2]], [[TMP0]]) : !s32i +// CIR: cir.set_bitfield align(4) (#bfi_d, [[TMP1]] : !cir.ptr<!u64i>, [[TMP3]] : !s32i) + +// LLVM: define {{.*@binOp}} +// LLVM: [[TMP0:%.*]] = load ptr, ptr {{.*}}, align 8 +// LLVM: [[TMP1:%.*]] = getelementptr %struct.S, ptr [[TMP0]], i32 0, i32 0 +// LLVM: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4 +// LLVM: [[TMP3:%.*]] = shl i64 [[TMP2]], 13 +// LLVM: [[TMP4:%.*]] = ashr i64 [[TMP3]], 62 +// LLVM: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// LLVM: [[TMP6:%.*]] = or i32 [[TMP5]], 42 +// LLVM: [[TMP7:%.*]] = zext i32 [[TMP6]] to i64 +// LLVM: [[TMP8:%.*]] = load i64, ptr [[TMP1]], align 4 +// LLVM: [[TMP9:%.*]] = and i64 [[TMP7]], 3 +// LLVM: [[TMP10:%.*]] = shl i64 [[TMP9]], 49 +// LLVM: [[TMP11:%.*]] = and i64 [[TMP8]], -1688849860263937 +// LLVM: [[TMP12:%.*]] = or i64 [[TMP11]], [[TMP10]] +// LLVM: store i64 [[TMP12]], ptr [[TMP1]], align 4 +// LLVM: [[TMP13:%.*]] = shl i64 [[TMP9]], 62 +// LLVM: [[TMP14:%.*]] = ashr i64 [[TMP13]], 62 +// LLVM: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 + +// OGCG: define {{.*@binOp}} +// OGCG: [[TMP0:%.*]] = load ptr, ptr %s.addr, align 8 +// OGCG: [[TMP1:%.*]] = load i64, ptr [[TMP0]], align 4 +// OGCG: [[TMP2:%.*]] = shl i64 [[TMP1]], 13 +// OGCG: [[TMP3:%.*]] = ashr i64 [[TMP2]], 62 +// OGCG: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32 +// OGCG: [[TMP5:%.*]] = or i32 [[TMP4]], 42 +// OGCG: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// OGCG: [[TMP7:%.*]] = load i64, ptr [[TMP0]], align 4 +// OGCG: [[TMP8:%.*]] = and i64 [[TMP6]], 3 +// OGCG: [[TMP9:%.*]] = shl i64 [[TMP8]], 49 +// OGCG: [[TMP10:%.*]] = and i64 [[TMP7]], -1688849860263937 +// OGCG: [[TMP11:%.*]] = or i64 [[TMP10]], [[TMP9]] +// OGCG: store i64 [[TMP11]], ptr [[TMP0]], align 4 +// OGCG: [[TMP12:%.*]] = shl i64 [[TMP8]], 62 +// OGCG: [[TMP13:%.*]] = ashr i64 [[TMP12]], 62 +// OGCG: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 diff --git a/clang/test/CIR/CodeGen/cleanup.cpp b/clang/test/CIR/CodeGen/cleanup.cpp new file mode 100644 index 0000000..41961513 --- /dev/null +++ b/clang/test/CIR/CodeGen/cleanup.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +struct Struk { + ~Struk(); +}; + +// CHECK: !rec_Struk = !cir.record<struct "Struk" padded {!u8i}> + +// CHECK: cir.func{{.*}} @_ZN5StrukD1Ev(!cir.ptr<!rec_Struk>) + +void test_cleanup() { + Struk s; +} + +// CHECK: cir.func{{.*}} @_Z12test_cleanupv() +// CHECK: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S_ADDR]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: cir.return + +void test_cleanup_ifelse(bool b) { + if (b) { + Struk s; + } else { + Struk s; + } +} + +// CHECK: cir.func{{.*}} @_Z19test_cleanup_ifelseb(%arg0: !cir.bool +// CHECK: cir.scope { +// CHECK: %[[B:.*]] = cir.load{{.*}} %0 : !cir.ptr<!cir.bool> +// CHECK: cir.if %[[B]] { +// CHECK: %[[S:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } else { +// CHECK: %[[S_TOO:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S_TOO]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: } +// CHECK: cir.return + +void test_cleanup_for() { + for (int i = 0; i < 10; i++) { + Struk s; + } +} + +// CHECK: cir.func{{.*}} @_Z16test_cleanup_forv() +// CHECK: cir.scope { +// CHECK: cir.for : cond { +// CHECK: } body { +// CHECK: cir.scope { +// CHECK: %[[S:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.yield +// CHECK: } step { +// CHECK: } +// CHECK: } +// CHECK: cir.return + +void test_cleanup_nested() { + Struk outer; + { + Struk middle; + { + Struk inner; + } + } +} + +// CHECK: cir.func{{.*}} @_Z19test_cleanup_nestedv() +// CHECK: %[[OUTER:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["outer"] +// CHECK: cir.scope { +// CHECK: %[[MIDDLE:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["middle"] +// CHECK: cir.scope { +// CHECK: %[[INNER:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["inner"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[INNER]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.call @_ZN5StrukD1Ev(%[[MIDDLE]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.call @_ZN5StrukD1Ev(%[[OUTER]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/complex-cast.cpp b/clang/test/CIR/CodeGen/complex-cast.cpp new file mode 100644 index 0000000..0881057 --- /dev/null +++ b/clang/test/CIR/CodeGen/complex-cast.cpp @@ -0,0 +1,358 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +double _Complex cd; +float _Complex cf; +int _Complex ci; +short _Complex cs; +double sd; +int si; +bool b; + +void scalar_to_complex() { + cd = sd; + ci = si; + cd = si; + ci = sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void scalar_to_complex_explicit() { + cd = (double _Complex)sd; + ci = (int _Complex)si; + cd = (double _Complex)si; + ci = (int _Complex)sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void complex_to_scalar() { + sd = (double)cd; + si = (int)ci; + sd = (double)ci; + si = (int)cd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 +// LLVM: store double %[[REAL]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0 +// LLVM: store i32 %[[REAL]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %[[INT_COMPLEX_TO_REAL]] : !s32i), !cir.double + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(int_to_float, %[[REAL]] : !s32i), !cir.double + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.+}}, 0 +// LLVM-NEXT: %[[REAL_TO_DOUBLE:.*]] = sitofp i32 %[[REAL]] to double +// LLVM-NEXT: store double %[[REAL_TO_DOUBLE]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[INT_TO_FP:.*]] = sitofp i32 %[[REAL]] to double +// OGCG: store double %[[INT_TO_FP]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %[[FP_TO_COMPLEX_REAL]] : !cir.double), !s32i + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(float_to_int, %[[REAL]] : !cir.double), !s32i + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.+}}, 0 +// LLVM-NEXT: %[[REAL_TO_INT:.*]] = fptosi double %[[REAL]] to i32 +// LLVM-NEXT: store i32 %[[REAL_TO_INT]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[FP_TO_INT:.*]] = fptosi double %[[REAL]] to i32 +// OGCG: store i32 %[[FP_TO_INT]], ptr {{.*}}, align 4 + +void complex_to_bool() { + b = (bool)cd; + b = (bool)ci; +} + +// CIR-BEFORE: %[[FP_COMPLEX_TO_BOOL:.*]] = cir.cast(float_complex_to_bool, %{{.*}} : !cir.complex<!cir.double>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[REAL]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[IMAG]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.*}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { double, double } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// LLVM-NEXT: %[[OR:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8 +// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[IMAG:.*]] = load double, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 +// OGCG: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// OGCG: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_BOOL:.*]] = cir.cast(int_complex_to_bool, %{{.*}} : !cir.complex<!s32i>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[REAL]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[IMAG]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.+}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { i32, i32 } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// LLVM-NEXT: %[[OR:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8 +// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load i32, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// OGCG: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +void complex_to_complex_cast() { + cd = cf; + ci = cs; +} + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-BEFORE: %[[FP_COMPLEX:.*]] = cir.cast(float_complex, %[[TMP]] : !cir.complex<!cir.float>), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[REAL_FP_CAST:.*]] = cir.cast(floating, %[[REAL]] : !cir.float), !cir.double +// CIR-AFTER: %[[IMAG_FP_CAST:.*]] = cir.cast(floating, %[[IMAG]] : !cir.float), !cir.double +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_FP_CAST]], %[[IMAG_FP_CAST]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = extractvalue { float, float } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %{{.*}}, 1 +// LLVM: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// LLVM: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL_FP_CAST]], 0 +// LLVM: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double %[[IMAG_FP_CAST]], 1 +// LLVM: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// OGCG: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// OGCG: store double %[[REAL_FP_CAST]], ptr {{.*}}, align 8 +// OGCG: store double %[[IMAG_FP_CAST]], ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!s16i>>, !cir.complex<!s16i> +// CIR-BEFORE: %[[INT_COMPLEX:.*]] = cir.cast(int_complex, %[[TMP]] : !cir.complex<!s16i>), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[REAL_INT_CAST:.*]] = cir.cast(integral, %[[REAL]] : !s16i), !s32i +// CIR-AFTER: %[[IMAG_INT_CAST:.*]] = cir.cast(integral, %[[IMAG]] : !s16i), !s32i +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_INT_CAST]], %[[IMAG_INT_CAST]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = extractvalue { i16, i16 } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { i16, i16 } %{{.*}}, 1 +// LLVM: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// LLVM: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// LLVM: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL_INT_CAST]], 0 +// LLVM: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 %[[IMAG_INT_CAST]], 1 +// LLVM: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i16, ptr {{.*}}, align 2 +// OGCG: %[[IMAG:.*]] = load i16, ptr getelementptr inbounds nuw ({ i16, i16 }, ptr {{.*}}, i32 0, i32 1), align 2 +// OGCG: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// OGCG: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// OGCG: store i32 %[[REAL_INT_CAST]], ptr {{.*}}, align 4 +// OGCG: store i32 %[[IMAG_INT_CAST]], ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +struct CX { + double real; + double imag; +}; + +void lvalue_to_rvalue_bitcast() { + CX a; + double _Complex b = __builtin_bit_cast(double _Complex, a); +} + + +// CIR-BEFORE: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// CIR-AFTER: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// LLVM: %[[PTR_ADDR:.*]] = alloca %struct.CX, i64 1, align 8 +// LLVM: %[[COMPLEX_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[PTR_TO_COMPLEX:.*]] = load { double, double }, ptr %[[PTR_ADDR]], align 8 +// LLVM: store { double, double } %[[PTR_TO_COMPLEX]], ptr %[[COMPLEX_ADDR]], align 8 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CX, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: store double %[[A_REAL]], ptr %[[B_REAL_PTR]], align 8 +// OGCG: store double %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 8 diff --git a/clang/test/CIR/CodeGen/dtor-alias.cpp b/clang/test/CIR/CodeGen/dtor-alias.cpp new file mode 100644 index 0000000..e37ddab --- /dev/null +++ b/clang/test/CIR/CodeGen/dtor-alias.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct B { + ~B(); +}; +B::~B() { +} + +// OGCG: @_ZN1BD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BD2Ev + +// CHECK: cir.func{{.*}} @_ZN1BD2Ev(%arg0: !cir.ptr<!rec_B> +// CHECK: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["this", init] +// CHECK: cir.store %arg0, %[[THIS_ADDR]] +// CHECK: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B> + +// CHECK: cir.func{{.*}} private dso_local @_ZN1BD1Ev(!cir.ptr<!rec_B>) alias(@_ZN1BD2Ev) + +// LLVM: define{{.*}} @_ZN1BD2Ev(ptr %[[THIS_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + +// This should be an alias, like the similar OGCG alias above, but that's not +// implemented yet. +// LLVM: declare dso_local void @_ZN1BD1Ev(ptr) + +// OGCG: define{{.*}} @_ZN1BD2Ev(ptr{{.*}} %[[THIS_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + +// The destructor in this case is handled by RAUW rather than aliasing. +struct Struk { + ~Struk() {} +}; + +void baz() { + Struk s; +} + +// CHECK: cir.func{{.*}} @_ZN5StrukD2Ev(%arg0: !cir.ptr<!rec_Struk> +// CHECK: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Struk>, !cir.ptr<!cir.ptr<!rec_Struk>>, ["this", init] +// CHECK: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_Struk>, !cir.ptr<!cir.ptr<!rec_Struk>> +// CHECK: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_Struk>>, !cir.ptr<!rec_Struk> +// CHECK: cir.return + +// CHECK-NOT: cir.func{{.*}} @_ZN5StrukD1Ev + +// CHECK: cir.func{{.*}} @_Z3bazv() +// CHECK: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD2Ev(%[[S_ADDR]]) nothrow : (!cir.ptr<!rec_Struk>) -> () + +// LLVM: define linkonce_odr void @_ZN5StrukD2Ev(ptr %[[THIS_ARG]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + +// LLVM: define{{.*}} void @_Z3bazv() +// LLVM: %[[S_ADDR:.*]] = alloca %struct.Struk +// LLVM: call void @_ZN5StrukD2Ev(ptr{{.*}} %[[S_ADDR]]) + +// This function gets emitted before the destructor in OGCG. +// OGCG: define{{.*}} void @_Z3bazv() +// OGCG: %[[S_ADDR:.*]] = alloca %struct.Struk +// OGCG: call void @_ZN5StrukD2Ev(ptr{{.*}} %[[S_ADDR]]) + +// OGCG: define linkonce_odr void @_ZN5StrukD2Ev(ptr{{.*}} %[[THIS_ARG]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir new file mode 100644 index 0000000..2378992 --- /dev/null +++ b/clang/test/CIR/IR/array-ctor.cir @@ -0,0 +1,29 @@ + +// RUN: cir-opt %s | FileCheck %s + +!u8i = !cir.int<u, 8> +!rec_S = !cir.record<struct "S" padded {!u8i}> + +module { + cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) + cir.func dso_local @_Z3foov() { + %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} + cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } + cir.return + } + + // CHECK: cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) + // CHECK: cir.func dso_local @_Z3foov() { + // CHECK: %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} + // CHECK: cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { + // CHECK: ^bb0(%arg0: !cir.ptr<!rec_S>): + // CHECK: cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + // CHECK: cir.yield + // CHECK: } + // CHECK: cir.return + // CHECK: } +} diff --git a/clang/test/CodeGen/AArch64/neon-intrinsics.c b/clang/test/CodeGen/AArch64/neon-intrinsics.c index 6304245..035e1ca 100644 --- a/clang/test/CodeGen/AArch64/neon-intrinsics.c +++ b/clang/test/CodeGen/AArch64/neon-intrinsics.c @@ -8585,7 +8585,7 @@ uint32x2_t test_vqshrun_n_s64(int64x2_t a) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> // CHECK-NEXT: ret <16 x i8> [[SHUFFLE_I]] // -int8x16_t test_vqshrun_high_n_s16(int8x8_t a, int16x8_t b) { +uint8x16_t test_vqshrun_high_n_s16(uint8x8_t a, int16x8_t b) { return vqshrun_high_n_s16(a, b, 3); } @@ -8598,7 +8598,7 @@ int8x16_t test_vqshrun_high_n_s16(int8x8_t a, int16x8_t b) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> // CHECK-NEXT: ret <8 x i16> [[SHUFFLE_I]] // -int16x8_t test_vqshrun_high_n_s32(int16x4_t a, int32x4_t b) { +uint16x8_t test_vqshrun_high_n_s32(uint16x4_t a, int32x4_t b) { return vqshrun_high_n_s32(a, b, 9); } @@ -8611,7 +8611,7 @@ int16x8_t test_vqshrun_high_n_s32(int16x4_t a, int32x4_t b) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> // CHECK-NEXT: ret <4 x i32> [[SHUFFLE_I]] // -int32x4_t test_vqshrun_high_n_s64(int32x2_t a, int64x2_t b) { +uint32x4_t test_vqshrun_high_n_s64(uint32x2_t a, int64x2_t b) { return vqshrun_high_n_s64(a, b, 19); } @@ -8810,7 +8810,7 @@ uint32x2_t test_vqrshrun_n_s64(int64x2_t a) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[VQRSHRUN_N3]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15> // CHECK-NEXT: ret <16 x i8> [[SHUFFLE_I]] // -int8x16_t test_vqrshrun_high_n_s16(int8x8_t a, int16x8_t b) { +uint8x16_t test_vqrshrun_high_n_s16(uint8x8_t a, int16x8_t b) { return vqrshrun_high_n_s16(a, b, 3); } @@ -8823,7 +8823,7 @@ int8x16_t test_vqrshrun_high_n_s16(int8x8_t a, int16x8_t b) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[VQRSHRUN_N3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> // CHECK-NEXT: ret <8 x i16> [[SHUFFLE_I]] // -int16x8_t test_vqrshrun_high_n_s32(int16x4_t a, int32x4_t b) { +uint16x8_t test_vqrshrun_high_n_s32(uint16x4_t a, int32x4_t b) { return vqrshrun_high_n_s32(a, b, 9); } @@ -8836,7 +8836,7 @@ int16x8_t test_vqrshrun_high_n_s32(int16x4_t a, int32x4_t b) { // CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[VQRSHRUN_N3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3> // CHECK-NEXT: ret <4 x i32> [[SHUFFLE_I]] // -int32x4_t test_vqrshrun_high_n_s64(int32x2_t a, int64x2_t b) { +uint32x4_t test_vqrshrun_high_n_s64(uint32x2_t a, int64x2_t b) { return vqrshrun_high_n_s64(a, b, 19); } diff --git a/clang/test/CodeGenCXX/builtin-amdgcn-fence.cpp b/clang/test/CodeGenCXX/builtin-amdgcn-fence.cpp index 3af5a21..1e977dd 100644 --- a/clang/test/CodeGenCXX/builtin-amdgcn-fence.cpp +++ b/clang/test/CodeGenCXX/builtin-amdgcn-fence.cpp @@ -105,7 +105,7 @@ void test_mixed() { __builtin_amdgcn_fence( __ATOMIC_SEQ_CST, "workgroup", "local", "local", "global", "local", "local"); } //. -// CHECK: [[META3]] = !{!"amdgpu-as", !"local"} -// CHECK: [[META4]] = !{!"amdgpu-as", !"global"} +// CHECK: [[META3]] = !{!"amdgpu-synchronize-as", !"local"} +// CHECK: [[META4]] = !{!"amdgpu-synchronize-as", !"global"} // CHECK: [[META5]] = !{[[META4]], [[META3]]} //. diff --git a/clang/test/CodeGenCXX/delete.cpp b/clang/test/CodeGenCXX/delete.cpp index d5b0dc6..21b9f8c 100644 --- a/clang/test/CodeGenCXX/delete.cpp +++ b/clang/test/CodeGenCXX/delete.cpp @@ -76,27 +76,45 @@ namespace test1 { ~A(); }; - // CHECK-LABEL: define{{.*}} void @_ZN5test14testEPA10_A20_NS_1AE( - void test(A (*arr)[10][20]) { + // CHECK-LABEL: define{{.*}} void @_ZN5test11fEPA10_A20_NS_1AE( + void f(A (*arr)[10][20]) { delete [] arr; // CHECK: icmp eq ptr [[PTR:%.*]], null // CHECK-NEXT: br i1 - // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x [[A:%.*]]]], ptr [[PTR]], i32 0, i32 0, i32 0 - // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[BEGIN]], i64 -8 + // CHECK: [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 -8 // CHECK-NEXT: [[COUNT:%.*]] = load i64, ptr [[ALLOC]] - // CHECK: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], i64 [[COUNT]] - // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[BEGIN]], [[END]] + // CHECK: [[END:%.*]] = getelementptr inbounds [[A:%.*]], ptr [[PTR]], i64 [[COUNT]] + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[PTR]], [[END]] // CHECK-NEXT: br i1 [[ISEMPTY]], // CHECK: [[PAST:%.*]] = phi ptr [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[PAST]], i64 -1 // CHECK-NEXT: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[CUR]]) - // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[BEGIN]] + // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[PTR]] // CHECK-NEXT: br i1 [[ISDONE]] // CHECK: [[MUL:%.*]] = mul i64 4, [[COUNT]] // CHECK-NEXT: [[SIZE:%.*]] = add i64 [[MUL]], 8 // CHECK-NEXT: call void @_ZdaPvm(ptr noundef [[ALLOC]], i64 noundef [[SIZE]]) } + + // CHECK-LABEL: define{{.*}} void @_ZN5test11gEPA_NS_1AE( + void g(A (*arr)[]) { + delete [] arr; + // CHECK: icmp eq ptr [[PTR:%.*]], null + // CHECK-NEXT: br i1 + + // CHECK: [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 -8 + // CHECK-NEXT: [[COUNT:%.*]] = load i64, ptr [[ALLOC]] + // CHECK: [[END:%.*]] = getelementptr inbounds [[A:%.*]], ptr [[PTR]], i64 [[COUNT]] + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[PTR]], [[END]] + // CHECK-NEXT: br i1 [[ISEMPTY]], + // CHECK: [[PAST:%.*]] = phi ptr [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[PAST]], i64 -1 + // CHECK-NEXT: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[CUR]]) + // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[PTR]] + // CHECK-NEXT: br i1 [[ISDONE]] + // CHECK: call void @_ZdaPv(ptr noundef [[ALLOC]]) + } } namespace test2 { diff --git a/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl index bccfaf5..4571649 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/ArrayOutputArguments.hlsl @@ -11,7 +11,7 @@ void increment(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) +// CHECK-NEXT: call void @{{.*}}increment{{.*}}(ptr noalias noundef align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -32,7 +32,7 @@ void fn2(out int Arr[2]) { // CHECK: [[A:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}fn2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) +// CHECK-NEXT: call void @{{.*}}fn2{{.*}}(ptr noalias noundef align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -56,7 +56,7 @@ void nestedCall(inout int Arr[2], uint index) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}nestedCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]], i32 noundef 0) +// CHECK-NEXT: call void @{{.*}}nestedCall{{.*}}(ptr noalias noundef align 4 [[Tmp]], i32 noundef 0) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 1 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -70,7 +70,7 @@ export int arrayCall3() { // CHECK-LABEL: outerCall // CHECK: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 %{{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void {{.*}}increment{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) +// CHECK-NEXT: call void {{.*}}increment{{.*}}(ptr noalias noundef align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{.*}}, ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: ret void void outerCall(inout int Arr[2]) { @@ -82,7 +82,7 @@ void outerCall(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}outerCall{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) +// CHECK-NEXT: call void @{{.*}}outerCall{{.*}}(ptr noalias noundef align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 @@ -110,7 +110,7 @@ void outerCall2(inout int Arr[2]) { // CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 @{{.*}}, i32 8, i1 false) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false) -// CHECK-NEXT: call void @{{.*}}outerCall2{{.*}}(ptr noalias noundef byval([2 x i32]) align 4 [[Tmp]]) +// CHECK-NEXT: call void @{{.*}}outerCall2{{.*}}(ptr noalias noundef align 4 [[Tmp]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 [[Tmp]], i32 8, i1 false) // CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i32 0, i32 0 // CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Idx]], align 4 diff --git a/clang/test/CodeGenOpenCL/amdgpu-features.cl b/clang/test/CodeGenOpenCL/amdgpu-features.cl index 75e9710..e96dd66 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-features.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-features.cl @@ -108,7 +108,7 @@ // GFX1153: "target-features"="+16-bit-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot10-insts,+dot12-insts,+dot5-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" // GFX1200: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot10-insts,+dot11-insts,+dot12-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+fp8-conversion-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" // GFX1201: "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+ci-insts,+dl-insts,+dot10-insts,+dot11-insts,+dot12-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+fp8-conversion-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize32" -// GFX1250: "target-features"="+16-bit-insts,+ashr-pk-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+bf16-trans-insts,+bitop3-insts,+ci-insts,+dl-insts,+dot7-insts,+dot8-insts,+dpp,+fp8-conversion-insts,+fp8e5m3-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx1250-insts,+gfx8-insts,+gfx9-insts,+permlane16-swap,+prng-inst,+setprio-inc-wg-inst,+tanh-insts,+transpose-load-f4f6-insts,+wavefrontsize32 +// GFX1250: "target-features"="+16-bit-insts,+ashr-pk-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-buffer-pk-add-bf16-inst,+atomic-ds-pk-add-16-insts,+atomic-fadd-rtn-insts,+atomic-flat-pk-add-16-insts,+atomic-global-pk-add-bf16-inst,+bf16-trans-insts,+bitop3-insts,+ci-insts,+dl-insts,+dot7-insts,+dot8-insts,+dpp,+fp8-conversion-insts,+fp8e5m3-insts,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx12-insts,+gfx1250-insts,+gfx8-insts,+gfx9-insts,+permlane16-swap,+prng-inst,+setprio-inc-wg-inst,+tanh-insts,+transpose-load-f4f6-insts,+vmem-pref-insts,+wavefrontsize32 // GFX1103-W64: "target-features"="+16-bit-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot10-insts,+dot12-insts,+dot5-insts,+dot7-insts,+dot8-insts,+dot9-insts,+dpp,+gfx10-3-insts,+gfx10-insts,+gfx11-insts,+gfx8-insts,+gfx9-insts,+wavefrontsize64" diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250-load-monitor.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250-load-monitor.cl new file mode 100644 index 0000000..f2552d4 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250-load-monitor.cl @@ -0,0 +1,66 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgcn-unknown-unknown -target-cpu gfx1250 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-GFX1250 + +typedef int v2i __attribute__((ext_vector_type(2))); +typedef int v4i __attribute__((ext_vector_type(4))); + +// CHECK-GFX1250-LABEL: @test_amdgcn_global_load_monitor_b32( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.amdgcn.global.load.monitor.b32.i32(ptr addrspace(1) [[INPTR:%.*]], i32 1) +// CHECK-GFX1250-NEXT: ret i32 [[TMP0]] +// +int test_amdgcn_global_load_monitor_b32(global int* inptr) +{ + return __builtin_amdgcn_global_load_monitor_b32(inptr, 1); +} + +// CHECK-GFX1250-LABEL: @test_amdgcn_global_load_monitor_b64( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call <2 x i32> @llvm.amdgcn.global.load.monitor.b64.v2i32(ptr addrspace(1) [[INPTR:%.*]], i32 10) +// CHECK-GFX1250-NEXT: ret <2 x i32> [[TMP0]] +// +v2i test_amdgcn_global_load_monitor_b64(global v2i* inptr) +{ + return __builtin_amdgcn_global_load_monitor_b64(inptr, 10); +} + +// CHECK-GFX1250-LABEL: @test_amdgcn_global_load_monitor_b128( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call <4 x i32> @llvm.amdgcn.global.load.monitor.b128.v4i32(ptr addrspace(1) [[INPTR:%.*]], i32 22) +// CHECK-GFX1250-NEXT: ret <4 x i32> [[TMP0]] +// +v4i test_amdgcn_global_load_monitor_b128(global v4i* inptr) +{ + return __builtin_amdgcn_global_load_monitor_b128(inptr, 22); +} + +// CHECK-GFX1250-LABEL: @test_amdgcn_flat_load_monitor_b32( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.amdgcn.flat.load.monitor.b32.i32(ptr [[INPTR:%.*]], i32 27) +// CHECK-GFX1250-NEXT: ret i32 [[TMP0]] +// +int test_amdgcn_flat_load_monitor_b32(int* inptr) +{ + return __builtin_amdgcn_flat_load_monitor_b32(inptr, 27); +} + +// CHECK-GFX1250-LABEL: @test_amdgcn_flat_load_monitor_b64( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call <2 x i32> @llvm.amdgcn.flat.load.monitor.b64.v2i32(ptr [[INPTR:%.*]], i32 1) +// CHECK-GFX1250-NEXT: ret <2 x i32> [[TMP0]] +// +v2i test_amdgcn_flat_load_monitor_b64(v2i* inptr) +{ + return __builtin_amdgcn_flat_load_monitor_b64(inptr, 1); +} + +// CHECK-GFX1250-LABEL: @test_amdgcn_flat_load_monitor_b128( +// CHECK-GFX1250-NEXT: entry: +// CHECK-GFX1250-NEXT: [[TMP0:%.*]] = tail call <4 x i32> @llvm.amdgcn.flat.load.monitor.b128.v4i32(ptr [[INPTR:%.*]], i32 0) +// CHECK-GFX1250-NEXT: ret <4 x i32> [[TMP0]] +// +v4i test_amdgcn_flat_load_monitor_b128(v4i* inptr) +{ + return __builtin_amdgcn_flat_load_monitor_b128(inptr, 0); +} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl index a21862c..81f39f9 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx1250.cl @@ -440,6 +440,25 @@ void test_permlane16_swap(global uint2* out, uint old, uint src) { *out = __builtin_amdgcn_permlane16_swap(old, src, false, true); } +// CHECK-LABEL: @test_prefetch( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[FPTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[GPTR_ADDR:%.*]] = alloca ptr addrspace(1), align 8, addrspace(5) +// CHECK-NEXT: [[FPTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[FPTR_ADDR]] to ptr +// CHECK-NEXT: [[GPTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[GPTR_ADDR]] to ptr +// CHECK-NEXT: store ptr [[FPTR:%.*]], ptr [[FPTR_ADDR_ASCAST]], align 8 +// CHECK-NEXT: store ptr addrspace(1) [[GPTR:%.*]], ptr [[GPTR_ADDR_ASCAST]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[FPTR_ADDR_ASCAST]], align 8 +// CHECK-NEXT: call void @llvm.amdgcn.flat.prefetch(ptr [[TMP0]], i32 0) +// CHECK-NEXT: [[TMP1:%.*]] = load ptr addrspace(1), ptr [[GPTR_ADDR_ASCAST]], align 8 +// CHECK-NEXT: call void @llvm.amdgcn.global.prefetch(ptr addrspace(1) [[TMP1]], i32 8) +// CHECK-NEXT: ret void +// +void test_prefetch(generic void *fptr, global void *gptr) { + __builtin_amdgcn_flat_prefetch(fptr, 0); + __builtin_amdgcn_global_prefetch(gptr, 8); +} + // CHECK-LABEL: @test_cvt_f32_fp8_e5m3( // CHECK-NEXT: entry: // CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr addrspace(1), align 8, addrspace(5) diff --git a/clang/test/Driver/fsanitize-ignorelist.c b/clang/test/Driver/fsanitize-ignorelist.c index 7dd666a..d3c8e6c 100644 --- a/clang/test/Driver/fsanitize-ignorelist.c +++ b/clang/test/Driver/fsanitize-ignorelist.c @@ -50,7 +50,7 @@ // Driver properly reports malformed ignorelist files. // RUN: not %clang --target=x86_64-linux-gnu -fsanitize=address -fsanitize-ignorelist=%t.second -fsanitize-ignorelist=%t.bad -fsanitize-ignorelist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-IGNORELIST -// CHECK-BAD-IGNORELIST: error: malformed sanitizer ignorelist: 'error parsing file '{{.*}}.bad': malformed line 1: 'badline'' +// CHECK-BAD-IGNORELIST: error: failed to parse malformed sanitizer ignorelist: ''{{.*}}.bad': malformed line 1: 'badline' // -fno-sanitize-ignorelist disables all ignorelists specified earlier. // RUN: %clang --target=x86_64-linux-gnu -fsanitize=address -fsanitize-ignorelist=%t.good -fno-sanitize-ignorelist -fsanitize-ignorelist=%t.second %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-FIRST-DISABLED --implicit-check-not=-fsanitize-ignorelist= @@ -71,3 +71,10 @@ // CHECK-MISSING-CFI-NO-IGNORELIST-NOT: error: no such file or directory: '{{.*}}cfi_ignorelist.txt' // DELIMITERS: {{^ *"}} + +// Check that a missing file passed to -fsanitize-system-ignorelist triggers a clean error without crashing. +// RUN: not %clang --target=x86_64-linux-gnu -Xclang -fsanitize-system-ignorelist=%t.nonexistent %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-SYSTEM-IGNORELIST-NOFILE +// CHECK-SYSTEM-IGNORELIST-NOFILE: error: failed to load sanitizer ignorelist file: ''{{.*[\\/]fsanitize-ignorelist\.c\.tmp\.nonexistent}}': {{[Nn]o such file or directory}} +// CHECK-SYSTEM-IGNORELIST-NOFILE-NOT: Stack dump: +// CHECK-SYSTEM-IGNORELIST-NOFILE-NOT: PLEASE submit a bug report +// CHECK-SYSTEM-IGNORELIST-NOFILE-NOT: diagnostic msg: diff --git a/clang/test/Driver/hip-phases.hip b/clang/test/Driver/hip-phases.hip index d8a58b7..0ad5d76 100644 --- a/clang/test/Driver/hip-phases.hip +++ b/clang/test/Driver/hip-phases.hip @@ -675,3 +675,25 @@ // DEVICE-ONLY-NEXT: 2: compiler, {1}, ir, (device-hip, gfx90a) // DEVICE-ONLY-NEXT: 3: backend, {2}, ir, (device-hip, gfx90a) // DEVICE-ONLY-NEXT: 4: offload, "device-hip (amdgcn-amd-amdhsa:gfx90a)" {3}, none + +// +// Test the new driver bundling SPIR-V targets. +// +// RUN: %clang -### --target=x86_64-linux-gnu --offload-new-driver -ccc-print-phases \ +// RUN: --offload-device-only --offload-arch=amdgcnspirv,gfx1030 %s 2>&1 \ +// RUN: | FileCheck -check-prefix=SPIRV-ONLY %s +// SPIRV-ONLY: 0: input, "[[INPUT:.+]]", hip, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 1: preprocessor, {0}, hip-cpp-output, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 2: compiler, {1}, ir, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 3: backend, {2}, assembler, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 4: assembler, {3}, object, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 5: linker, {4}, image, (device-hip, gfx1030) +// SPIRV-ONLY-NEXT: 6: offload, "device-hip (amdgcn-amd-amdhsa:gfx1030)" {5}, image +// SPIRV-ONLY-NEXT: 7: input, "[[INPUT]]", hip, (device-hip, amdgcnspirv) +// SPIRV-ONLY-NEXT: 8: preprocessor, {7}, hip-cpp-output, (device-hip, amdgcnspirv) +// SPIRV-ONLY-NEXT: 9: compiler, {8}, ir, (device-hip, amdgcnspirv) +// SPIRV-ONLY-NEXT: 10: backend, {9}, ir, (device-hip, amdgcnspirv) +// SPIRV-ONLY-NEXT: 11: linker, {10}, image, (device-hip, amdgcnspirv) +// SPIRV-ONLY-NEXT: 12: offload, "device-hip (spirv64-amd-amdhsa:amdgcnspirv)" {11}, image +// SPIRV-ONLY-NEXT: 13: linker, {6, 12}, hip-fatbin, (device-hip) +// SPIRV-ONLY-NEXT: 14: offload, "device-hip (amdgcn-amd-amdhsa)" {13}, none diff --git a/clang/test/Driver/offload-target.c b/clang/test/Driver/offload-target.c index 123ecd3..23a2cf2 100644 --- a/clang/test/Driver/offload-target.c +++ b/clang/test/Driver/offload-target.c @@ -10,7 +10,7 @@ // RUN: | FileCheck %s -check-prefix=CUDA // CUDA: "nvptx64-nvidia-cuda" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[NV_OBJ:.+]]" -// RUN: %clang -### --offload-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda -fopenmp \ +// RUN: %clang -### --offload-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda -fopenmp=libomp \ // RUN: -Xarch_amdgcn --offload-arch=gfx90a -Xarch_nvptx64 --offload-arch=sm_89 \ // RUN: -nogpulib -nogpuinc %s -ccc-print-bindings 2>&1 \ // RUN: | FileCheck %s -check-prefix=OPENMP diff --git a/clang/test/Driver/sparc-target-features.c b/clang/test/Driver/sparc-target-features.c index 48a180c..bd17da1 100644 --- a/clang/test/Driver/sparc-target-features.c +++ b/clang/test/Driver/sparc-target-features.c @@ -39,4 +39,8 @@ // SOFT-QUAD-FLOAT: "-target-feature" "-hard-quad-float" // RUN: %clang --target=sparc -mv8plus %s -### 2>&1 | FileCheck -check-prefix=V8PLUS %s +/// 32-bit Solaris/SPARC defaults to -mv8plus +// RUN: %clang --target=sparc-sun-solaris2.11 %s -### 2>&1 | FileCheck -check-prefix=V8PLUS %s +// RUN: %clang --target=sparc-sun-solaris2.11 -mno-v8plus %s -### 2>&1 | FileCheck -check-prefix=NO-V8PLUS %s // V8PLUS: "-target-feature" "+v8plus" +// NO-V8PLUS-NOT: "-target-feature" "+v8plus" diff --git a/clang/test/Interpreter/fail.cpp b/clang/test/Interpreter/fail.cpp index 633d927..4963df8 100644 --- a/clang/test/Interpreter/fail.cpp +++ b/clang/test/Interpreter/fail.cpp @@ -18,4 +18,11 @@ extern "C" int printf(const char *, ...); int i = 42; auto r1 = printf("i = %d\n", i); // CHECK: i = 42 + +1aap = 42; // expected-error {{invalid digit 'a' in decimal constant}} +1aap = 42; i = 5; // expected-error {{invalid digit 'a' in decimal constant}} + +printf("i = %d\n", i); +// CHECK: i = 42 + %quit diff --git a/clang/test/Interpreter/pretty-print.c b/clang/test/Interpreter/pretty-print.c index 56488a1..e1408c0 100644 --- a/clang/test/Interpreter/pretty-print.c +++ b/clang/test/Interpreter/pretty-print.c @@ -3,7 +3,7 @@ // RUN: cat %s | clang-repl -Xcc -xc | FileCheck %s // RUN: cat %s | clang-repl -Xcc -std=c++11 | FileCheck %s -// UNSUPPORTED: hwasan +// UNSUPPORTED: hwasan, msan char c = 'a'; c diff --git a/clang/test/Interpreter/pretty-print.cpp b/clang/test/Interpreter/pretty-print.cpp index fd79d31..e1036ab 100644 --- a/clang/test/Interpreter/pretty-print.cpp +++ b/clang/test/Interpreter/pretty-print.cpp @@ -1,6 +1,7 @@ // RUN: clang-repl "int i = 10;" 'extern "C" int printf(const char*,...);' \ // RUN: 'auto r1 = printf("i = %d\n", i);' | FileCheck --check-prefix=CHECK-DRIVER %s -// UNSUPPORTED: system-aix +// The test is flaky with asan https://github.com/llvm/llvm-project/pull/148701. +// UNSUPPORTED: system-aix, asan // CHECK-DRIVER: i = 10 // RUN: cat %s | clang-repl -Xcc -std=c++11 -Xcc -fno-delayed-template-parsing | FileCheck %s extern "C" int printf(const char*,...); diff --git a/clang/test/OpenMP/copy-gaps-1.cpp b/clang/test/OpenMP/copy-gaps-1.cpp new file mode 100644 index 0000000..3d4fae3 --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-1.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { + int x; + int y; + int z; + int *p1; + int *p2; +}; + +struct T : public S { + int a; + int b; + int c; +}; + +int main() { + T v; + +#pragma omp target map(tofrom: v, v.x, v.y, v.z, v.p1[:8], v.a, v.b, v.c) + { + v.x++; + v.y += 2; + v.z += 3; + v.p1[0] += 4; + v.a += 7; + v.b += 5; + v.c += 6; + } + + return 0; +} + +// CHECK: [[CSTSZ:@.+]] = private {{.*}}constant [10 x i64] [i64 0, i64 0, i64 0, i64 4, i64 4, i64 4, i64 32, i64 4, i64 4, i64 4] +// CHECK: [[CSTTY:@.+]] = private {{.*}}constant [10 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000013]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [10 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Check for filling of four non-constant size elements here: the whole struct +// size, the (padded) region covering p1 & p2, and the padding at the end of +// struct T. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [10 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[P1P2:%.+]] = getelementptr inbounds [10 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[P1P2]], align 8 +// CHECK-DAG: [[PAD:%.+]] = getelementptr inbounds [10 x i64], ptr [[SIZES]], i32 0, i32 2 +// CHECK-DAG: store i64 %{{.+}}, ptr [[PAD]], align 8 diff --git a/clang/test/OpenMP/copy-gaps-2.cpp b/clang/test/OpenMP/copy-gaps-2.cpp new file mode 100644 index 0000000..5bf603a --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-2.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { + int x; + int y; + int z; +}; + +struct M : public S { + int mid; +}; + +struct T : public M { + int a; + int b; + int c; +}; + +int main() { + T v; + +#pragma omp target map(tofrom: v, v.y, v.z, v.a) + { + v.y++; + v.z += 2; + v.a += 3; + v.mid += 5; + } + + return 0; +} + +// CHECK: [[CSTSZ:@.+]] = private {{.*}}constant [7 x i64] [i64 0, i64 0, i64 0, i64 0, i64 4, i64 4, i64 4] +// CHECK: [[CSTTY:@.+]] = private {{.*}}constant [7 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [7 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill four non-constant size elements here: the whole struct size, the region +// covering v.x, the region covering v.mid and the region covering v.b and v.c. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[X:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[X]], align 8 +// CHECK-DAG: [[MID:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 2 +// CHECK-DAG: store i64 %{{.+}}, ptr [[MID]], align 8 +// CHECK-DAG: [[BC:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 3 +// CHECK-DAG: store i64 %{{.+}}, ptr [[BC]], align 8 diff --git a/clang/test/OpenMP/copy-gaps-3.cpp b/clang/test/OpenMP/copy-gaps-3.cpp new file mode 100644 index 0000000..5febb18 --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-3.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { + int x; + int y; + int z; +}; + +struct T : public S { + int a; + int b; + int c; +}; + +int main() { + T v; + + // This one should have no gap between v.z & v.a. +#pragma omp target map(tofrom: v, v.y, v.z, v.a) + { + v.y++; + v.z += 2; + v.a += 3; + } + + return 0; +} + +// CHECK: [[CSTSZ:@.+]] = private {{.*}}constant [6 x i64] [i64 0, i64 0, i64 0, i64 4, i64 4, i64 4] +// CHECK: [[CSTTY:@.+]] = private {{.*}}constant [6 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [6 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill three non-constant size elements here: the whole struct size, the region +// covering v.x, and the region covering v.b and v.c. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [6 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[X:%.+]] = getelementptr inbounds [6 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[X]], align 8 +// CHECK-DAG: [[BC:%.+]] = getelementptr inbounds [6 x i64], ptr [[SIZES]], i32 0, i32 2 +// CHECK-DAG: store i64 %{{.+}}, ptr [[BC]], align 8 diff --git a/clang/test/OpenMP/copy-gaps-4.cpp b/clang/test/OpenMP/copy-gaps-4.cpp new file mode 100644 index 0000000..7060fe3 --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-4.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { + int x; + int y; + char z; // Hidden padding after here... +}; + +struct T : public S { + int a; + int b; + int c; +}; + +int main() { + T v; + +#pragma omp target map(tofrom: v, v.y, v.z, v.a) + { + v.y++; + v.z += 2; + v.a += 3; + } + + return 0; +} + +// CHECK: [[CSTSZ:@.+]] = private {{.*}}constant [7 x i64] [i64 0, i64 0, i64 0, i64 0, i64 4, i64 1, i64 4] +// CHECK: [[CSTTY:@.+]] = private {{.*}}constant [7 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [7 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill four non-constant size elements here: the whole struct size, the region +// covering v.x, the region covering padding after v.z and the region covering +// v.b and v.c. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[X:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[X]], align 8 +// CHECK-DAG: [[PAD:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 2 +// CHECK-DAG: store i64 %{{.+}}, ptr [[PAD]], align 8 +// CHECK-DAG: [[BC:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 3 +// CHECK-DAG: store i64 %{{.+}}, ptr [[BC]], align 8 diff --git a/clang/test/OpenMP/copy-gaps-5.cpp b/clang/test/OpenMP/copy-gaps-5.cpp new file mode 100644 index 0000000..fae675d --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-5.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +template<typename C> +struct S { + C x; + C y; + char z; // Hidden padding after here... +}; + +template<typename C> +struct T : public S<C> { + C a; + C b; + C c; +}; + +int main() { + T<int> v; + +#pragma omp target map(tofrom: v, v.y, v.z, v.a) + { + v.y++; + v.z += 2; + v.a += 3; + } + + return 0; +} + +// CHECK: [[CSTSZ:@.+]] = private {{.*}}constant [7 x i64] [i64 0, i64 0, i64 0, i64 0, i64 4, i64 1, i64 4] +// CHECK: [[CSTTY:@.+]] = private {{.*}}constant [7 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [7 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill four non-constant size elements here: the whole struct size, the region +// covering v.x, the region covering padding after v.z and the region covering +// v.b and v.c. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[X:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[X]], align 8 +// CHECK-DAG: [[PAD:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 2 +// CHECK-DAG: store i64 %{{.+}}, ptr [[PAD]], align 8 +// CHECK-DAG: [[BC:%.+]] = getelementptr inbounds [7 x i64], ptr [[SIZES]], i32 0, i32 3 +// CHECK-DAG: store i64 %{{.+}}, ptr [[BC]], align 8 diff --git a/clang/test/OpenMP/copy-gaps-6.cpp b/clang/test/OpenMP/copy-gaps-6.cpp new file mode 100644 index 0000000..9c62fde --- /dev/null +++ b/clang/test/OpenMP/copy-gaps-6.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +struct S { + int x; + int *arr; + int y; + int z; +}; + +int main() { + S v; + +#pragma omp target map(tofrom: v, v.x, v.z) + { + v.x++; + v.y += 2; + v.z += 3; + } + +#pragma omp target map(tofrom: v, v.x, v.arr[:1]) + { + v.x++; + v.y += 2; + v.arr[0] += 2; + v.z += 4; + } + +#pragma omp target map(tofrom: v, v.arr[:1]) + { + v.x++; + v.y += 2; + v.arr[0] += 2; + v.z += 4; + } + + return 0; +} + +// CHECK: [[CSTSZ0:@.+]] = private {{.*}}constant [4 x i64] [i64 0, i64 0, i64 4, i64 4] +// CHECK: [[CSTTY0:@.+]] = private {{.*}}constant [4 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]]] + +// CHECK: [[CSTSZ1:@.+]] = private {{.*}}constant [4 x i64] [i64 0, i64 0, i64 4, i64 4] +// CHECK: [[CSTTY1:@.+]] = private {{.*}}constant [4 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000003]], i64 [[#0x1000000000013]]] + +// CHECK: [[CSTSZ2:@.+]] = private {{.*}}constant [3 x i64] [i64 0, i64 24, i64 4] +// CHECK: [[CSTTY2:@.+]] = private {{.*}}constant [3 x i64] [i64 [[#0x20]], i64 [[#0x1000000000003]], i64 [[#0x1000000000013]]] + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [4 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill two non-constant size elements here: the whole struct size, and the +// region covering v.arr and v.y. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [4 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[ARRY:%.+]] = getelementptr inbounds [4 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[ARRY]], align 8 + +// CHECK: call void + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [4 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill two non-constant size elements here: the whole struct size, and the +// region covering v.arr, v.y and v.z. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [4 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 +// CHECK-DAG: [[ARRYZ:%.+]] = getelementptr inbounds [4 x i64], ptr [[SIZES]], i32 0, i32 1 +// CHECK-DAG: store i64 %{{.+}}, ptr [[ARRYZ]], align 8 + +// CHECK: call void + +// CHECK-DAG: call i32 @__tgt_target_kernel(ptr @{{.+}}, i64 -1, i32 -1, i32 0, ptr @.{{.+}}.region_id, ptr [[ARGS:%.+]]) +// CHECK-DAG: [[KSIZE:%.+]] = getelementptr inbounds {{.+}}[[ARGS]], i32 0, i32 4 +// CHECK-DAG: store ptr [[SZBASE:%.+]], ptr [[KSIZE]], align 8 +// CHECK-DAG: [[SZBASE]] = getelementptr inbounds [3 x i64], ptr [[SIZES:%[^,]*]], i32 0, i32 0 + +// Fill one non-constant size element here: the whole struct size. + +// CHECK-DAG: [[STR:%.+]] = getelementptr inbounds [3 x i64], ptr [[SIZES]], i32 0, i32 0 +// CHECK-DAG: store i64 %{{.+}}, ptr [[STR]], align 8 diff --git a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp index c14e19c..e98a23e 100644 --- a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp +++ b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp @@ -38,11 +38,11 @@ #ifndef HEADER #define HEADER -void foo_v1(float *AAA, float *BBB, int *I) {return;} -void foo_v2(float *AAA, float *BBB, int *I) {return;} -void foo_v3(float *AAA, float *BBB, int *I) {return;} +void foo_v1(float *AAA, float *BBB, int &CCC, int *I) {return;} +void foo_v2(float *AAA, float *BBB, int &CCC, int *I) {return;} +void foo_v3(float *AAA, float *BBB, int &CCC, int *I) {return;} -//DUMP: FunctionDecl{{.*}} foo 'void (float *, float *, int *)' +//DUMP: FunctionDecl{{.*}} foo 'void (float *, float *, int &, int *)' //DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86, x86_64)} //DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v3 //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'I' @@ -54,9 +54,9 @@ void foo_v3(float *AAA, float *BBB, int *I) {return;} //DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v1 //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' -//PRINT: #pragma omp declare variant(foo_v3) match(construct={dispatch}, device={arch(x86, x86_64)}) adjust_args(nothing:I) adjust_args(need_device_ptr:BBB) adjust_args(need_device_addr:AAA) +//PRINT: #pragma omp declare variant(foo_v3) match(construct={dispatch}, device={arch(x86, x86_64)}) adjust_args(nothing:I) adjust_args(need_device_ptr:BBB) adjust_args(need_device_addr:CCC) -//PRINT: #pragma omp declare variant(foo_v2) match(construct={dispatch}, device={arch(ppc)}) adjust_args(need_device_ptr:AAA) adjust_args(need_device_addr:BBB) +//PRINT: #pragma omp declare variant(foo_v2) match(construct={dispatch}, device={arch(ppc)}) adjust_args(need_device_ptr:AAA) adjust_args(need_device_addr:CCC) //PRINT: omp declare variant(foo_v1) match(construct={dispatch}, device={arch(arm)}) adjust_args(need_device_ptr:AAA,BBB) @@ -67,33 +67,33 @@ void foo_v3(float *AAA, float *BBB, int *I) {return;} #pragma omp declare variant(foo_v2) \ match(construct={dispatch}, device={arch(ppc)}), \ adjust_args(need_device_ptr:AAA) \ - adjust_args(need_device_addr:BBB) + adjust_args(need_device_addr:CCC) #pragma omp declare variant(foo_v3) \ adjust_args(need_device_ptr:BBB) adjust_args(nothing:I) \ - adjust_args(need_device_addr:AAA) \ + adjust_args(need_device_addr:CCC) \ match(construct={dispatch}, device={arch(x86,x86_64)}) -void foo(float *AAA, float *BBB, int *I) {return;} +void foo(float *AAA, float *BBB, int &CCC, int *I) {return;} -void Foo_Var(float *AAA, float *BBB, float *CCC) {return;} +void Foo_Var(float *AAA, float *BBB, float *&CCC) {return;} #pragma omp declare variant(Foo_Var) \ match(construct={dispatch}, device={arch(x86_64)}) \ adjust_args(need_device_ptr:AAA) adjust_args(nothing:BBB) \ adjust_args(need_device_addr:CCC) template<typename T> -void Foo(T *AAA, T *BBB, T *CCC) {return;} +void Foo(T *AAA, T *BBB, T *&CCC) {return;} //PRINT: #pragma omp declare variant(Foo_Var) match(construct={dispatch}, device={arch(x86_64)}) adjust_args(nothing:BBB) adjust_args(need_device_ptr:AAA) adjust_args(need_device_addr:CCC) -//DUMP: FunctionDecl{{.*}} Foo 'void (T *, T *, T *)' +//DUMP: FunctionDecl{{.*}} Foo 'void (T *, T *, T *&)' //DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} //DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'CCC' // -//DUMP: FunctionDecl{{.*}} Foo 'void (float *, float *, float *)' +//DUMP: FunctionDecl{{.*}} Foo 'void (float *, float *, float *&)' //DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} //DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' diff --git a/clang/test/OpenMP/declare_variant_clauses_messages.cpp b/clang/test/OpenMP/declare_variant_clauses_messages.cpp index bca9148..916d15f 100644 --- a/clang/test/OpenMP/declare_variant_clauses_messages.cpp +++ b/clang/test/OpenMP/declare_variant_clauses_messages.cpp @@ -91,6 +91,7 @@ void foo_v1(float *AAA, float *BBB, int *I) { return; } void foo_v2(float *AAA, float *BBB, int *I) { return; } void foo_v3(float *AAA, float *BBB, int *I) { return; } void foo_v4(float *AAA, float *BBB, int *I, omp_interop_t IOp) { return; } +void foo_v5(float *AAA, float *BBB, int I) { return; } #if _OPENMP >= 202011 // At least OpenMP 5.1 void vararg_foo(const char *fmt, omp_interop_t it, ...); @@ -129,6 +130,11 @@ void vararg_bar2(const char *fmt) { return; } adjust_args(nothing:J) \ match(construct={dispatch}, device={arch(x86,x86_64)}) +// expected-error@+2 {{expected reference type argument on 'adjust_args' clause with 'need_device_addr' modifier}} +#pragma omp declare variant(foo_v1) \ + adjust_args(need_device_addr:AAA) \ + match(construct={dispatch}, device={arch(x86,x86_64)}) + // expected-error@+2 {{expected reference to one of the parameters of function 'foo'}} #pragma omp declare variant(foo_v3) \ adjust_args(nothing:Other) \ @@ -218,6 +224,12 @@ void vararg_bar2(const char *fmt) { return; } void foo(float *AAA, float *BBB, int *I) { return; } +// expected-error@+2 {{expected reference type argument on 'adjust_args' clause with 'need_device_addr' modifier}} +#pragma omp declare variant(foo_v5) \ + adjust_args(need_device_addr:I) \ + match(construct={dispatch}, device={arch(x86,x86_64)}) +void foo5(float *AAA, float *BBB, int I) { return; } + #endif // NO_INTEROP_T_DEF #ifdef C diff --git a/clang/test/OpenMP/target_map_array_section_no_length_codegen.cpp b/clang/test/OpenMP/target_map_array_section_no_length_codegen.cpp new file mode 100644 index 0000000..43fd509 --- /dev/null +++ b/clang/test/OpenMP/target_map_array_section_no_length_codegen.cpp @@ -0,0 +1,361 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ --version 5 +// RUN: %clang_cc1 -verify -triple i386-unknown-unknown -fopenmp -fopenmp-version=60 -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s + +// RUN: %clang_cc1 -verify -triple i386-unknown-unknown -fopenmp -fopenmp-version=60 -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s +// RUN: %clang_cc1 -verify -triple i386-unknown-unknown -fopenmp -fopenmp-version=60 -fopenmp-targets=i386-pc-linux-gnu -include-pch %t -emit-llvm %s -o - | FileCheck %s + +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER +void array_section_no_length_map_clause(float *d, int index) { + float **f; + + #pragma omp target map(tofrom : d[:]) + { + d[3] += 2; + } + + #pragma omp target map(to : d[2:]) + { + d[3] += 3; + } + + #pragma omp target map(alloc : f[index][:]) + { + f[index][2] += 4; + } + + #pragma omp target map(tofrom : f[index][index+1:]) + { + f[index][index] += 5; + } +} +#endif +// CHECK-LABEL: define dso_local void @_Z34array_section_no_length_map_clausePfi( +// CHECK-SAME: ptr noundef [[D:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[D_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[F:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_PTRS:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[KERNEL_ARGS:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS:%.*]], align 8 +// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS2:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_PTRS3:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS4:%.*]] = alloca [1 x ptr], align 4 +// CHECK-NEXT: [[KERNEL_ARGS5:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK-NEXT: [[INDEX_CASTED:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS11:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_PTRS12:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS13:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[KERNEL_ARGS14:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK-NEXT: [[INDEX_CASTED17:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOFFLOAD_BASEPTRS22:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_PTRS23:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_MAPPERS24:%.*]] = alloca [3 x ptr], align 4 +// CHECK-NEXT: [[DOTOFFLOAD_SIZES:%.*]] = alloca [3 x i64], align 4 +// CHECK-NEXT: [[KERNEL_ARGS25:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8 +// CHECK-NEXT: store ptr [[D]], ptr [[D_ADDR]], align 4 +// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw float, ptr [[TMP2]], i32 0 +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[TMP1]], ptr [[TMP3]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[TMP4]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS]], i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr [[TMP5]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0 +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0 +// CHECK-NEXT: store i32 3, ptr [[TMP8]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 1 +// CHECK-NEXT: store i32 1, ptr [[TMP9]], align 4 +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP6]], ptr [[TMP10]], align 4 +// CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 3 +// CHECK-NEXT: store ptr [[TMP7]], ptr [[TMP11]], align 4 +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 4 +// CHECK-NEXT: store ptr @.offload_sizes, ptr [[TMP12]], align 4 +// CHECK-NEXT: [[TMP13:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 5 +// CHECK-NEXT: store ptr @.offload_maptypes, ptr [[TMP13]], align 4 +// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 6 +// CHECK-NEXT: store ptr null, ptr [[TMP14]], align 4 +// CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 7 +// CHECK-NEXT: store ptr null, ptr [[TMP15]], align 4 +// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 8 +// CHECK-NEXT: store i64 0, ptr [[TMP16]], align 8 +// CHECK-NEXT: [[TMP17:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 9 +// CHECK-NEXT: store i64 0, ptr [[TMP17]], align 8 +// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 10 +// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP18]], align 4 +// CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 11 +// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP19]], align 4 +// CHECK-NEXT: [[TMP20:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12 +// CHECK-NEXT: store i32 0, ptr [[TMP20]], align 4 +// CHECK-NEXT: [[TMP21:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1:[0-9]+]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l14.region_id, ptr [[KERNEL_ARGS]]) +// CHECK-NEXT: [[TMP22:%.*]] = icmp ne i32 [[TMP21]], 0 +// CHECK-NEXT: br i1 [[TMP22]], label %[[OMP_OFFLOAD_FAILED:.*]], label %[[OMP_OFFLOAD_CONT:.*]] +// CHECK: [[OMP_OFFLOAD_FAILED]]: +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l14(ptr [[TMP0]]) #[[ATTR2:[0-9]+]] +// CHECK-NEXT: br label %[[OMP_OFFLOAD_CONT]] +// CHECK: [[OMP_OFFLOAD_CONT]]: +// CHECK-NEXT: [[TMP23:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP24:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw float, ptr [[TMP25]], i32 2 +// CHECK-NEXT: [[TMP26:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS2]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[TMP24]], ptr [[TMP26]], align 4 +// CHECK-NEXT: [[TMP27:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS3]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[ARRAYIDX1]], ptr [[TMP27]], align 4 +// CHECK-NEXT: [[TMP28:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS4]], i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr [[TMP28]], align 4 +// CHECK-NEXT: [[TMP29:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS2]], i32 0, i32 0 +// CHECK-NEXT: [[TMP30:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS3]], i32 0, i32 0 +// CHECK-NEXT: [[TMP31:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 0 +// CHECK-NEXT: store i32 3, ptr [[TMP31]], align 4 +// CHECK-NEXT: [[TMP32:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 1 +// CHECK-NEXT: store i32 1, ptr [[TMP32]], align 4 +// CHECK-NEXT: [[TMP33:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP29]], ptr [[TMP33]], align 4 +// CHECK-NEXT: [[TMP34:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 3 +// CHECK-NEXT: store ptr [[TMP30]], ptr [[TMP34]], align 4 +// CHECK-NEXT: [[TMP35:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 4 +// CHECK-NEXT: store ptr @.offload_sizes.1, ptr [[TMP35]], align 4 +// CHECK-NEXT: [[TMP36:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 5 +// CHECK-NEXT: store ptr @.offload_maptypes.2, ptr [[TMP36]], align 4 +// CHECK-NEXT: [[TMP37:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 6 +// CHECK-NEXT: store ptr null, ptr [[TMP37]], align 4 +// CHECK-NEXT: [[TMP38:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 7 +// CHECK-NEXT: store ptr null, ptr [[TMP38]], align 4 +// CHECK-NEXT: [[TMP39:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 8 +// CHECK-NEXT: store i64 0, ptr [[TMP39]], align 8 +// CHECK-NEXT: [[TMP40:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 9 +// CHECK-NEXT: store i64 0, ptr [[TMP40]], align 8 +// CHECK-NEXT: [[TMP41:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 10 +// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP41]], align 4 +// CHECK-NEXT: [[TMP42:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 11 +// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP42]], align 4 +// CHECK-NEXT: [[TMP43:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 12 +// CHECK-NEXT: store i32 0, ptr [[TMP43]], align 4 +// CHECK-NEXT: [[TMP44:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l19.region_id, ptr [[KERNEL_ARGS5]]) +// CHECK-NEXT: [[TMP45:%.*]] = icmp ne i32 [[TMP44]], 0 +// CHECK-NEXT: br i1 [[TMP45]], label %[[OMP_OFFLOAD_FAILED6:.*]], label %[[OMP_OFFLOAD_CONT7:.*]] +// CHECK: [[OMP_OFFLOAD_FAILED6]]: +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l19(ptr [[TMP23]]) #[[ATTR2]] +// CHECK-NEXT: br label %[[OMP_OFFLOAD_CONT7]] +// CHECK: [[OMP_OFFLOAD_CONT7]]: +// CHECK-NEXT: [[TMP46:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP47:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP47]], ptr [[INDEX_CASTED]], align 4 +// CHECK-NEXT: [[TMP48:%.*]] = load i32, ptr [[INDEX_CASTED]], align 4 +// CHECK-NEXT: [[TMP49:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP50:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP51:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds ptr, ptr [[TMP50]], i32 [[TMP51]] +// CHECK-NEXT: [[TMP52:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP53:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX9:%.*]] = getelementptr inbounds ptr, ptr [[TMP52]], i32 [[TMP53]] +// CHECK-NEXT: [[TMP54:%.*]] = load ptr, ptr [[ARRAYIDX9]], align 4 +// CHECK-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds nuw float, ptr [[TMP54]], i32 0 +// CHECK-NEXT: [[TMP55:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS11]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[TMP49]], ptr [[TMP55]], align 4 +// CHECK-NEXT: [[TMP56:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS12]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[ARRAYIDX8]], ptr [[TMP56]], align 4 +// CHECK-NEXT: [[TMP57:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS13]], i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr [[TMP57]], align 4 +// CHECK-NEXT: [[TMP58:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS11]], i32 0, i32 1 +// CHECK-NEXT: store ptr [[ARRAYIDX8]], ptr [[TMP58]], align 4 +// CHECK-NEXT: [[TMP59:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS12]], i32 0, i32 1 +// CHECK-NEXT: store ptr [[ARRAYIDX10]], ptr [[TMP59]], align 4 +// CHECK-NEXT: [[TMP60:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS13]], i32 0, i32 1 +// CHECK-NEXT: store ptr null, ptr [[TMP60]], align 4 +// CHECK-NEXT: [[TMP61:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS11]], i32 0, i32 2 +// CHECK-NEXT: store i32 [[TMP48]], ptr [[TMP61]], align 4 +// CHECK-NEXT: [[TMP62:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS12]], i32 0, i32 2 +// CHECK-NEXT: store i32 [[TMP48]], ptr [[TMP62]], align 4 +// CHECK-NEXT: [[TMP63:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS13]], i32 0, i32 2 +// CHECK-NEXT: store ptr null, ptr [[TMP63]], align 4 +// CHECK-NEXT: [[TMP64:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS11]], i32 0, i32 0 +// CHECK-NEXT: [[TMP65:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS12]], i32 0, i32 0 +// CHECK-NEXT: [[TMP66:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 0 +// CHECK-NEXT: store i32 3, ptr [[TMP66]], align 4 +// CHECK-NEXT: [[TMP67:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 1 +// CHECK-NEXT: store i32 3, ptr [[TMP67]], align 4 +// CHECK-NEXT: [[TMP68:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP64]], ptr [[TMP68]], align 4 +// CHECK-NEXT: [[TMP69:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 3 +// CHECK-NEXT: store ptr [[TMP65]], ptr [[TMP69]], align 4 +// CHECK-NEXT: [[TMP70:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 4 +// CHECK-NEXT: store ptr @.offload_sizes.3, ptr [[TMP70]], align 4 +// CHECK-NEXT: [[TMP71:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 5 +// CHECK-NEXT: store ptr @.offload_maptypes.4, ptr [[TMP71]], align 4 +// CHECK-NEXT: [[TMP72:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 6 +// CHECK-NEXT: store ptr null, ptr [[TMP72]], align 4 +// CHECK-NEXT: [[TMP73:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 7 +// CHECK-NEXT: store ptr null, ptr [[TMP73]], align 4 +// CHECK-NEXT: [[TMP74:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 8 +// CHECK-NEXT: store i64 0, ptr [[TMP74]], align 8 +// CHECK-NEXT: [[TMP75:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 9 +// CHECK-NEXT: store i64 0, ptr [[TMP75]], align 8 +// CHECK-NEXT: [[TMP76:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 10 +// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP76]], align 4 +// CHECK-NEXT: [[TMP77:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 11 +// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP77]], align 4 +// CHECK-NEXT: [[TMP78:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS14]], i32 0, i32 12 +// CHECK-NEXT: store i32 0, ptr [[TMP78]], align 4 +// CHECK-NEXT: [[TMP79:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l24.region_id, ptr [[KERNEL_ARGS14]]) +// CHECK-NEXT: [[TMP80:%.*]] = icmp ne i32 [[TMP79]], 0 +// CHECK-NEXT: br i1 [[TMP80]], label %[[OMP_OFFLOAD_FAILED15:.*]], label %[[OMP_OFFLOAD_CONT16:.*]] +// CHECK: [[OMP_OFFLOAD_FAILED15]]: +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l24(ptr [[TMP46]], i32 [[TMP48]]) #[[ATTR2]] +// CHECK-NEXT: br label %[[OMP_OFFLOAD_CONT16]] +// CHECK: [[OMP_OFFLOAD_CONT16]]: +// CHECK-NEXT: [[TMP81:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP82:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP82]], ptr [[INDEX_CASTED17]], align 4 +// CHECK-NEXT: [[TMP83:%.*]] = load i32, ptr [[INDEX_CASTED17]], align 4 +// CHECK-NEXT: [[TMP84:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP85:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP86:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX18:%.*]] = getelementptr inbounds ptr, ptr [[TMP85]], i32 [[TMP86]] +// CHECK-NEXT: [[TMP87:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP87]], 1 +// CHECK-NEXT: [[TMP88:%.*]] = load ptr, ptr [[F]], align 4 +// CHECK-NEXT: [[TMP89:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX19:%.*]] = getelementptr inbounds ptr, ptr [[TMP88]], i32 [[TMP89]] +// CHECK-NEXT: [[TMP90:%.*]] = load ptr, ptr [[ARRAYIDX19]], align 4 +// CHECK-NEXT: [[ARRAYIDX20:%.*]] = getelementptr inbounds nuw float, ptr [[TMP90]], i32 [[ADD]] +// CHECK-NEXT: [[TMP91:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ADD21:%.*]] = add nsw i32 [[TMP91]], 1 +// CHECK-NEXT: [[TMP92:%.*]] = mul nuw i32 [[ADD21]], 4 +// CHECK-NEXT: [[TMP93:%.*]] = icmp ugt i32 4, [[TMP92]] +// CHECK-NEXT: [[TMP94:%.*]] = sub nuw i32 4, [[TMP92]] +// CHECK-NEXT: [[TMP95:%.*]] = select i1 [[TMP93]], i32 [[TMP94]], i32 0 +// CHECK-NEXT: [[TMP96:%.*]] = sext i32 [[TMP95]] to i64 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[DOTOFFLOAD_SIZES]], ptr align 4 @.offload_sizes.5, i32 24, i1 false) +// CHECK-NEXT: [[TMP97:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS22]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[TMP84]], ptr [[TMP97]], align 4 +// CHECK-NEXT: [[TMP98:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS23]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[ARRAYIDX18]], ptr [[TMP98]], align 4 +// CHECK-NEXT: [[TMP99:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS24]], i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr [[TMP99]], align 4 +// CHECK-NEXT: [[TMP100:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS22]], i32 0, i32 1 +// CHECK-NEXT: store ptr [[ARRAYIDX18]], ptr [[TMP100]], align 4 +// CHECK-NEXT: [[TMP101:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS23]], i32 0, i32 1 +// CHECK-NEXT: store ptr [[ARRAYIDX20]], ptr [[TMP101]], align 4 +// CHECK-NEXT: [[TMP102:%.*]] = getelementptr inbounds [3 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 1 +// CHECK-NEXT: store i64 [[TMP96]], ptr [[TMP102]], align 4 +// CHECK-NEXT: [[TMP103:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS24]], i32 0, i32 1 +// CHECK-NEXT: store ptr null, ptr [[TMP103]], align 4 +// CHECK-NEXT: [[TMP104:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS22]], i32 0, i32 2 +// CHECK-NEXT: store i32 [[TMP83]], ptr [[TMP104]], align 4 +// CHECK-NEXT: [[TMP105:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS23]], i32 0, i32 2 +// CHECK-NEXT: store i32 [[TMP83]], ptr [[TMP105]], align 4 +// CHECK-NEXT: [[TMP106:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_MAPPERS24]], i32 0, i32 2 +// CHECK-NEXT: store ptr null, ptr [[TMP106]], align 4 +// CHECK-NEXT: [[TMP107:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_BASEPTRS22]], i32 0, i32 0 +// CHECK-NEXT: [[TMP108:%.*]] = getelementptr inbounds [3 x ptr], ptr [[DOTOFFLOAD_PTRS23]], i32 0, i32 0 +// CHECK-NEXT: [[TMP109:%.*]] = getelementptr inbounds [3 x i64], ptr [[DOTOFFLOAD_SIZES]], i32 0, i32 0 +// CHECK-NEXT: [[TMP110:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 0 +// CHECK-NEXT: store i32 3, ptr [[TMP110]], align 4 +// CHECK-NEXT: [[TMP111:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 1 +// CHECK-NEXT: store i32 3, ptr [[TMP111]], align 4 +// CHECK-NEXT: [[TMP112:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP107]], ptr [[TMP112]], align 4 +// CHECK-NEXT: [[TMP113:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 3 +// CHECK-NEXT: store ptr [[TMP108]], ptr [[TMP113]], align 4 +// CHECK-NEXT: [[TMP114:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 4 +// CHECK-NEXT: store ptr [[TMP109]], ptr [[TMP114]], align 4 +// CHECK-NEXT: [[TMP115:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 5 +// CHECK-NEXT: store ptr @.offload_maptypes.6, ptr [[TMP115]], align 4 +// CHECK-NEXT: [[TMP116:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 6 +// CHECK-NEXT: store ptr null, ptr [[TMP116]], align 4 +// CHECK-NEXT: [[TMP117:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 7 +// CHECK-NEXT: store ptr null, ptr [[TMP117]], align 4 +// CHECK-NEXT: [[TMP118:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 8 +// CHECK-NEXT: store i64 0, ptr [[TMP118]], align 8 +// CHECK-NEXT: [[TMP119:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 9 +// CHECK-NEXT: store i64 0, ptr [[TMP119]], align 8 +// CHECK-NEXT: [[TMP120:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 10 +// CHECK-NEXT: store [3 x i32] [i32 -1, i32 0, i32 0], ptr [[TMP120]], align 4 +// CHECK-NEXT: [[TMP121:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 11 +// CHECK-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP121]], align 4 +// CHECK-NEXT: [[TMP122:%.*]] = getelementptr inbounds nuw [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS25]], i32 0, i32 12 +// CHECK-NEXT: store i32 0, ptr [[TMP122]], align 4 +// CHECK-NEXT: [[TMP123:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB1]], i64 -1, i32 -1, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l29.region_id, ptr [[KERNEL_ARGS25]]) +// CHECK-NEXT: [[TMP124:%.*]] = icmp ne i32 [[TMP123]], 0 +// CHECK-NEXT: br i1 [[TMP124]], label %[[OMP_OFFLOAD_FAILED26:.*]], label %[[OMP_OFFLOAD_CONT27:.*]] +// CHECK: [[OMP_OFFLOAD_FAILED26]]: +// CHECK-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l29(ptr [[TMP81]], i32 [[TMP83]]) #[[ATTR2]] +// CHECK-NEXT: br label %[[OMP_OFFLOAD_CONT27]] +// CHECK: [[OMP_OFFLOAD_CONT27]]: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l14( +// CHECK-SAME: ptr noundef [[D:%.*]]) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[D_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: store ptr [[D]], ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr [[TMP0]], i32 3 +// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], 2.000000e+00 +// CHECK-NEXT: store float [[ADD]], ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l19( +// CHECK-SAME: ptr noundef [[D:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[D_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: store ptr [[D]], ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[D_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr [[TMP0]], i32 3 +// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], 3.000000e+00 +// CHECK-NEXT: store float [[ADD]], ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l24( +// CHECK-SAME: ptr noundef [[F:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[F_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[F]], ptr [[F_ADDR]], align 4 +// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i32 [[TMP1]] +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds float, ptr [[TMP2]], i32 2 +// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[ARRAYIDX1]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP3]], 4.000000e+00 +// CHECK-NEXT: store float [[ADD]], ptr [[ARRAYIDX1]], align 4 +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z34array_section_no_length_map_clausePfi_l29( +// CHECK-SAME: ptr noundef [[F:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[F_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[F]], ptr [[F_ADDR]], align 4 +// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i32 [[TMP1]] +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4 +// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds float, ptr [[TMP2]], i32 [[TMP3]] +// CHECK-NEXT: [[TMP4:%.*]] = load float, ptr [[ARRAYIDX1]], align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP4]], 5.000000e+00 +// CHECK-NEXT: store float [[ADD]], ptr [[ARRAYIDX1]], align 4 +// CHECK-NEXT: ret void +// diff --git a/clang/test/OpenMP/target_map_codegen_35.cpp b/clang/test/OpenMP/target_map_codegen_35.cpp index afa0965..c4fc49c 100644 --- a/clang/test/OpenMP/target_map_codegen_35.cpp +++ b/clang/test/OpenMP/target_map_codegen_35.cpp @@ -27,11 +27,11 @@ public: void foo(); }; -// CK35-DAG: [[SIZE_TO:@.+]] = private {{.*}}constant [4 x i64] [i64 0, i64 0, i64 0, i64 8] +// CK35-DAG: [[SIZE_TO:@.+]] = private {{.*}}constant [3 x i64] [i64 0, i64 0, i64 8] // TARGET_PARAM = 0x20 // MEMBER_OF_1 | TO = 0x1000000000001 // MEMBER_OF_1 | PTR_AND_OBJ | TO = 0x1000000000011 -// CK35-DAG: [[MTYPE_TO:@.+]] = {{.+}}constant [4 x i64] [i64 [[#0x20]], i64 [[#0x1000000000001]], i64 [[#0x1000000000001]], i64 [[#0x1000000000011]]] +// CK35-DAG: [[MTYPE_TO:@.+]] = {{.+}}constant [3 x i64] [i64 [[#0x20]], i64 [[#0x1000000000001]], i64 [[#0x1000000000011]]] // CK35-DAG: [[SIZE_FROM:@.+]] = private {{.*}}constant [2 x i64] [i64 0, i64 8] // TARGET_PARAM = 0x20 // MEMBER_OF_1 | PTR_AND_OBJ | FROM = 0x1000000000012 @@ -86,35 +86,14 @@ void ref_map() { // CK35-DAG: [[B_BEGIN_INTPTR]] = ptrtoint ptr [[B_BEGIN_VOID:%.+]] to i64 // CK35-DAG: [[B_ADDR:%.+]] = getelementptr inbounds nuw %class.S, ptr [[S_ADDR]], i32 0, i32 1 - // pass MEMBER_OF_1 | TO {&s, &s.b+1, ((ptr)(&s+1)-(ptr)(&s.b+1))} to copy the data of remainder of s. + // pass MEMBER_OF_1 | PTR_AND_OBJ | TO {&s, &s.b, 8|4} to copy the data of s.b. // CK35-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2 // CK35-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2 - // CK35-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2 // CK35-DAG: store ptr [[S_ADDR]], ptr [[BP2]], - // CK35-DAG: store ptr [[B_END:%.+]], ptr [[P2]], - // CK35-DAG: store i64 [[REM_SIZE:%.+]], ptr [[S2]], - - // CK35-DAG: [[B_END]] = getelementptr ptr, ptr [[B_ADDR]], i{{.+}} 1 - - // CK35-DAG: [[REM_SIZE]] = sdiv exact i64 [[SZ:%.+]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) - // CK35-DAG: [[SZ]] = sub i64 [[S_END_INTPTR:%.+]], [[B_END_INTPTR:%.+]] - // CK35-DAG: [[B_END_INTPTR]] = ptrtoint ptr [[B_END_VOID:%.+]] to i64 - // CK35-DAG: [[S_END_INTPTR]] = ptrtoint ptr [[S_END_VOID:%.+]] to i64 - // CK35-DAG: [[S_END_VOID]] = getelementptr i8, ptr [[S_LAST:%.+]], i{{.+}} 1 - // CK35-64-DAG: [[S_LAST]] = getelementptr i8, ptr [[S_VOIDPTR:%.+]], i64 15 - // CK35-32-DAG: [[S_LAST]] = getelementptr i8, ptr [[S_VOIDPTR:%.+]], i32 7 - - // pass MEMBER_OF_1 | PTR_AND_OBJ | TO {&s, &s.b, 8|4} to copy the data of s.b. - - // CK35-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3 - // CK35-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3 - - - // CK35-DAG: store ptr [[S_ADDR]], ptr [[BP3]], - // CK35-DAG: store ptr [[B_ADDR:%.+]], ptr [[P3]], + // CK35-DAG: store ptr [[B_ADDR:%.+]], ptr [[P2]], // CK35-DAG: [[B_ADDR]] = load ptr, ptr [[B_REF:%.+]], align {{[0-9]+}}, !nonnull !{{[0-9]+}}, !align !{{[0-9]+}} // CK35-DAG: [[B_REF]] = getelementptr inbounds nuw %class.S, ptr [[S_ADDR]], i32 0, i32 1 diff --git a/clang/test/OpenMP/target_map_messages.cpp b/clang/test/OpenMP/target_map_messages.cpp index 4a026584..0ee70be 100644 --- a/clang/test/OpenMP/target_map_messages.cpp +++ b/clang/test/OpenMP/target_map_messages.cpp @@ -122,9 +122,9 @@ struct SA { {} #pragma omp target map(always, tofrom: c,f[1:2]) {} - #pragma omp target map(always, tofrom: c[:],f) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(always, tofrom: c[:],f) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} - #pragma omp target map(always, tofrom: c,f[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(always, tofrom: c,f[:]) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} #pragma omp target map(always) // expected-error {{use of undeclared identifier 'always'}} {} @@ -134,9 +134,9 @@ struct SA { {} #pragma omp target map(self, tofrom: c,f[1:2]) // lt60-error {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} {} - #pragma omp target map(self, tofrom: c[:],f) // lt60-error {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(self, tofrom: c[:],f) // lt60-error {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} - #pragma omp target map(self, tofrom: c,f[:]) // lt60-error {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(self, tofrom: c,f[:]) // lt60-error {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} #pragma omp target map(close, tofrom: c,f) {} @@ -144,9 +144,9 @@ struct SA { {} #pragma omp target map(close, tofrom: c,f[1:2]) {} - #pragma omp target map(close, tofrom: c[:],f) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(close, tofrom: c[:],f) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} - #pragma omp target map(close, tofrom: c,f[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + #pragma omp target map(close, tofrom: c,f[:]) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} #pragma omp target map(close) // expected-error {{use of undeclared identifier 'close'}} {} @@ -159,11 +159,11 @@ struct SA { // lt51-error@+1 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} #pragma omp target map(present, tofrom: c,f[1:2]) {} - // expected-error@+2 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + // lt60-error@+2 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} // lt51-error@+1 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} #pragma omp target map(present, tofrom: c[:],f) {} - // expected-error@+2 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + // lt60-error@+2 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} // lt51-error@+1 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} #pragma omp target map(present, tofrom: c,f[:]) {} @@ -190,14 +190,14 @@ struct SA { {} // ge60-error@+5 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present', 'iterator', 'self}} // ge52-error@+4 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present', 'iterator'}} - // expected-error@+3 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + // lt60-error@+3 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} // ge51-omp-error@+2 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present'}} // lt51-omp-error@+1 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} #pragma omp target map(ompx_hold, tofrom: c[:],f) {} // ge60-error@+5 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present', 'iterator', 'self}} // ge52-error@+4 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present', 'iterator'}} - // expected-error@+3 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} + // lt60-error@+3 {{section length is unspecified and cannot be inferred because subscripted value is not an array}} // ge51-omp-error@+2 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper', 'present'}} // lt51-omp-error@+1 {{incorrect map type modifier, expected one of: 'always', 'close', 'mapper'}} #pragma omp target map(ompx_hold, tofrom: c,f[:]) @@ -448,7 +448,7 @@ void SAclient(int arg) { {} #pragma omp target map(mptr[:1][:2] [0:2]) // expected-error {{array section does not specify contiguous storage}} {} -#pragma omp target map(mptr[:1][:] [0:2]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} +#pragma omp target map(mptr[:1][:] [0:2]) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} #pragma omp target map(mptr[:2][:1] [0:2]) // expected-error {{array section does not specify contiguous storage}} {} @@ -517,7 +517,7 @@ void SAclient(int arg) { {} #pragma omp target map(r.S.Ptr [4:5]) {} -#pragma omp target map(r.S.Ptr[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} +#pragma omp target map(r.S.Ptr[:]) // lt60-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} {} #pragma omp target map((p + 1)->A) // lt50-error {{expected expression containing only member accesses and/or array sections based on named variables}} {} diff --git a/clang/test/Sema/implicit-special-member-deprecated.cpp b/clang/test/Sema/implicit-special-member-deprecated.cpp new file mode 100644 index 0000000..8e23404 --- /dev/null +++ b/clang/test/Sema/implicit-special-member-deprecated.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++20 -Wdeprecated-declarations -verify %s + +struct A { + [[deprecated("use something else")]] int x = 42; // expected-note {{marked deprecated here}} +}; + +A makeDefaultA() { return {}; } // ctor is implicit → no warn +A copyA(const A &a) { return a; } // copy-ctor implicit → no warn + +void assignA() { + A a, b; + a = b; // copy-assign implicit → no warn +} + +void useA() { + A a; + (void)a.x; // expected-warning {{is deprecated}} +} + +// Explicitly-defaulted ctor – now silent +struct B { + [[deprecated]] int y; + B() = default; // no warning under new policy +}; diff --git a/clang/test/Sema/unsupported-arm-streaming.cpp b/clang/test/Sema/unsupported-arm-streaming.cpp new file mode 100644 index 0000000..8693dd6 --- /dev/null +++ b/clang/test/Sema/unsupported-arm-streaming.cpp @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s + +void arm_streaming(void) __arm_streaming {} // expected-error {{'__arm_streaming' is not supported on this target}} diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp index 16f5f82..312a778 100644 --- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp +++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp @@ -383,3 +383,17 @@ namespace enable_if_2 { } } } + +namespace GH150015 { + extern int (& c)[8]; // interpreter-note {{declared here}} + constexpr int x = c <= c+8; // interpreter-error {{constexpr variable 'x' must be initialized by a constant expression}} \ + // interpreter-note {{initializer of 'c' is unknown}} + + struct X {}; + struct Y {}; + struct Z : X, Y {}; + extern Z &z; // interpreter-note{{declared here}} + constexpr int bases = (void*)(X*)&z <= (Y*)&z; // expected-error {{constexpr variable 'bases' must be initialized by a constant expression}} \ + // nointerpreter-note {{comparison of addresses of subobjects of different base classes has unspecified value}} \ + // interpreter-note {{initializer of 'z' is unknown}} +} diff --git a/clang/test/SemaCXX/wreturn-always-throws.cpp b/clang/test/SemaCXX/wreturn-always-throws.cpp index addcadd..df7689f 100644 --- a/clang/test/SemaCXX/wreturn-always-throws.cpp +++ b/clang/test/SemaCXX/wreturn-always-throws.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wreturn-type -verify %s +// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wreturn-type -Winvalid-noreturn -verify %s // expected-no-diagnostics namespace std { @@ -44,3 +44,22 @@ void testTemplates() { throwErrorTemplate("ERROR"); (void)ensureZeroTemplate(42); } + +// Ensure that explicit specialization of a member function does not inherit +// the warning from the primary template. + +template<typename T> +struct S { + void f(); + void g(); +}; + +template<typename T> +void S<T>::f() { throw 0; } +template<> +void S<int>::f() {} + +template<typename T> +void S<T>::g() {} +template<> +void S<int>::g() { throw 0; } diff --git a/clang/test/SemaOpenACC/atomic-construct.cpp b/clang/test/SemaOpenACC/atomic-construct.cpp index eba2559..10c85c2 100644 --- a/clang/test/SemaOpenACC/atomic-construct.cpp +++ b/clang/test/SemaOpenACC/atomic-construct.cpp @@ -1098,7 +1098,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS--; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used in unary expression('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used in unary expression('LHS') from the first statement}} LHS = RHS; } @@ -1128,7 +1128,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS *= 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of compound assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of compound assignment('LHS') from the first statement}} LHS = RHS; } #pragma acc atomic capture @@ -1157,7 +1157,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS = LHS * 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1186,7 +1186,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS = LHS | 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1255,7 +1255,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on left hand side of assignment('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression on left hand side of assignment('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS = 1; } @@ -1294,7 +1294,7 @@ void AtomicCaptureTemplateCompound(T LHS, T RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable in unary expression('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression in unary expression('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS++; } } @@ -1352,7 +1352,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS--; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used in unary expression('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used in unary expression('LHS') from the first statement}} LHS = RHS; } @@ -1384,7 +1384,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS *= 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of compound assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of compound assignment('LHS') from the first statement}} LHS = RHS; } #pragma acc atomic capture @@ -1415,7 +1415,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS = LHS * 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1446,7 +1446,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS = LHS | 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1523,7 +1523,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on left hand side of assignment('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression on left hand side of assignment('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS = 1; } @@ -1570,7 +1570,7 @@ void AtomicCaptureTemplateCompound2(T LHS, T RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable in unary expression('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression in unary expression('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS++; } } @@ -1629,7 +1629,7 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS--; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used in unary expression('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used in unary expression('LHS') from the first statement}} LHS = RHS; } @@ -1666,7 +1666,7 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS *= 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of compound assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of compound assignment('LHS') from the first statement}} LHS = RHS; } #pragma acc atomic capture @@ -1702,7 +1702,7 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS = LHS * 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1738,7 +1738,7 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS = LHS | 1; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on right hand side of assignment('RHS') must match variable used on left hand side of assignment('LHS') from the first statement}} + // expected-note@+1{{sub-expression on right hand side of assignment('RHS') must match sub-expression used on left hand side of assignment('LHS') from the first statement}} RHS = RHS; } #pragma acc atomic capture @@ -1815,7 +1815,7 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable on left hand side of assignment('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression on left hand side of assignment('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS = 1; } @@ -1861,7 +1861,23 @@ void AtomicCaptureCompound(int LHS, int RHS) { { LHS = RHS; // expected-error@-3{{statement associated with OpenACC 'atomic capture' directive is invalid}} - // expected-note@+1{{variable in unary expression('LHS') must match variable used on right hand side of assignment('RHS') from the first statement}} + // expected-note@+1{{sub-expression in unary expression('LHS') must match sub-expression used on right hand side of assignment('RHS') from the first statement}} LHS++; } + + // Example from UDel test suite, which wasn't working because of irrelevant + // parens, make sure we work with these. This should not diagnose. + typedef double real_t; + int * distribution; + real_t *a; + real_t *b; + int *c; + for (int x = 0; x < 5; ++x) { +#pragma acc atomic capture + { + c[x] = distribution[(int) (a[x]*b[x]/10)]; + (distribution[(int)(a[x]*b[x]/10)])--; + } + } + } diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl index 9711b3b..3247380 100644 --- a/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl +++ b/clang/test/SemaOpenCL/builtins-amdgcn-error-gfx1250-param.cl @@ -1,6 +1,7 @@ // REQUIRES: amdgpu-registered-target -// RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx1250 -verify -S -o - %s +// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgcn-- -target-cpu gfx1250 -verify -S -o - %s +typedef int v2i __attribute__((ext_vector_type(2))); typedef int v4i __attribute__((ext_vector_type(4))); typedef int v8i __attribute__((ext_vector_type(8))); @@ -28,6 +29,17 @@ void test__builtin_amdgcn_cvt_f16_bf8(int a, int b) { __builtin_amdgcn_cvt_f16_bf8(a, b); // expected-error {{'__builtin_amdgcn_cvt_f16_bf8' must be a constant integer}} } +void test_amdgcn_load_monitor(global int* b32gaddr, global v2i* b64gaddr, global v4i* b128gaddr, int *b32faddr, v2i* b64faddr, v4i *b128faddr, + global int* b32out, global v2i* b64out, global v4i* b128out, int cpol) +{ + *b32out = __builtin_amdgcn_global_load_monitor_b32(b32gaddr, cpol); // expected-error {{'__builtin_amdgcn_global_load_monitor_b32' must be a constant integer}} + *b64out = __builtin_amdgcn_global_load_monitor_b64(b64gaddr, cpol); // expected-error {{'__builtin_amdgcn_global_load_monitor_b64' must be a constant integer}} + *b128out = __builtin_amdgcn_global_load_monitor_b128(b128gaddr, cpol); // expected-error {{'__builtin_amdgcn_global_load_monitor_b128' must be a constant integer}} + *b32out = __builtin_amdgcn_flat_load_monitor_b32(b32faddr, cpol); // expected-error {{'__builtin_amdgcn_flat_load_monitor_b32' must be a constant integer}} + *b64out = __builtin_amdgcn_flat_load_monitor_b64(b64faddr, cpol); // expected-error {{'__builtin_amdgcn_flat_load_monitor_b64' must be a constant integer}} + *b128out = __builtin_amdgcn_flat_load_monitor_b128(b128faddr, cpol); // expected-error {{'__builtin_amdgcn_flat_load_monitor_b128' must be a constant integer}} +} + void test_amdgcn_tensor_load_store(v4i sg0, v8i sg1, v4i sg2, v4i sg3, int cpol) { __builtin_amdgcn_tensor_load_to_lds(sg0, sg1, sg2, sg3, cpol); // expected-error {{'__builtin_amdgcn_tensor_load_to_lds' must be a constant integer}} @@ -36,6 +48,11 @@ void test_amdgcn_tensor_load_store(v4i sg0, v8i sg1, v4i sg2, v4i sg3, int cpol) __builtin_amdgcn_tensor_store_from_lds_d2(sg0, sg1, cpol); // expected-error {{'__builtin_amdgcn_tensor_store_from_lds_d2' must be a constant integer}} } +void test_prefetch(generic void *fptr, global void *gptr, int cpol) { + __builtin_amdgcn_flat_prefetch(fptr, cpol); // expected-error {{'__builtin_amdgcn_flat_prefetch' must be a constant integer}} + __builtin_amdgcn_global_prefetch(gptr, cpol); // expected-error {{'__builtin_amdgcn_global_prefetch' must be a constant integer}} +} + void test_cvt_f32_fp8_e5m3(global int* out, int a) { *out = __builtin_amdgcn_cvt_f32_fp8_e5m3(a, a); // expected-error {{'__builtin_amdgcn_cvt_f32_fp8_e5m3' must be a constant integer}} diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 62a4f95..663bc98 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1250,3 +1250,11 @@ static_assert(!D<Priv>::has, "Private should be invisible."); static_assert(!D<Prot>::has, "Protected should be invisible."); } + + +namespace GH149986 { +template <typename T> concept PerfectSquare = [](){} // expected-note 2{{here}} +([](auto) { return true; }) < PerfectSquare <class T>; +// expected-error@-1 {{declaration of 'T' shadows template parameter}} \ +// expected-error@-1 {{a concept definition cannot refer to itself}} +} diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 0953f647..f6bc6ee 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -966,3 +966,19 @@ Expand<Type, Invocable<>> _{}; // CHECK-NEXT: | `-ParmVarDecl {{.+}} 'T...' pack } + +namespace GH134613 { +template <typename R> struct Foo { + using value_type = R; + + Foo() = default; + Foo(Foo<Foo<R>> &&rhs) {} +}; + +void main() { + auto r1 = Foo(Foo<Foo<int>>{}); + + static_assert(__is_same(decltype(r1)::value_type, int)); +} + +} diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 65d8b36..9de3cca 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -249,6 +249,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterFunctionDefinitionName); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterIfMacros); + CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterNot); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterOverloadedOperator); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterPlacementOperator); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, BeforeNonEmptyParentheses); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index dbf6950..c20d099 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -7783,6 +7783,16 @@ TEST_F(FormatTest, ConstructorInitializers) { "Constructor() :\n" " // Comment forcing unwanted break.\n" " aaaa(aaaa) {}"); + + // Braced initializers with trailing commas. + verifyFormat("MyClass::MyClass()\n" + " : aaaa{\n" + " 0,\n" + " },\n" + " bbbb{\n" + " 0,\n" + " } {}", + "MyClass::MyClass():aaaa{0,},bbbb{0,}{}"); } TEST_F(FormatTest, AllowAllConstructorInitializersOnNextLine) { @@ -12103,6 +12113,8 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { Prefix = "void a() const &;\n" "void b() const &;\n"; verifyFormat(Prefix + "int *x;", Prefix + "int* x;", DerivePointerAlignment); + + verifyGoogleFormat("MACRO(int*, std::function<void() &&>);"); } TEST_F(FormatTest, PointerAlignmentFallback) { @@ -17664,6 +17676,12 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { verifyFormat("int x = int (y);", SomeSpace2); verifyFormat("auto lambda = []() { return 0; };", SomeSpace2); + auto Style = getLLVMStyle(); + Style.SpaceBeforeParens = FormatStyle::SBPO_Custom; + EXPECT_FALSE(Style.SpaceBeforeParensOptions.AfterNot); + Style.SpaceBeforeParensOptions.AfterNot = true; + verifyFormat("return not (a || b);", Style); + FormatStyle SpaceAfterOverloadedOperator = getLLVMStyle(); SpaceAfterOverloadedOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom; SpaceAfterOverloadedOperator.SpaceBeforeParensOptions diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index 4b24800..4d08f8d 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -136,15 +136,13 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); - ASSERT_EQ((int)Elements.size(), 0); + ASSERT_EQ((int)Parser.getElements().size(), 0); ASSERT_TRUE(Consumer->isSatisfied()); } @@ -172,15 +170,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); // First Descriptor Table with 4 elements RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem)); @@ -277,15 +274,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 2u); // Check default values are as expected @@ -364,15 +360,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseFloatsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem)); ASSERT_FLOAT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f); @@ -441,15 +436,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem)); ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler); @@ -474,15 +468,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 2u); RootElement Elem = Elements[0].getElement(); @@ -533,15 +526,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 3u); RootElement Elem = Elements[0].getElement(); @@ -588,15 +580,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 4u); RootElement Elem = Elements[0].getElement(); @@ -664,9 +655,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidTrailingCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); @@ -697,15 +686,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidVersion10Test) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_0, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_0, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); auto DefRootDescriptorFlag = llvm::dxbc::RootDescriptorFlags::DataVolatile; RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem)); @@ -770,15 +758,14 @@ TEST_F(ParseHLSLRootSignatureTest, ValidVersion11Test) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); + auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem)); ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer); @@ -838,9 +825,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedTokenTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -860,9 +845,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced - invalid token Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -882,9 +865,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedEndOfStreamTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced - expected '(' after DescriptorTable Consumer->setExpected(diag::err_expected_after); @@ -909,9 +890,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidMissingDTParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); @@ -933,9 +912,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRDParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); @@ -957,9 +934,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRCParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); @@ -983,9 +958,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryDTParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); @@ -1007,9 +980,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryRCParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); @@ -1033,9 +1004,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalDTParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); @@ -1061,9 +1030,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalRCParameterTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); @@ -1086,9 +1053,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); @@ -1110,9 +1075,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidParseOverflowedNegativeNumberTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); @@ -1133,9 +1096,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedFloatTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); @@ -1156,9 +1117,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexNegOverflowedFloatTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); @@ -1179,9 +1138,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedDoubleTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); @@ -1202,9 +1159,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexUnderflowFloatTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_underflow); @@ -1228,9 +1183,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_non_zero_flag); @@ -1253,9 +1206,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootElementMissingCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1280,9 +1231,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableMissingCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1307,9 +1256,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootConstantParamsCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1334,9 +1281,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorParamsCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1363,9 +1308,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorClauseParamsCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1390,9 +1333,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidStaticSamplerCommaTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); @@ -1414,9 +1355,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorParamTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1441,9 +1380,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableParamTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1467,9 +1404,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableClauseParamTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1496,9 +1431,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidStaticSamplerParamTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1523,9 +1456,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidVisibilityValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1549,9 +1480,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRegisterValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1576,9 +1505,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidFilterValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1603,9 +1530,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidTextureAddressModeValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1630,9 +1555,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidComparisonFuncValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1657,9 +1580,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidStaticBorderColorValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1681,9 +1602,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootFlagsValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1705,9 +1624,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorFlagsValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); @@ -1733,9 +1650,7 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorRangeFlagsValueTest) { TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); - SmallVector<RootSignatureElement> Elements; - hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Elements, - Signature, *PP); + hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); |