summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2024-07-26 11:43:08 -0700
committerVitaly Buka <vitalybuka@google.com>2024-07-26 11:43:08 -0700
commitc6d8bf4b0543aa8c51e31f3fb7490809145651da (patch)
treebf046e889802a7d06b171cfbc03562f790325032
parentd683d378998c85c12d7f0549944f807bb44c7b76 (diff)
parentf8cd4c505fd9c0be329630b6b82e3a3ff53107cc (diff)
Created using spr 1.3.4 [skip ci]
-rw-r--r--.github/workflows/release-asset-audit.yml2
-rw-r--r--clang/docs/ReleaseNotes.rst2
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--libc/cmake/modules/LLVMLibCLibraryRules.cmake16
-rw-r--r--libc/cmake/modules/prepare_libc_gpu_build.cmake30
-rw-r--r--libc/lib/CMakeLists.txt27
-rw-r--r--libcxx/include/__atomic/atomic_ref.h15
-rw-r--r--libcxx/test/std/atomics/atomics.lockfree/is_always_lock_free.cpp165
-rw-r--r--libcxx/test/std/atomics/atomics.lockfree/isalwayslockfree.pass.cpp120
-rw-r--r--libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp34
-rw-r--r--libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_double.hex.pass.cpp5
-rw-r--r--libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.hex.pass.cpp5
-rw-r--r--libcxx/test/support/atomic_helpers.h103
-rw-r--r--libcxx/utils/libcxx/test/features.py20
-rw-r--r--libcxxabi/test/test_demangle.pass.cpp2
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbplatformutil.py10
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbtest.py4
-rw-r--r--llvm/include/llvm/Analysis/Loads.h13
-rw-r--r--llvm/include/llvm/Analysis/ValueTracking.h7
-rw-r--r--llvm/include/llvm/SandboxIR/SandboxIR.h221
-rw-r--r--llvm/include/llvm/SandboxIR/SandboxIRValues.def3
-rw-r--r--llvm/include/llvm/SandboxIR/Use.h2
-rw-r--r--llvm/lib/Analysis/Loads.cpp13
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp11
-rw-r--r--llvm/lib/SandboxIR/SandboxIR.cpp115
-rw-r--r--llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp17
-rw-r--r--llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp30
-rw-r--r--llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-constant.mir191
-rw-r--r--llvm/test/Instrumentation/HWAddressSanitizer/pgo-opt-out.ll2
-rw-r--r--llvm/test/Transforms/lower-builtin-allow-check.ll2
-rw-r--r--llvm/unittests/SandboxIR/SandboxIRTest.cpp212
-rw-r--r--llvm/unittests/SandboxIR/TrackerTest.cpp75
-rw-r--r--mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp42
-rw-r--r--mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir26
-rw-r--r--polly/lib/Analysis/ScopBuilder.cpp2
-rw-r--r--polly/lib/Analysis/ScopDetection.cpp3
36 files changed, 1279 insertions, 270 deletions
diff --git a/.github/workflows/release-asset-audit.yml b/.github/workflows/release-asset-audit.yml
index fd42bc67b999..018c5d542f32 100644
--- a/.github/workflows/release-asset-audit.yml
+++ b/.github/workflows/release-asset-audit.yml
@@ -40,7 +40,7 @@ jobs:
var fs = require('fs');
var body = ''
if (fs.existsSync('./comment')) {
- body = JSON.parse(fs.readFileSync('./comment')) + "\n\n";
+ body = fs.readFileSync('./comment') + "\n\n";
}
body = body + `\n\nhttps://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 286f319d41a2..4f1a916aad9d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -133,6 +133,8 @@ Improvements to Clang's diagnostics
- Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic.
+- -Wdangling-assignment-gsl is enabled by default.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index beee2432fdb0..e768151ce23c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10131,7 +10131,7 @@ def warn_dangling_lifetime_pointer : Warning<
InGroup<DanglingGsl>;
def warn_dangling_lifetime_pointer_assignment : Warning<"object backing the "
"pointer %0 will be destroyed at the end of the full-expression">,
- InGroup<DanglingAssignmentGsl>, DefaultIgnore;
+ InGroup<DanglingAssignmentGsl>;
def warn_new_dangling_initializer_list : Warning<
"array backing "
"%select{initializer list subobject of the allocated object|"
diff --git a/libc/cmake/modules/LLVMLibCLibraryRules.cmake b/libc/cmake/modules/LLVMLibCLibraryRules.cmake
index e677b4cd2c28..ad931d445720 100644
--- a/libc/cmake/modules/LLVMLibCLibraryRules.cmake
+++ b/libc/cmake/modules/LLVMLibCLibraryRules.cmake
@@ -111,19 +111,9 @@ function(add_bitcode_entrypoint_library target_name base_target_name)
list(APPEND objects ${object})
endforeach()
- set(output ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.bc)
- add_custom_command(
- OUTPUT ${output}
- COMMAND ${LIBC_LLVM_LINK} ${objects} -o ${output}
- DEPENDS ${all_deps} ${base_target_name}
- COMMENT "Linking LLVM-IR bitcode for ${base_target_name}"
- COMMAND_EXPAND_LISTS
- )
- add_custom_target(${target_name} DEPENDS ${output} ${all_deps})
- set_target_properties(${target_name} PROPERTIES TARGET_OBJECT ${output})
- if(TARGET llvm-link)
- add_dependencies(${target_name} llvm-link)
- endif()
+ add_executable(${target_name} ${objects})
+ target_link_options(${target_name} PRIVATE
+ "-r" "-nostdlib" "-flto" "-Wl,--lto-emit-llvm" "-march= ")
endfunction(add_bitcode_entrypoint_library)
# A rule to build a library from a collection of entrypoint objects.
diff --git a/libc/cmake/modules/prepare_libc_gpu_build.cmake b/libc/cmake/modules/prepare_libc_gpu_build.cmake
index e2a0908023a0..f3537f2634e5 100644
--- a/libc/cmake/modules/prepare_libc_gpu_build.cmake
+++ b/libc/cmake/modules/prepare_libc_gpu_build.cmake
@@ -21,36 +21,10 @@ if(LIBC_TARGET_TRIPLE)
set(CMAKE_REQUIRED_FLAGS "--target=${LIBC_TARGET_TRIPLE}")
endif()
if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
- set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nogpulib")
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nogpulib -nostdlib")
elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
set(CMAKE_REQUIRED_FLAGS
- "${CMAKE_REQUIRED_FLAGS} -flto -c -Wno-unused-command-line-argument")
-endif()
-
-# Identify the program used to package multiple images into a single binary.
-get_filename_component(compiler_path ${CMAKE_CXX_COMPILER} DIRECTORY)
-if(TARGET clang-offload-packager)
- get_target_property(LIBC_CLANG_OFFLOAD_PACKAGER clang-offload-packager LOCATION)
-else()
- find_program(LIBC_CLANG_OFFLOAD_PACKAGER
- NAMES clang-offload-packager NO_DEFAULT_PATH
- PATHS ${LLVM_BINARY_DIR}/bin ${compiler_path})
- if(NOT LIBC_CLANG_OFFLOAD_PACKAGER)
- message(FATAL_ERROR "Cannot find the 'clang-offload-packager' for the GPU "
- "build")
- endif()
-endif()
-
-# Identify llvm-link program so we can merge the output IR into a single blob.
-if(TARGET llvm-link)
- get_target_property(LIBC_LLVM_LINK llvm-link LOCATION)
-else()
- find_program(LIBC_LLVM_LINK
- NAMES llvm-link NO_DEFAULT_PATH
- PATHS ${LLVM_BINARY_DIR}/bin ${compiler_path})
- if(NOT LIBC_LLVM_LINK)
- message(FATAL_ERROR "Cannot find 'llvm-link' for the GPU build")
- endif()
+ "${CMAKE_REQUIRED_FLAGS} -flto -c -Wno-unused-command-line-argument -nostdlib")
endif()
# Optionally set up a job pool to limit the number of GPU tests run in parallel.
diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index 4b7cfc4b76e2..ce0b07fb6cb4 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -51,7 +51,7 @@ foreach(archive IN ZIP_LISTS
PROPERTIES
OUTPUT_NAME ${archive_1}.bc
)
- list(APPEND added_gpu_bitcode_targets ${archive_1}bitcode)
+ list(APPEND added_bitcode_targets ${archive_1}bitcode)
endif()
endforeach()
@@ -61,24 +61,13 @@ install(
COMPONENT libc
)
-if(LIBC_TARGET_OS_IS_GPU)
- set(gpu_install_dir lib${LLVM_LIBDIR_SUFFIX})
- if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
- set(gpu_install_dir lib${LLVM_LIBDIR_SUFFIX}/${LLVM_HOST_TRIPLE})
- endif()
- install(
- TARGETS ${added_gpu_archive_targets}
- ARCHIVE DESTINATION ${gpu_install_dir}
- COMPONENT libc
+foreach(file ${added_bitcode_targets})
+ install(FILES $<TARGET_FILE:${file}>
+ DESTINATION ${LIBC_INSTALL_LIBRARY_DIR}
+ RENAME $<TARGET_PROPERTY:${file},OUTPUT_NAME>
+ COMPONENT libc
)
- foreach(file ${added_gpu_bitcode_targets})
- install(FILES $<TARGET_PROPERTY:${file},TARGET_OBJECT>
- DESTINATION ${LIBC_INSTALL_LIBRARY_DIR}
- RENAME $<TARGET_PROPERTY:${file},OUTPUT_NAME>
- COMPONENT libc
- )
- endforeach()
-endif()
+endforeach()
if(NOT LIBC_TARGET_OS_IS_BAREMETAL)
# For now we will disable libc-startup installation for baremetal. The
@@ -93,6 +82,7 @@ endif()
add_custom_target(install-libc
DEPENDS ${added_archive_targets}
+ ${added_bitcode_targets}
${startup_target}
${header_install_target}
COMMAND "${CMAKE_COMMAND}"
@@ -100,6 +90,7 @@ add_custom_target(install-libc
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
add_custom_target(install-libc-stripped
DEPENDS ${added_archive_targets}
+ ${added_bitcode_targets}
${startup_target}
${header_install_target}
COMMAND "${CMAKE_COMMAND}"
diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h
index 156f1961151c..2849b82e1a3d 100644
--- a/libcxx/include/__atomic/atomic_ref.h
+++ b/libcxx/include/__atomic/atomic_ref.h
@@ -42,6 +42,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
+// These types are required to make __atomic_is_always_lock_free work across GCC and Clang.
+// The purpose of this trick is to make sure that we provide an object with the correct alignment
+// to __atomic_is_always_lock_free, since that answer depends on the alignment.
+template <size_t _Alignment>
+struct __alignment_checker_type {
+ alignas(_Alignment) char __data;
+};
+
+template <size_t _Alignment>
+struct __get_aligner_instance {
+ static constexpr __alignment_checker_type<_Alignment> __instance{};
+};
+
template <class _Tp>
struct __atomic_ref_base {
protected:
@@ -105,7 +118,7 @@ public:
// that the pointer is going to be aligned properly at runtime because that is a (checked) precondition
// of atomic_ref's constructor.
static constexpr bool is_always_lock_free =
- __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast<void*>(-required_alignment));
+ __atomic_always_lock_free(sizeof(_Tp), &__get_aligner_instance<required_alignment>::__instance);
_LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); }
diff --git a/libcxx/test/std/atomics/atomics.lockfree/is_always_lock_free.cpp b/libcxx/test/std/atomics/atomics.lockfree/is_always_lock_free.cpp
new file mode 100644
index 000000000000..2dc7f5c76541
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.lockfree/is_always_lock_free.cpp
@@ -0,0 +1,165 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <atomic>
+//
+// template <class T>
+// class atomic;
+//
+// static constexpr bool is_always_lock_free;
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+
+#include "test_macros.h"
+#include "atomic_helpers.h"
+
+template <typename T>
+void check_always_lock_free(std::atomic<T> const& a) {
+ using InfoT = LockFreeStatusInfo<T>;
+
+ constexpr std::same_as<const bool> decltype(auto) is_always_lock_free = std::atomic<T>::is_always_lock_free;
+
+ // If we know the status of T for sure, validate the exact result of the function.
+ if constexpr (InfoT::status_known) {
+ constexpr LockFreeStatus known_status = InfoT::value;
+ if constexpr (known_status == LockFreeStatus::always) {
+ static_assert(is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status");
+ assert(a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status");
+ } else if constexpr (known_status == LockFreeStatus::never) {
+ static_assert(!is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status");
+ assert(!a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status");
+ } else {
+ assert(a.is_lock_free() || !a.is_lock_free()); // This is kinda dumb, but we might as well call the function once.
+ }
+ }
+
+ // In all cases, also sanity-check it based on the implication always-lock-free => lock-free.
+ if (is_always_lock_free) {
+ std::same_as<bool> decltype(auto) is_lock_free = a.is_lock_free();
+ assert(is_lock_free);
+ }
+ ASSERT_NOEXCEPT(a.is_lock_free());
+}
+
+#define CHECK_ALWAYS_LOCK_FREE(T) \
+ do { \
+ typedef T type; \
+ type obj{}; \
+ std::atomic<type> a(obj); \
+ check_always_lock_free(a); \
+ } while (0)
+
+void test() {
+ char c = 'x';
+ check_always_lock_free(std::atomic<char>(c));
+
+ int i = 0;
+ check_always_lock_free(std::atomic<int>(i));
+
+ float f = 0.f;
+ check_always_lock_free(std::atomic<float>(f));
+
+ int* p = &i;
+ check_always_lock_free(std::atomic<int*>(p));
+
+ CHECK_ALWAYS_LOCK_FREE(bool);
+ CHECK_ALWAYS_LOCK_FREE(char);
+ CHECK_ALWAYS_LOCK_FREE(signed char);
+ CHECK_ALWAYS_LOCK_FREE(unsigned char);
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+ CHECK_ALWAYS_LOCK_FREE(char8_t);
+#endif
+ CHECK_ALWAYS_LOCK_FREE(char16_t);
+ CHECK_ALWAYS_LOCK_FREE(char32_t);
+ CHECK_ALWAYS_LOCK_FREE(wchar_t);
+ CHECK_ALWAYS_LOCK_FREE(short);
+ CHECK_ALWAYS_LOCK_FREE(unsigned short);
+ CHECK_ALWAYS_LOCK_FREE(int);
+ CHECK_ALWAYS_LOCK_FREE(unsigned int);
+ CHECK_ALWAYS_LOCK_FREE(long);
+ CHECK_ALWAYS_LOCK_FREE(unsigned long);
+ CHECK_ALWAYS_LOCK_FREE(long long);
+ CHECK_ALWAYS_LOCK_FREE(unsigned long long);
+ CHECK_ALWAYS_LOCK_FREE(std::nullptr_t);
+ CHECK_ALWAYS_LOCK_FREE(void*);
+ CHECK_ALWAYS_LOCK_FREE(float);
+ CHECK_ALWAYS_LOCK_FREE(double);
+ CHECK_ALWAYS_LOCK_FREE(long double);
+#if __has_attribute(vector_size) && defined(_LIBCPP_VERSION)
+ CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(1 * sizeof(int)))));
+ CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(2 * sizeof(int)))));
+ CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(4 * sizeof(int)))));
+ CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(16 * sizeof(int)))));
+ CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(32 * sizeof(int)))));
+ CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(1 * sizeof(float)))));
+ CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(2 * sizeof(float)))));
+ CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(4 * sizeof(float)))));
+ CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(16 * sizeof(float)))));
+ CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(32 * sizeof(float)))));
+ CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(1 * sizeof(double)))));
+ CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(2 * sizeof(double)))));
+ CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(4 * sizeof(double)))));
+ CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(16 * sizeof(double)))));
+ CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(32 * sizeof(double)))));
+#endif // __has_attribute(vector_size) && defined(_LIBCPP_VERSION)
+ CHECK_ALWAYS_LOCK_FREE(struct Empty{});
+ CHECK_ALWAYS_LOCK_FREE(struct OneInt { int i; });
+ CHECK_ALWAYS_LOCK_FREE(struct IntArr2 { int i[2]; });
+ CHECK_ALWAYS_LOCK_FREE(struct FloatArr3 { float i[3]; });
+ CHECK_ALWAYS_LOCK_FREE(struct LLIArr2 { long long int i[2]; });
+ CHECK_ALWAYS_LOCK_FREE(struct LLIArr4 { long long int i[4]; });
+ CHECK_ALWAYS_LOCK_FREE(struct LLIArr8 { long long int i[8]; });
+ CHECK_ALWAYS_LOCK_FREE(struct LLIArr16 { long long int i[16]; });
+ CHECK_ALWAYS_LOCK_FREE(struct Padding {
+ char c; /* padding */
+ long long int i;
+ });
+ CHECK_ALWAYS_LOCK_FREE(union IntFloat {
+ int i;
+ float f;
+ });
+ CHECK_ALWAYS_LOCK_FREE(enum class CharEnumClass : char{foo});
+
+ // C macro and static constexpr must be consistent.
+ enum class CharEnumClass : char { foo };
+ static_assert(std::atomic<bool>::is_always_lock_free == (2 == ATOMIC_BOOL_LOCK_FREE), "");
+ static_assert(std::atomic<char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
+ static_assert(std::atomic<CharEnumClass>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
+ static_assert(std::atomic<signed char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
+ static_assert(std::atomic<unsigned char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+ static_assert(std::atomic<char8_t>::is_always_lock_free == (2 == ATOMIC_CHAR8_T_LOCK_FREE), "");
+#endif
+ static_assert(std::atomic<char16_t>::is_always_lock_free == (2 == ATOMIC_CHAR16_T_LOCK_FREE), "");
+ static_assert(std::atomic<char32_t>::is_always_lock_free == (2 == ATOMIC_CHAR32_T_LOCK_FREE), "");
+ static_assert(std::atomic<wchar_t>::is_always_lock_free == (2 == ATOMIC_WCHAR_T_LOCK_FREE), "");
+ static_assert(std::atomic<short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE), "");
+ static_assert(std::atomic<unsigned short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE), "");
+ static_assert(std::atomic<int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE), "");
+ static_assert(std::atomic<unsigned int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE), "");
+ static_assert(std::atomic<long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE), "");
+ static_assert(std::atomic<unsigned long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE), "");
+ static_assert(std::atomic<long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE), "");
+ static_assert(std::atomic<unsigned long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE), "");
+ static_assert(std::atomic<void*>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE), "");
+ static_assert(std::atomic<std::nullptr_t>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE), "");
+
+#if TEST_STD_VER >= 20
+ static_assert(std::atomic_signed_lock_free::is_always_lock_free, "");
+ static_assert(std::atomic_unsigned_lock_free::is_always_lock_free, "");
+#endif
+}
+
+int main(int, char**) {
+ test();
+ return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.lockfree/isalwayslockfree.pass.cpp b/libcxx/test/std/atomics/atomics.lockfree/isalwayslockfree.pass.cpp
deleted file mode 100644
index 6d6e6477bc25..000000000000
--- a/libcxx/test/std/atomics/atomics.lockfree/isalwayslockfree.pass.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03, c++11, c++14
-
-// <atomic>
-
-// static constexpr bool is_always_lock_free;
-
-#include <atomic>
-#include <cassert>
-#include <cstddef>
-
-#include "test_macros.h"
-
-template <typename T>
-void checkAlwaysLockFree() {
- if (std::atomic<T>::is_always_lock_free) {
- assert(std::atomic<T>().is_lock_free());
- }
-}
-
-void run()
-{
-// structs and unions can't be defined in the template invocation.
-// Work around this with a typedef.
-#define CHECK_ALWAYS_LOCK_FREE(T) \
- do { \
- typedef T type; \
- checkAlwaysLockFree<type>(); \
- } while (0)
-
- CHECK_ALWAYS_LOCK_FREE(bool);
- CHECK_ALWAYS_LOCK_FREE(char);
- CHECK_ALWAYS_LOCK_FREE(signed char);
- CHECK_ALWAYS_LOCK_FREE(unsigned char);
-#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
- CHECK_ALWAYS_LOCK_FREE(char8_t);
-#endif
- CHECK_ALWAYS_LOCK_FREE(char16_t);
- CHECK_ALWAYS_LOCK_FREE(char32_t);
- CHECK_ALWAYS_LOCK_FREE(wchar_t);
- CHECK_ALWAYS_LOCK_FREE(short);
- CHECK_ALWAYS_LOCK_FREE(unsigned short);
- CHECK_ALWAYS_LOCK_FREE(int);
- CHECK_ALWAYS_LOCK_FREE(unsigned int);
- CHECK_ALWAYS_LOCK_FREE(long);
- CHECK_ALWAYS_LOCK_FREE(unsigned long);
- CHECK_ALWAYS_LOCK_FREE(long long);
- CHECK_ALWAYS_LOCK_FREE(unsigned long long);
- CHECK_ALWAYS_LOCK_FREE(std::nullptr_t);
- CHECK_ALWAYS_LOCK_FREE(void*);
- CHECK_ALWAYS_LOCK_FREE(float);
- CHECK_ALWAYS_LOCK_FREE(double);
- CHECK_ALWAYS_LOCK_FREE(long double);
-#if __has_attribute(vector_size) && defined(_LIBCPP_VERSION)
- CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(1 * sizeof(int)))));
- CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(2 * sizeof(int)))));
- CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(4 * sizeof(int)))));
- CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(16 * sizeof(int)))));
- CHECK_ALWAYS_LOCK_FREE(int __attribute__((vector_size(32 * sizeof(int)))));
- CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(1 * sizeof(float)))));
- CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(2 * sizeof(float)))));
- CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(4 * sizeof(float)))));
- CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(16 * sizeof(float)))));
- CHECK_ALWAYS_LOCK_FREE(float __attribute__((vector_size(32 * sizeof(float)))));
- CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(1 * sizeof(double)))));
- CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(2 * sizeof(double)))));
- CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(4 * sizeof(double)))));
- CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(16 * sizeof(double)))));
- CHECK_ALWAYS_LOCK_FREE(double __attribute__((vector_size(32 * sizeof(double)))));
-#endif // __has_attribute(vector_size) && defined(_LIBCPP_VERSION)
- CHECK_ALWAYS_LOCK_FREE(struct Empty {});
- CHECK_ALWAYS_LOCK_FREE(struct OneInt { int i; });
- CHECK_ALWAYS_LOCK_FREE(struct IntArr2 { int i[2]; });
- CHECK_ALWAYS_LOCK_FREE(struct FloatArr3 { float i[3]; });
- CHECK_ALWAYS_LOCK_FREE(struct LLIArr2 { long long int i[2]; });
- CHECK_ALWAYS_LOCK_FREE(struct LLIArr4 { long long int i[4]; });
- CHECK_ALWAYS_LOCK_FREE(struct LLIArr8 { long long int i[8]; });
- CHECK_ALWAYS_LOCK_FREE(struct LLIArr16 { long long int i[16]; });
- CHECK_ALWAYS_LOCK_FREE(struct Padding { char c; /* padding */ long long int i; });
- CHECK_ALWAYS_LOCK_FREE(union IntFloat { int i; float f; });
- CHECK_ALWAYS_LOCK_FREE(enum class CharEnumClass : char { foo });
-
- // C macro and static constexpr must be consistent.
- enum class CharEnumClass : char { foo };
- static_assert(std::atomic<bool>::is_always_lock_free == (2 == ATOMIC_BOOL_LOCK_FREE), "");
- static_assert(std::atomic<char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
- static_assert(std::atomic<CharEnumClass>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
- static_assert(std::atomic<signed char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
- static_assert(std::atomic<unsigned char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE), "");
-#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
- static_assert(std::atomic<char8_t>::is_always_lock_free == (2 == ATOMIC_CHAR8_T_LOCK_FREE), "");
-#endif
- static_assert(std::atomic<char16_t>::is_always_lock_free == (2 == ATOMIC_CHAR16_T_LOCK_FREE), "");
- static_assert(std::atomic<char32_t>::is_always_lock_free == (2 == ATOMIC_CHAR32_T_LOCK_FREE), "");
- static_assert(std::atomic<wchar_t>::is_always_lock_free == (2 == ATOMIC_WCHAR_T_LOCK_FREE), "");
- static_assert(std::atomic<short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE), "");
- static_assert(std::atomic<unsigned short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE), "");
- static_assert(std::atomic<int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE), "");
- static_assert(std::atomic<unsigned int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE), "");
- static_assert(std::atomic<long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE), "");
- static_assert(std::atomic<unsigned long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE), "");
- static_assert(std::atomic<long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE), "");
- static_assert(std::atomic<unsigned long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE), "");
- static_assert(std::atomic<void*>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE), "");
- static_assert(std::atomic<std::nullptr_t>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE), "");
-
-#if TEST_STD_VER >= 20
- static_assert(std::atomic_signed_lock_free::is_always_lock_free, "");
- static_assert(std::atomic_unsigned_lock_free::is_always_lock_free, "");
-#endif
-}
-
-int main(int, char**) { run(); return 0; }
diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp
index 94f65e3b4b66..acdbf63a24d8 100644
--- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp
@@ -9,7 +9,10 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <atomic>
-
+//
+// template <class T>
+// class atomic_ref;
+//
// static constexpr bool is_always_lock_free;
// bool is_lock_free() const noexcept;
@@ -18,10 +21,29 @@
#include <concepts>
#include "test_macros.h"
+#include "atomic_helpers.h"
template <typename T>
-void check_always_lock_free(std::atomic_ref<T> const a) {
- std::same_as<const bool> decltype(auto) is_always_lock_free = std::atomic_ref<T>::is_always_lock_free;
+void check_always_lock_free(std::atomic_ref<T> const& a) {
+ using InfoT = LockFreeStatusInfo<T>;
+
+ constexpr std::same_as<const bool> decltype(auto) is_always_lock_free = std::atomic_ref<T>::is_always_lock_free;
+
+ // If we know the status of T for sure, validate the exact result of the function.
+ if constexpr (InfoT::status_known) {
+ constexpr LockFreeStatus known_status = InfoT::value;
+ if constexpr (known_status == LockFreeStatus::always) {
+ static_assert(is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status");
+ assert(a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status");
+ } else if constexpr (known_status == LockFreeStatus::never) {
+ static_assert(!is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status");
+ assert(!a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status");
+ } else {
+ assert(a.is_lock_free() || !a.is_lock_free()); // This is kinda dumb, but we might as well call the function once.
+ }
+ }
+
+ // In all cases, also sanity-check it based on the implication always-lock-free => lock-free.
if (is_always_lock_free) {
std::same_as<bool> decltype(auto) is_lock_free = a.is_lock_free();
assert(is_lock_free);
@@ -33,10 +55,14 @@ void check_always_lock_free(std::atomic_ref<T> const a) {
do { \
typedef T type; \
type obj{}; \
- check_always_lock_free(std::atomic_ref<type>(obj)); \
+ std::atomic_ref<type> a(obj); \
+ check_always_lock_free(a); \
} while (0)
void test() {
+ char c = 'x';
+ check_always_lock_free(std::atomic_ref<char>(c));
+
int i = 0;
check_always_lock_free(std::atomic_ref<int>(i));
diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_double.hex.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_double.hex.pass.cpp
index 21efa978abdc..946c26398fcb 100644
--- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_double.hex.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_double.hex.pass.cpp
@@ -12,10 +12,7 @@
// iter_type put(iter_type s, ios_base& iob, char_type fill, double v) const;
-// With the Microsoft UCRT, printf("%a", 0.0) produces "0x0.0000000000000p+0"
-// while other C runtimes produce just "0x0p+0".
-// https://developercommunity.visualstudio.com/t/Printf-formatting-of-float-as-hex-prints/1660844
-// XFAIL: msvc
+// XFAIL: win32-broken-printf-a-precision
// XFAIL: LIBCXX-AIX-FIXME
diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.hex.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.hex.pass.cpp
index c97c9a0c4036..a195c34e5f8e 100644
--- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.hex.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.hex.pass.cpp
@@ -12,10 +12,7 @@
// iter_type put(iter_type s, ios_base& iob, char_type fill, long double v) const;
-// With the Microsoft UCRT, printf("%a", 0.0) produces "0x0.0000000000000p+0"
-// while other C runtimes produce just "0x0p+0".
-// https://developercommunity.visualstudio.com/t/Printf-formatting-of-float-as-hex-prints/1660844
-// XFAIL: msvc
+// XFAIL: win32-broken-printf-a-precision
// XFAIL: LIBCXX-AIX-FIXME
diff --git a/libcxx/test/support/atomic_helpers.h b/libcxx/test/support/atomic_helpers.h
index 0266a0961067..d2f2b751cb47 100644
--- a/libcxx/test/support/atomic_helpers.h
+++ b/libcxx/test/support/atomic_helpers.h
@@ -11,9 +11,112 @@
#include <cassert>
#include <cstdint>
+#include <cstddef>
+#include <type_traits>
#include "test_macros.h"
+#if defined(TEST_COMPILER_CLANG)
+# define TEST_ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
+# define TEST_ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
+# define TEST_ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
+# define TEST_ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
+# define TEST_ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
+# define TEST_ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
+#elif defined(TEST_COMPILER_GCC)
+# define TEST_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
+# define TEST_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
+# define TEST_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
+# define TEST_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
+# define TEST_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
+# define TEST_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
+#elif TEST_COMPILER_MSVC
+// This is lifted from STL/stl/inc/atomic on github for the purposes of
+// keeping the tests compiling for MSVC's STL. It's not a perfect solution
+// but at least the tests will keep running.
+//
+// Note MSVC's STL never produces a type that is sometimes lock free, but not always lock free.
+template <class T, size_t Size = sizeof(T)>
+constexpr bool msvc_is_lock_free_macro_value() {
+ return (Size <= 8 && (Size & Size - 1) == 0) ? 2 : 0;
+}
+# define TEST_ATOMIC_CHAR_LOCK_FREE ::msvc_is_lock_free_macro_value<char>()
+# define TEST_ATOMIC_SHORT_LOCK_FREE ::msvc_is_lock_free_macro_value<short>()
+# define TEST_ATOMIC_INT_LOCK_FREE ::msvc_is_lock_free_macro_value<int>()
+# define TEST_ATOMIC_LONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long>()
+# define TEST_ATOMIC_LLONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long long>()
+# define TEST_ATOMIC_POINTER_LOCK_FREE ::msvc_is_lock_free_macro_value<void*>()
+#else
+# error "Unknown compiler"
+#endif
+
+#ifdef TEST_COMPILER_CLANG
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wc++11-extensions"
+#endif
+
+enum class LockFreeStatus : int { unknown = -1, never = 0, sometimes = 1, always = 2 };
+
+// We should really be checking whether the alignment of T is greater-than-or-equal-to the alignment required
+// for T to be atomic, but this is basically impossible to implement portably. Instead, we assume that any type
+// aligned to at least its size is going to be atomic if there exists atomic operations for that size at all,
+// which is true on most platforms. This technically reduces our test coverage in the sense that if a type has
+// an alignment requirement less than its size but could still be made lockfree, LockFreeStatusInfo will report
+// that we don't know whether it is lockfree or not.
+#define COMPARE_TYPES(T, FundamentalT) (sizeof(T) == sizeof(FundamentalT) && TEST_ALIGNOF(T) >= sizeof(T))
+
+template <class T>
+struct LockFreeStatusInfo {
+ static const LockFreeStatus value = LockFreeStatus(
+ COMPARE_TYPES(T, char)
+ ? TEST_ATOMIC_CHAR_LOCK_FREE
+ : (COMPARE_TYPES(T, short)
+ ? TEST_ATOMIC_SHORT_LOCK_FREE
+ : (COMPARE_TYPES(T, int)
+ ? TEST_ATOMIC_INT_LOCK_FREE
+ : (COMPARE_TYPES(T, long)
+ ? TEST_ATOMIC_LONG_LOCK_FREE
+ : (COMPARE_TYPES(T, long long)
+ ? TEST_ATOMIC_LLONG_LOCK_FREE
+ : (COMPARE_TYPES(T, void*) ? TEST_ATOMIC_POINTER_LOCK_FREE : -1))))));
+
+ static const bool status_known = LockFreeStatusInfo::value != LockFreeStatus::unknown;
+};
+
+#undef COMPARE_TYPES
+
+// This doesn't work in C++03 due to issues with scoped enumerations. Just disable the test.
+#if TEST_STD_VER >= 11
+static_assert(LockFreeStatusInfo<char>::status_known, "");
+static_assert(LockFreeStatusInfo<short>::status_known, "");
+static_assert(LockFreeStatusInfo<int>::status_known, "");
+static_assert(LockFreeStatusInfo<long>::status_known, "");
+static_assert(LockFreeStatusInfo<void*>::status_known, "");
+
+// long long is a bit funky: on some platforms, its alignment is 4 bytes but its size is
+// 8 bytes. In that case, atomics may or may not be lockfree based on their address.
+static_assert(alignof(long long) == sizeof(long long) ? LockFreeStatusInfo<long long>::status_known : true, "");
+
+// Those should always be lock free: hardcode some expected values to make sure our tests are actually
+// testing something meaningful.
+static_assert(LockFreeStatusInfo<char>::value == LockFreeStatus::always, "");
+static_assert(LockFreeStatusInfo<short>::value == LockFreeStatus::always, "");
+static_assert(LockFreeStatusInfo<int>::value == LockFreeStatus::always, "");
+#endif
+
+// These macros are somewhat suprising to use, since they take the values 0, 1, or 2.
+// To make the tests clearer, get rid of them in preference of LockFreeStatusInfo.
+#undef TEST_ATOMIC_CHAR_LOCK_FREE
+#undef TEST_ATOMIC_SHORT_LOCK_FREE
+#undef TEST_ATOMIC_INT_LOCK_FREE
+#undef TEST_ATOMIC_LONG_LOCK_FREE
+#undef TEST_ATOMIC_LLONG_LOCK_FREE
+#undef TEST_ATOMIC_POINTER_LOCK_FREE
+
+#ifdef TEST_COMPILER_CLANG
+# pragma clang diagnostic pop
+#endif
+
struct UserAtomicType {
int i;
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index e978875d543f..97cdb0349885 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -263,6 +263,26 @@ DEFAULT_FEATURES = [
""",
),
),
+ # Check for a Windows UCRT bug (not fixed upstream yet).
+ # With UCRT, printf("%a", 0.0) produces "0x0.0000000000000p+0",
+ # while other C runtimes produce just "0x0p+0".
+ # https://developercommunity.visualstudio.com/t/Printf-formatting-of-float-as-hex-prints/1660844
+ Feature(
+ name="win32-broken-printf-a-precision",
+ when=lambda cfg: "_WIN32" in compilerMacros(cfg)
+ and not programSucceeds(
+ cfg,
+ """
+ #include <stdio.h>
+ #include <string.h>
+ int main(int, char**) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%a", 0.0);
+ return strcmp(buf, "0x0p+0");
+ }
+ """,
+ ),
+ ),
# Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had
# mon_decimal_point == ".", which our tests don't handle.
Feature(
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index fe5598991b83..ab783cf9d96f 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -17,6 +17,8 @@
// 80-bit format, and this demangling test is failing on it.
// XFAIL: LIBCXX-ANDROID-FIXME && target={{i686|x86_64}}-{{.+}}-android{{.*}}
+// XFAIL: win32-broken-printf-a-precision
+
#include "support/timer.h"
#include <algorithm>
#include <cassert>
diff --git a/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py b/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py
index e3c6fd1a9956..602e15d207e9 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py
@@ -266,17 +266,13 @@ def getCompiler():
return module.getCompiler()
-def getCompilerBinary():
- """Returns the compiler binary the test suite is running with."""
- return getCompiler().split()[0]
-
-
def getCompilerVersion():
"""Returns a string that represents the compiler version.
Supports: llvm, clang.
"""
- compiler = getCompilerBinary()
- version_output = subprocess.check_output([compiler, "--version"], errors="replace")
+ version_output = subprocess.check_output(
+ [getCompiler(), "--version"], errors="replace"
+ )
m = re.search("version ([0-9.]+)", version_output)
if m:
return m.group(1)
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 5e50b0c14588..f97c41d867e7 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1379,10 +1379,6 @@ class Base(unittest.TestCase):
"""Returns the compiler in effect the test suite is running with."""
return lldbplatformutil.getCompiler()
- def getCompilerBinary(self):
- """Returns the compiler binary the test suite is running with."""
- return lldbplatformutil.getCompilerBinary()
-
def getCompilerVersion(self):
"""Returns a string that represents the compiler version.
Supports: llvm, clang.
diff --git a/llvm/include/llvm/Analysis/Loads.h b/llvm/include/llvm/Analysis/Loads.h
index 33e817828b75..1f01ff7027fa 100644
--- a/llvm/include/llvm/Analysis/Loads.h
+++ b/llvm/include/llvm/Analysis/Loads.h
@@ -69,8 +69,7 @@ bool isDereferenceableAndAlignedPointer(const Value *V, Align Alignment,
/// quick local scan of the basic block containing ScanFrom, to determine if
/// the address is already accessed.
bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size,
- const DataLayout &DL,
- Instruction *ScanFrom = nullptr,
+ const DataLayout &DL, Instruction *ScanFrom,
AssumptionCache *AC = nullptr,
const DominatorTree *DT = nullptr,
const TargetLibraryInfo *TLI = nullptr);
@@ -100,12 +99,18 @@ bool isDereferenceableReadOnlyLoop(Loop *L, ScalarEvolution *SE,
/// quick local scan of the basic block containing ScanFrom, to determine if
/// the address is already accessed.
bool isSafeToLoadUnconditionally(Value *V, Type *Ty, Align Alignment,
- const DataLayout &DL,
- Instruction *ScanFrom = nullptr,
+ const DataLayout &DL, Instruction *ScanFrom,
AssumptionCache *AC = nullptr,
const DominatorTree *DT = nullptr,
const TargetLibraryInfo *TLI = nullptr);
+/// Return true if speculation of the given load must be suppressed to avoid
+/// ordering or interfering with an active sanitizer. If not suppressed,
+/// dereferenceability and alignment must be proven separately. Note: This
+/// is only needed for raw reasoning; if you use the interface below
+/// (isSafeToSpeculativelyExecute), this is handled internally.
+bool mustSuppressSpeculation(const LoadInst &LI);
+
/// The default number of maximum instructions to scan in the block, used by
/// FindAvailableLoadedValue().
extern cl::opt<unsigned> DefMaxInstsToScan;
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 5ef6e4348390..96fa16970584 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -792,13 +792,6 @@ bool onlyUsedByLifetimeMarkers(const Value *V);
/// droppable instructions.
bool onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V);
-/// Return true if speculation of the given load must be suppressed to avoid
-/// ordering or interfering with an active sanitizer. If not suppressed,
-/// dereferenceability and alignment must be proven separately. Note: This
-/// is only needed for raw reasoning; if you use the interface below
-/// (isSafeToSpeculativelyExecute), this is handled internally.
-bool mustSuppressSpeculation(const LoadInst &LI);
-
/// Return true if the instruction does not have any effects besides
/// calculating the result and does not have undefined behavior.
///
diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 6c04c92e3e70..2678ee0f4f90 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -18,13 +18,19 @@
//
// namespace sandboxir {
//
-// +- Argument +- BinaryOperator
-// | |
-// Value -+- BasicBlock +- BranchInst
-// | |
-// +- Function +- Constant +- CastInst
-// | | |
-// +- User ------+- Instruction -+- CallInst
+// Value -+- Argument
+// |
+// +- BasicBlock
+// |
+// +- User ------+- Constant ------ Function
+// |
+// +- Instruction -+- BinaryOperator
+// |
+// +- BranchInst
+// |
+// +- CastInst
+// |
+// +- CallBase ----- CallInst
// |
// +- CmpInst
// |
@@ -82,6 +88,8 @@ class ReturnInst;
class StoreInst;
class User;
class Value;
+class CallBase;
+class CallInst;
/// Iterator for the `Use` edges of a User's operands.
/// \Returns the operand `Use` when dereferenced.
@@ -103,12 +111,20 @@ public:
OperandUseIterator() = default;
value_type operator*() const;
OperandUseIterator &operator++();
+ OperandUseIterator operator++(int) {
+ auto Copy = *this;
+ this->operator++();
+ return Copy;
+ }
bool operator==(const OperandUseIterator &Other) const {
return Use == Other.Use;
}
bool operator!=(const OperandUseIterator &Other) const {
return !(*this == Other);
}
+ OperandUseIterator operator+(unsigned Num) const;
+ OperandUseIterator operator-(unsigned Num) const;
+ int operator-(const OperandUseIterator &Other) const;
};
/// Iterator for the `Use` edges of a Value's users.
@@ -135,6 +151,7 @@ public:
bool operator!=(const UserUseIterator &Other) const {
return !(*this == Other);
}
+ const sandboxir::Use &getUse() const { return Use; }
};
/// A SandboxIR Value has users. This is the base class.
@@ -184,6 +201,8 @@ protected:
friend class LoadInst; // For getting `Val`.
friend class StoreInst; // For getting `Val`.
friend class ReturnInst; // For getting `Val`.
+ friend class CallBase; // For getting `Val`.
+ friend class CallInst; // For getting `Val`.
/// All values point to the context.
Context &Ctx;
@@ -417,7 +436,10 @@ public:
class Constant : public sandboxir::User {
Constant(llvm::Constant *C, sandboxir::Context &SBCtx)
: sandboxir::User(ClassID::Constant, C, SBCtx) {}
- friend class Context; // For constructor.
+ Constant(ClassID ID, llvm::Constant *C, sandboxir::Context &SBCtx)
+ : sandboxir::User(ID, C, SBCtx) {}
+ friend class Function; // For constructor
+ friend class Context; // For constructor.
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
return getOperandUseDefault(OpIdx, Verify);
}
@@ -435,7 +457,7 @@ public:
return getUseOperandNoDefault(Use);
}
#ifndef NDEBUG
- void verify() const final {
+ void verify() const override {
assert(isa<llvm::Constant>(Val) && "Expected Constant!");
}
friend raw_ostream &operator<<(raw_ostream &OS,
@@ -518,6 +540,7 @@ protected:
friend class LoadInst; // For getTopmostLLVMInstruction().
friend class StoreInst; // For getTopmostLLVMInstruction().
friend class ReturnInst; // For getTopmostLLVMInstruction().
+ friend class CallInst; // For getTopmostLLVMInstruction().
/// \Returns the LLVM IR Instructions that this SandboxIR maps to in program
/// order.
@@ -835,6 +858,177 @@ public:
#endif
};
+class CallBase : public Instruction {
+ CallBase(ClassID ID, Opcode Opc, llvm::Instruction *I, Context &Ctx)
+ : Instruction(ID, Opc, I, Ctx) {}
+ friend class CallInst; // For constructor.
+
+public:
+ static bool classof(const Value *From) {
+ auto Opc = From->getSubclassID();
+ return Opc == Instruction::ClassID::Call ||
+ Opc == Instruction::ClassID::Invoke ||
+ Opc == Instruction::ClassID::CallBr;
+ }
+
+ FunctionType *getFunctionType() const {
+ return cast<llvm::CallBase>(Val)->getFunctionType();
+ }
+
+ op_iterator data_operands_begin() { return op_begin(); }
+ const_op_iterator data_operands_begin() const {
+ return const_cast<CallBase *>(this)->data_operands_begin();
+ }
+ op_iterator data_operands_end() {
+ auto *LLVMCB = cast<llvm::CallBase>(Val);
+ auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
+ return op_begin() + Dist;
+ }
+ const_op_iterator data_operands_end() const {
+ auto *LLVMCB = cast<llvm::CallBase>(Val);
+ auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
+ return op_begin() + Dist;
+ }
+ iterator_range<op_iterator> data_ops() {
+ return make_range(data_operands_begin(), data_operands_end());
+ }
+ iterator_range<const_op_iterator> data_ops() const {
+ return make_range(data_operands_begin(), data_operands_end());
+ }
+ bool data_operands_empty() const {
+ return data_operands_end() == data_operands_begin();
+ }
+ unsigned data_operands_size() const {
+ return std::distance(data_operands_begin(), data_operands_end());
+ }
+ bool isDataOperand(Use U) const {
+ assert(this == U.getUser() &&
+ "Only valid to query with a use of this instruction!");
+ return cast<llvm::CallBase>(Val)->isDataOperand(U.LLVMUse);
+ }
+ unsigned getDataOperandNo(Use U) const {
+ assert(isDataOperand(U) && "Data operand # out of range!");
+ return cast<llvm::CallBase>(Val)->getDataOperandNo(U.LLVMUse);
+ }
+
+ /// Return the total number operands (not operand bundles) used by
+ /// every operand bundle in this OperandBundleUser.
+ unsigned getNumTotalBundleOperands() const {
+ return cast<llvm::CallBase>(Val)->getNumTotalBundleOperands();
+ }
+
+ op_iterator arg_begin() { return op_begin(); }
+ const_op_iterator arg_begin() const { return op_begin(); }
+ op_iterator arg_end() {
+ return data_operands_end() - getNumTotalBundleOperands();
+ }
+ const_op_iterator arg_end() const {
+ return const_cast<CallBase *>(this)->arg_end();
+ }
+ iterator_range<op_iterator> args() {
+ return make_range(arg_begin(), arg_end());
+ }
+ iterator_range<const_op_iterator> args() const {
+ return make_range(arg_begin(), arg_end());
+ }
+ bool arg_empty() const { return arg_end() == arg_begin(); }
+ unsigned arg_size() const { return arg_end() - arg_begin(); }
+
+ Value *getArgOperand(unsigned OpIdx) const {
+ assert(OpIdx < arg_size() && "Out of bounds!");
+ return getOperand(OpIdx);
+ }
+ void setArgOperand(unsigned OpIdx, Value *NewOp) {
+ assert(OpIdx < arg_size() && "Out of bounds!");
+ setOperand(OpIdx, NewOp);
+ }
+
+ Use getArgOperandUse(unsigned Idx) const {
+ assert(Idx < arg_size() && "Out of bounds!");
+ return getOperandUse(Idx);
+ }
+ Use getArgOperandUse(unsigned Idx) {
+ assert(Idx < arg_size() && "Out of bounds!");
+ return getOperandUse(Idx);
+ }
+
+ bool isArgOperand(Use U) const {
+ return cast<llvm::CallBase>(Val)->isArgOperand(U.LLVMUse);
+ }
+ unsigned getArgOperandNo(Use U) const {
+ return cast<llvm::CallBase>(Val)->getArgOperandNo(U.LLVMUse);
+ }
+ bool hasArgument(const Value *V) const { return is_contained(args(), V); }
+
+ Value *getCalledOperand() const;
+ Use getCalledOperandUse() const;
+
+ Function *getCalledFunction() const;
+ bool isIndirectCall() const {
+ return cast<llvm::CallBase>(Val)->isIndirectCall();
+ }
+ bool isCallee(Use U) const {
+ return cast<llvm::CallBase>(Val)->isCallee(U.LLVMUse);
+ }
+ Function *getCaller();
+ const Function *getCaller() const {
+ return const_cast<CallBase *>(this)->getCaller();
+ }
+ bool isMustTailCall() const {
+ return cast<llvm::CallBase>(Val)->isMustTailCall();
+ }
+ bool isTailCall() const { return cast<llvm::CallBase>(Val)->isTailCall(); }
+ Intrinsic::ID getIntrinsicID() const {
+ return cast<llvm::CallBase>(Val)->getIntrinsicID();
+ }
+ void setCalledOperand(Value *V) { getCalledOperandUse().set(V); }
+ void setCalledFunction(Function *F);
+ CallingConv::ID getCallingConv() const {
+ return cast<llvm::CallBase>(Val)->getCallingConv();
+ }
+ bool isInlineAsm() const { return cast<llvm::CallBase>(Val)->isInlineAsm(); }
+};
+
+class CallInst final : public CallBase {
+ /// Use Context::createCallInst(). Don't call the
+ /// constructor directly.
+ CallInst(llvm::Instruction *I, Context &Ctx)
+ : CallBase(ClassID::Call, Opcode::Call, I, Ctx) {}
+ friend class Context; // For accessing the constructor in
+ // create*()
+ Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
+ return getOperandUseDefault(OpIdx, Verify);
+ }
+ SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
+ return {cast<llvm::Instruction>(Val)};
+ }
+
+public:
+ static CallInst *create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, BBIterator WhereIt,
+ BasicBlock *WhereBB, Context &Ctx,
+ const Twine &NameStr = "");
+ static CallInst *create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, Instruction *InsertBefore,
+ Context &Ctx, const Twine &NameStr = "");
+ static CallInst *create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+ Context &Ctx, const Twine &NameStr = "");
+
+ static bool classof(const Value *From) {
+ return From->getSubclassID() == ClassID::Call;
+ }
+ unsigned getUseOperandNo(const Use &Use) const final {
+ return getUseOperandNoDefault(Use);
+ }
+ unsigned getNumOfIRInstrs() const final { return 1u; }
+#ifndef NDEBUG
+ void verify() const final {}
+ void dump(raw_ostream &OS) const override;
+ LLVM_DUMP_METHOD void dump() const override;
+#endif
+};
+
/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
/// an OpaqueInstr.
class OpaqueInst : public sandboxir::Instruction {
@@ -983,6 +1177,8 @@ protected:
friend StoreInst; // For createStoreInst()
ReturnInst *createReturnInst(llvm::ReturnInst *I);
friend ReturnInst; // For createReturnInst()
+ CallInst *createCallInst(llvm::CallInst *I);
+ friend CallInst; // For createCallInst()
public:
Context(LLVMContext &LLVMCtx)
@@ -1010,7 +1206,7 @@ public:
size_t getNumValues() const { return LLVMValueToValueMap.size(); }
};
-class Function : public sandboxir::Value {
+class Function : public Constant {
/// Helper for mapped_iterator.
struct LLVMBBToBB {
Context &Ctx;
@@ -1021,7 +1217,7 @@ class Function : public sandboxir::Value {
};
/// Use Context::createFunction() instead.
Function(llvm::Function *F, sandboxir::Context &Ctx)
- : sandboxir::Value(ClassID::Function, F, Ctx) {}
+ : Constant(ClassID::Function, F, Ctx) {}
friend class Context; // For constructor.
public:
@@ -1047,6 +1243,9 @@ public:
LLVMBBToBB BBGetter(Ctx);
return iterator(cast<llvm::Function>(Val)->end(), BBGetter);
}
+ FunctionType *getFunctionType() const {
+ return cast<llvm::Function>(Val)->getFunctionType();
+ }
#ifndef NDEBUG
void verify() const final {
diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
index f3d616774b3f..5f6fc84fc2e0 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def
+++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
@@ -30,6 +30,9 @@ DEF_INSTR(Br, OP(Br), BranchInst)
DEF_INSTR(Load, OP(Load), LoadInst)
DEF_INSTR(Store, OP(Store), StoreInst)
DEF_INSTR(Ret, OP(Ret), ReturnInst)
+DEF_INSTR(Call, OP(Call), CallInst)
+DEF_INSTR(Invoke, OP(Invoke), InvokeInst)
+DEF_INSTR(CallBr, OP(CallBr), CallBrInst)
#ifdef DEF_VALUE
#undef DEF_VALUE
diff --git a/llvm/include/llvm/SandboxIR/Use.h b/llvm/include/llvm/SandboxIR/Use.h
index 03cbfe6cb044..d30eb9059429 100644
--- a/llvm/include/llvm/SandboxIR/Use.h
+++ b/llvm/include/llvm/SandboxIR/Use.h
@@ -21,6 +21,7 @@ namespace llvm::sandboxir {
class Context;
class Value;
class User;
+class CallBase;
/// Represents a Def-use/Use-def edge in SandboxIR.
/// NOTE: Unlike llvm::Use, this is not an integral part of the use-def chains.
@@ -40,6 +41,7 @@ class Use {
friend class User; // For constructor
friend class OperandUseIterator; // For constructor
friend class UserUseIterator; // For accessing members
+ friend class CallBase; // For LLVMUse
public:
operator Value *() const { return get(); }
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 61c6aa5e5a3e..1704f0db4c59 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -345,6 +345,19 @@ bool llvm::isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L,
HeaderFirstNonPHI, AC, &DT);
}
+static bool suppressSpeculativeLoadForSanitizers(const Instruction &CtxI) {
+ const Function &F = *CtxI.getFunction();
+ // Speculative load may create a race that did not exist in the source.
+ return F.hasFnAttribute(Attribute::SanitizeThread) ||
+ // Speculative load may load data from dirty regions.
+ F.hasFnAttribute(Attribute::SanitizeAddress) ||
+ F.hasFnAttribute(Attribute::SanitizeHWAddress);
+}
+
+bool llvm::mustSuppressSpeculation(const LoadInst &LI) {
+ return !LI.isUnordered() || suppressSpeculativeLoadForSanitizers(LI);
+}
+
/// Check if executing a load of this pointer value cannot trap.
///
/// If DT and ScanFrom are specified this method performs context-sensitive
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index bfd26fadd237..497f6eafd22d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -6798,17 +6798,6 @@ bool llvm::onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V) {
V, /* AllowLifetime */ true, /* AllowDroppable */ true);
}
-bool llvm::mustSuppressSpeculation(const LoadInst &LI) {
- if (!LI.isUnordered())
- return true;
- const Function &F = *LI.getFunction();
- // Speculative load may create a race that did not exist in the source.
- return F.hasFnAttribute(Attribute::SanitizeThread) ||
- // Speculative load may load data from dirty regions.
- F.hasFnAttribute(Attribute::SanitizeAddress) ||
- F.hasFnAttribute(Attribute::SanitizeHWAddress);
-}
-
bool llvm::isSafeToSpeculativelyExecute(const Instruction *Inst,
const Instruction *CtxI,
AssumptionCache *AC,
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index ceadb34f53ea..da482765c7d1 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -16,7 +16,12 @@ using namespace llvm::sandboxir;
Value *Use::get() const { return Ctx->getValue(LLVMUse->get()); }
-void Use::set(Value *V) { LLVMUse->set(V->Val); }
+void Use::set(Value *V) {
+ auto &Tracker = Ctx->getTracker();
+ if (Tracker.isTracking())
+ Tracker.track(std::make_unique<UseSet>(*this, Tracker));
+ LLVMUse->set(V->Val);
+}
unsigned Use::getOperandNo() const { return Usr->getUseOperandNo(*this); }
@@ -84,6 +89,25 @@ UserUseIterator &UserUseIterator::operator++() {
return *this;
}
+OperandUseIterator OperandUseIterator::operator+(unsigned Num) const {
+ sandboxir::Use U = Use.getUser()->getOperandUseInternal(
+ Use.getOperandNo() + Num, /*Verify=*/true);
+ return OperandUseIterator(U);
+}
+
+OperandUseIterator OperandUseIterator::operator-(unsigned Num) const {
+ assert(Use.getOperandNo() >= Num && "Out of bounds!");
+ sandboxir::Use U = Use.getUser()->getOperandUseInternal(
+ Use.getOperandNo() - Num, /*Verify=*/true);
+ return OperandUseIterator(U);
+}
+
+int OperandUseIterator::operator-(const OperandUseIterator &Other) const {
+ int ThisOpNo = Use.getOperandNo();
+ int OtherOpNo = Other.Use.getOperandNo();
+ return ThisOpNo - OtherOpNo;
+}
+
Value::Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx)
: SubclassID(SubclassID), Val(Val), Ctx(Ctx) {
#ifndef NDEBUG
@@ -713,6 +737,78 @@ void ReturnInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
+#endif // NDEBUG
+
+Value *CallBase::getCalledOperand() const {
+ return Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledOperand());
+}
+
+Use CallBase::getCalledOperandUse() const {
+ llvm::Use *LLVMUse = &cast<llvm::CallBase>(Val)->getCalledOperandUse();
+ return Use(LLVMUse, cast<User>(Ctx.getValue(LLVMUse->getUser())), Ctx);
+}
+
+Function *CallBase::getCalledFunction() const {
+ return cast_or_null<Function>(
+ Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledFunction()));
+}
+Function *CallBase::getCaller() {
+ return cast<Function>(Ctx.getValue(cast<llvm::CallBase>(Val)->getCaller()));
+}
+
+void CallBase::setCalledFunction(Function *F) {
+ // F's function type is private, so we rely on `setCalledFunction()` to update
+ // it. But even though we are calling `setCalledFunction()` we also need to
+ // track this change at the SandboxIR level, which is why we call
+ // `setCalledOperand()` here.
+ // Note: This may break if `setCalledFunction()` early returns if `F`
+ // is already set, but we do have a unit test for it.
+ setCalledOperand(F);
+ cast<llvm::CallBase>(Val)->setCalledFunction(F->getFunctionType(),
+ cast<llvm::Function>(F->Val));
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, BasicBlock::iterator WhereIt,
+ BasicBlock *WhereBB, Context &Ctx,
+ const Twine &NameStr) {
+ auto &Builder = Ctx.getLLVMIRBuilder();
+ if (WhereIt != WhereBB->end())
+ Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+ else
+ Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+ SmallVector<llvm::Value *> LLVMArgs;
+ LLVMArgs.reserve(Args.size());
+ for (Value *Arg : Args)
+ LLVMArgs.push_back(Arg->Val);
+ llvm::CallInst *NewCI = Builder.CreateCall(FTy, Func->Val, LLVMArgs, NameStr);
+ return Ctx.createCallInst(NewCI);
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, Instruction *InsertBefore,
+ Context &Ctx, const Twine &NameStr) {
+ return CallInst::create(FTy, Func, Args, InsertBefore->getIterator(),
+ InsertBefore->getParent(), Ctx, NameStr);
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+ ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+ Context &Ctx, const Twine &NameStr) {
+ return CallInst::create(FTy, Func, Args, InsertAtEnd->end(), InsertAtEnd, Ctx,
+ NameStr);
+}
+
+#ifndef NDEBUG
+void CallInst::dump(raw_ostream &OS) const {
+ dumpCommonPrefix(OS);
+ dumpCommonSuffix(OS);
+}
+
+void CallInst::dump() const {
+ dump(dbgs());
+ dbgs() << "\n";
+}
void OpaqueInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
@@ -819,7 +915,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
return It->second.get();
if (auto *C = dyn_cast<llvm::Constant>(LLVMV)) {
- It->second = std::unique_ptr<Constant>(new Constant(C, *this));
+ if (auto *F = dyn_cast<llvm::Function>(LLVMV))
+ It->second = std::unique_ptr<Function>(new Function(F, *this));
+ else
+ It->second = std::unique_ptr<Constant>(new Constant(C, *this));
auto *NewC = It->second.get();
for (llvm::Value *COp : C->operands())
getOrCreateValueInternal(COp, C);
@@ -864,6 +963,11 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
It->second = std::unique_ptr<ReturnInst>(new ReturnInst(LLVMRet, *this));
return It->second.get();
}
+ case llvm::Instruction::Call: {
+ auto *LLVMCall = cast<llvm::CallInst>(LLVMV);
+ It->second = std::unique_ptr<CallInst>(new CallInst(LLVMCall, *this));
+ return It->second.get();
+ }
default:
break;
}
@@ -907,6 +1011,11 @@ ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) {
return cast<ReturnInst>(registerValue(std::move(NewPtr)));
}
+CallInst *Context::createCallInst(llvm::CallInst *I) {
+ auto NewPtr = std::unique_ptr<CallInst>(new CallInst(I, *this));
+ return cast<CallInst>(registerValue(std::move(NewPtr)));
+}
+
Value *Context::getValue(llvm::Value *V) const {
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end())
@@ -917,13 +1026,13 @@ Value *Context::getValue(llvm::Value *V) const {
Function *Context::createFunction(llvm::Function *F) {
assert(getValue(F) == nullptr && "Already exists!");
auto NewFPtr = std::unique_ptr<Function>(new Function(F, *this));
+ auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
// Create arguments.
for (auto &Arg : F->args())
getOrCreateArgument(&Arg);
// Create BBs.
for (auto &BB : *F)
createBasicBlock(&BB);
- auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
return SBF;
}
diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index a0e63bf12400..812874ff3c17 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -1528,11 +1528,7 @@ static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,
bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
Function &F, FunctionAnalysisManager &FAM) const {
- bool Skip = [&]() {
- if (ClRandomSkipRate.getNumOccurrences()) {
- std::bernoulli_distribution D(ClRandomSkipRate);
- return !D(*Rng);
- }
+ auto SkipHot = [&]() {
if (!ClHotPercentileCutoff.getNumOccurrences())
return false;
auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
@@ -1544,7 +1540,16 @@ bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
}
return PSI->isFunctionHotInCallGraphNthPercentile(
ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));
- }();
+ };
+
+ auto SkipRandom = [&]() {
+ if (!ClRandomSkipRate.getNumOccurrences())
+ return false;
+ std::bernoulli_distribution D(ClRandomSkipRate);
+ return !D(*Rng);
+ };
+
+ bool Skip = SkipRandom() || SkipHot();
emitRemark(F, FAM.getResult<OptimizationRemarkEmitterAnalysis>(F), Skip);
return Skip;
}
diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
index 0115809e939e..19cf7dc7e754 100644
--- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
+++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
@@ -76,13 +76,25 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue;
std::unique_ptr<RandomNumberGenerator> Rng;
- auto ShouldRemove = [&](bool IsHot) {
- if (!RandomRate.getNumOccurrences())
- return IsHot;
+ auto GetRng = [&]() -> RandomNumberGenerator & {
if (!Rng)
Rng = F.getParent()->createRNG(F.getName());
- std::bernoulli_distribution D(RandomRate);
- return !D(*Rng);
+ return *Rng;
+ };
+
+ auto ShouldRemoveHot = [&](const BasicBlock &BB) {
+ return HotPercentileCutoff.getNumOccurrences() && PSI &&
+ PSI->isHotCountNthPercentile(
+ HotPercentileCutoff, BFI.getBlockProfileCount(&BB).value_or(0));
+ };
+
+ auto ShouldRemoveRandom = [&]() {
+ return RandomRate.getNumOccurrences() &&
+ !std::bernoulli_distribution(RandomRate)(GetRng());
+ };
+
+ auto ShouldRemove = [&](const BasicBlock &BB) {
+ return ShouldRemoveRandom() || ShouldRemoveHot(BB);
};
for (BasicBlock &BB : F) {
@@ -96,13 +108,7 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
case Intrinsic::allow_runtime_check: {
++NumChecksTotal;
- bool IsHot = false;
- if (PSI) {
- uint64_t Count = BFI.getBlockProfileCount(&BB).value_or(0);
- IsHot = PSI->isHotCountNthPercentile(HotPercentileCutoff, Count);
- }
-
- bool ToRemove = ShouldRemove(IsHot);
+ bool ToRemove = ShouldRemove(BB);
ReplaceWithValue.push_back({
II,
ToRemove,
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-constant.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-constant.mir
index 390541ae7684..27d4698f8f6e 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-constant.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-constant.mir
@@ -407,6 +407,197 @@ body: |
...
---
+name: constant_s_p0
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ ; WAVE64-LABEL: name: constant_s_p0
+ ; WAVE64: [[S_MOV_B:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 0
+ ; WAVE64-NEXT: [[S_MOV_B1:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 1
+ ; WAVE64-NEXT: [[S_MOV_B2:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -1
+ ; WAVE64-NEXT: [[S_MOV_B3:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -54
+ ; WAVE64-NEXT: [[S_MOV_B4:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 27
+ ; WAVE64-NEXT: [[S_MOV_B5:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 4294967295
+ ; WAVE64-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+ ; WAVE64-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 1
+ ; WAVE64-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_]], %subreg.sub0, [[S_MOV_B32_1]], %subreg.sub1
+ ; WAVE64-NEXT: [[S_MOV_B32_2:%[0-9]+]]:sreg_32 = S_MOV_B32 23255
+ ; WAVE64-NEXT: [[S_MOV_B32_3:%[0-9]+]]:sreg_32 = S_MOV_B32 -16
+ ; WAVE64-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_2]], %subreg.sub0, [[S_MOV_B32_3]], %subreg.sub1
+ ; WAVE64-NEXT: S_ENDPGM 0, implicit [[S_MOV_B]], implicit [[S_MOV_B1]], implicit [[S_MOV_B2]], implicit [[S_MOV_B3]], implicit [[S_MOV_B4]], implicit [[S_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ ;
+ ; WAVE32-LABEL: name: constant_s_p0
+ ; WAVE32: [[S_MOV_B:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 0
+ ; WAVE32-NEXT: [[S_MOV_B1:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 1
+ ; WAVE32-NEXT: [[S_MOV_B2:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -1
+ ; WAVE32-NEXT: [[S_MOV_B3:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -54
+ ; WAVE32-NEXT: [[S_MOV_B4:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 27
+ ; WAVE32-NEXT: [[S_MOV_B5:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 4294967295
+ ; WAVE32-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+ ; WAVE32-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 1
+ ; WAVE32-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_]], %subreg.sub0, [[S_MOV_B32_1]], %subreg.sub1
+ ; WAVE32-NEXT: [[S_MOV_B32_2:%[0-9]+]]:sreg_32 = S_MOV_B32 23255
+ ; WAVE32-NEXT: [[S_MOV_B32_3:%[0-9]+]]:sreg_32 = S_MOV_B32 -16
+ ; WAVE32-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_2]], %subreg.sub0, [[S_MOV_B32_3]], %subreg.sub1
+ ; WAVE32-NEXT: S_ENDPGM 0, implicit [[S_MOV_B]], implicit [[S_MOV_B1]], implicit [[S_MOV_B2]], implicit [[S_MOV_B3]], implicit [[S_MOV_B4]], implicit [[S_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ %0:sgpr(p0) = G_CONSTANT i64 0
+ %1:sgpr(p0) = G_CONSTANT i64 1
+ %2:sgpr(p0) = G_CONSTANT i64 -1
+ %3:sgpr(p0) = G_CONSTANT i64 -54
+ %4:sgpr(p0) = G_CONSTANT i64 27
+ %5:sgpr(p0) = G_CONSTANT i64 4294967295
+ %6:sgpr(p0) = G_CONSTANT i64 4294967296
+ %7:sgpr(p0) = G_CONSTANT i64 18446744004990098135
+ S_ENDPGM 0, implicit %0 , implicit %1 , implicit %2, implicit %3, implicit %4, implicit %5, implicit %6, implicit %7
+...
+
+---
+name: constant_v_p0
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ ; WAVE64-LABEL: name: constant_v_p0
+ ; WAVE64: [[V_MOV_B:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 0, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B1:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 1, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B2:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -1, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B3:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -54, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B4:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 27, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B5:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 4294967295, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ ; WAVE64-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_]], %subreg.sub0, [[V_MOV_B32_e32_1]], %subreg.sub1
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 23255, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_3:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -16, implicit $exec
+ ; WAVE64-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_3]], %subreg.sub1
+ ; WAVE64-NEXT: S_ENDPGM 0, implicit [[V_MOV_B]], implicit [[V_MOV_B1]], implicit [[V_MOV_B2]], implicit [[V_MOV_B3]], implicit [[V_MOV_B4]], implicit [[V_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ ;
+ ; WAVE32-LABEL: name: constant_v_p0
+ ; WAVE32: [[V_MOV_B:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 0, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B1:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 1, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B2:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -1, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B3:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -54, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B4:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 27, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B5:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 4294967295, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ ; WAVE32-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_]], %subreg.sub0, [[V_MOV_B32_e32_1]], %subreg.sub1
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 23255, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_3:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -16, implicit $exec
+ ; WAVE32-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_3]], %subreg.sub1
+ ; WAVE32-NEXT: S_ENDPGM 0, implicit [[V_MOV_B]], implicit [[V_MOV_B1]], implicit [[V_MOV_B2]], implicit [[V_MOV_B3]], implicit [[V_MOV_B4]], implicit [[V_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ %0:vgpr(p0) = G_CONSTANT i64 0
+ %1:vgpr(p0) = G_CONSTANT i64 1
+ %2:vgpr(p0) = G_CONSTANT i64 -1
+ %3:vgpr(p0) = G_CONSTANT i64 -54
+ %4:vgpr(p0) = G_CONSTANT i64 27
+ %5:vgpr(p0) = G_CONSTANT i64 4294967295
+ %6:vgpr(p0) = G_CONSTANT i64 4294967296
+ %7:vgpr(p0) = G_CONSTANT i64 18446744004990098135
+ S_ENDPGM 0, implicit %0 , implicit %1 , implicit %2, implicit %3, implicit %4, implicit %5, implicit %6, implicit %7
+...
+---
+name: constant_s_p4
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ ; WAVE64-LABEL: name: constant_s_p4
+ ; WAVE64: [[S_MOV_B:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 0
+ ; WAVE64-NEXT: [[S_MOV_B1:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 1
+ ; WAVE64-NEXT: [[S_MOV_B2:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -1
+ ; WAVE64-NEXT: [[S_MOV_B3:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -54
+ ; WAVE64-NEXT: [[S_MOV_B4:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 27
+ ; WAVE64-NEXT: [[S_MOV_B5:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 4294967295
+ ; WAVE64-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+ ; WAVE64-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 1
+ ; WAVE64-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_]], %subreg.sub0, [[S_MOV_B32_1]], %subreg.sub1
+ ; WAVE64-NEXT: [[S_MOV_B32_2:%[0-9]+]]:sreg_32 = S_MOV_B32 23255
+ ; WAVE64-NEXT: [[S_MOV_B32_3:%[0-9]+]]:sreg_32 = S_MOV_B32 -16
+ ; WAVE64-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_2]], %subreg.sub0, [[S_MOV_B32_3]], %subreg.sub1
+ ; WAVE64-NEXT: S_ENDPGM 0, implicit [[S_MOV_B]], implicit [[S_MOV_B1]], implicit [[S_MOV_B2]], implicit [[S_MOV_B3]], implicit [[S_MOV_B4]], implicit [[S_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ ;
+ ; WAVE32-LABEL: name: constant_s_p4
+ ; WAVE32: [[S_MOV_B:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 0
+ ; WAVE32-NEXT: [[S_MOV_B1:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 1
+ ; WAVE32-NEXT: [[S_MOV_B2:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -1
+ ; WAVE32-NEXT: [[S_MOV_B3:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO -54
+ ; WAVE32-NEXT: [[S_MOV_B4:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 27
+ ; WAVE32-NEXT: [[S_MOV_B5:%[0-9]+]]:sreg_64 = S_MOV_B64_IMM_PSEUDO 4294967295
+ ; WAVE32-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+ ; WAVE32-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 1
+ ; WAVE32-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_]], %subreg.sub0, [[S_MOV_B32_1]], %subreg.sub1
+ ; WAVE32-NEXT: [[S_MOV_B32_2:%[0-9]+]]:sreg_32 = S_MOV_B32 23255
+ ; WAVE32-NEXT: [[S_MOV_B32_3:%[0-9]+]]:sreg_32 = S_MOV_B32 -16
+ ; WAVE32-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_MOV_B32_2]], %subreg.sub0, [[S_MOV_B32_3]], %subreg.sub1
+ ; WAVE32-NEXT: S_ENDPGM 0, implicit [[S_MOV_B]], implicit [[S_MOV_B1]], implicit [[S_MOV_B2]], implicit [[S_MOV_B3]], implicit [[S_MOV_B4]], implicit [[S_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ %0:sgpr(p4) = G_CONSTANT i64 0
+ %1:sgpr(p4) = G_CONSTANT i64 1
+ %2:sgpr(p4) = G_CONSTANT i64 -1
+ %3:sgpr(p4) = G_CONSTANT i64 -54
+ %4:sgpr(p4) = G_CONSTANT i64 27
+ %5:sgpr(p4) = G_CONSTANT i64 4294967295
+ %6:sgpr(p4) = G_CONSTANT i64 4294967296
+ %7:sgpr(p4) = G_CONSTANT i64 18446744004990098135
+ S_ENDPGM 0, implicit %0 , implicit %1 , implicit %2, implicit %3, implicit %4, implicit %5, implicit %6, implicit %7
+...
+
+---
+name: constant_v_p4
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ ; WAVE64-LABEL: name: constant_v_p4
+ ; WAVE64: [[V_MOV_B:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 0, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B1:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 1, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B2:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -1, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B3:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -54, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B4:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 27, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B5:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 4294967295, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ ; WAVE64-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_]], %subreg.sub0, [[V_MOV_B32_e32_1]], %subreg.sub1
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 23255, implicit $exec
+ ; WAVE64-NEXT: [[V_MOV_B32_e32_3:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -16, implicit $exec
+ ; WAVE64-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_3]], %subreg.sub1
+ ; WAVE64-NEXT: S_ENDPGM 0, implicit [[V_MOV_B]], implicit [[V_MOV_B1]], implicit [[V_MOV_B2]], implicit [[V_MOV_B3]], implicit [[V_MOV_B4]], implicit [[V_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ ;
+ ; WAVE32-LABEL: name: constant_v_p4
+ ; WAVE32: [[V_MOV_B:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 0, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B1:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 1, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B2:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -1, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B3:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO -54, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B4:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 27, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B5:%[0-9]+]]:vreg_64 = V_MOV_B64_PSEUDO 4294967295, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+ ; WAVE32-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_]], %subreg.sub0, [[V_MOV_B32_e32_1]], %subreg.sub1
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 23255, implicit $exec
+ ; WAVE32-NEXT: [[V_MOV_B32_e32_3:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -16, implicit $exec
+ ; WAVE32-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_3]], %subreg.sub1
+ ; WAVE32-NEXT: S_ENDPGM 0, implicit [[V_MOV_B]], implicit [[V_MOV_B1]], implicit [[V_MOV_B2]], implicit [[V_MOV_B3]], implicit [[V_MOV_B4]], implicit [[V_MOV_B5]], implicit [[REG_SEQUENCE]], implicit [[REG_SEQUENCE1]]
+ %0:vgpr(p4) = G_CONSTANT i64 0
+ %1:vgpr(p4) = G_CONSTANT i64 1
+ %2:vgpr(p4) = G_CONSTANT i64 -1
+ %3:vgpr(p4) = G_CONSTANT i64 -54
+ %4:vgpr(p4) = G_CONSTANT i64 27
+ %5:vgpr(p4) = G_CONSTANT i64 4294967295
+ %6:vgpr(p4) = G_CONSTANT i64 4294967296
+ %7:vgpr(p4) = G_CONSTANT i64 18446744004990098135
+ S_ENDPGM 0, implicit %0 , implicit %1 , implicit %2, implicit %3, implicit %4, implicit %5, implicit %6, implicit %7
+...
+
+---
name: constant_s_p999
legalized: true
regBankSelected: true
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/pgo-opt-out.ll b/llvm/test/Instrumentation/HWAddressSanitizer/pgo-opt-out.ll
index 01eda4e35d7c..0ef94235fd51 100644
--- a/llvm/test/Instrumentation/HWAddressSanitizer/pgo-opt-out.ll
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/pgo-opt-out.ll
@@ -2,6 +2,8 @@
; RUN: opt < %s -passes='require<profile-summary>,hwasan' -pass-remarks=hwasan -pass-remarks-missed=hwasan -S -hwasan-percentile-cutoff-hot=990000 2>&1 | FileCheck %s --check-prefix=NONE
; RUN: opt < %s -passes='require<profile-summary>,hwasan' -pass-remarks=hwasan -pass-remarks-missed=hwasan -S -hwasan-random-rate=1.0 2>&1 | FileCheck %s --check-prefix=ALL
; RUN: opt < %s -passes='require<profile-summary>,hwasan' -pass-remarks=hwasan -pass-remarks-missed=hwasan -S -hwasan-random-rate=0.0 2>&1 | FileCheck %s --check-prefix=NONE
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -pass-remarks=hwasan -pass-remarks-missed=hwasan -S -hwasan-random-rate=1.0 -hwasan-percentile-cutoff-hot=990000 2>&1 | FileCheck %s --check-prefix=NONE
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -pass-remarks=hwasan -pass-remarks-missed=hwasan -S -hwasan-random-rate=0.0 -hwasan-percentile-cutoff-hot=700000 2>&1 | FileCheck %s --check-prefix=NONE
; ALL: remark: <unknown>:0:0: Sanitized: F=sanitize
; ALL: @sanitized
diff --git a/llvm/test/Transforms/lower-builtin-allow-check.ll b/llvm/test/Transforms/lower-builtin-allow-check.ll
index 2f6fa96ffd9c..bcd9722d2b28 100644
--- a/llvm/test/Transforms/lower-builtin-allow-check.ll
+++ b/llvm/test/Transforms/lower-builtin-allow-check.ll
@@ -309,7 +309,7 @@ define dso_local noundef i32 @veryHot(ptr noundef readonly %0) !prof !39 {
; ALL70-LABEL: define dso_local noundef i32 @veryHot(
; ALL70-SAME: ptr noundef readonly [[TMP0:%.*]]) !prof [[PROF17:![0-9]+]] {
; ALL70-NEXT: [[CHK:%.*]] = icmp eq ptr [[TMP0]], null
-; ALL70-NEXT: [[HOT:%.*]] = xor i1 true, true
+; ALL70-NEXT: [[HOT:%.*]] = xor i1 false, true
; ALL70-NEXT: [[TMP2:%.*]] = or i1 [[CHK]], [[HOT]]
; ALL70-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP4:%.*]]
; ALL70: 3:
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index c600103fe10c..05ec42c952eb 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -90,7 +90,7 @@ define void @foo(i32 %v1) {
EXPECT_FALSE(isa<sandboxir::Instruction>(Const0));
EXPECT_TRUE(isa<sandboxir::Instruction>(OpaqueI));
- EXPECT_FALSE(isa<sandboxir::User>(F));
+ EXPECT_TRUE(isa<sandboxir::User>(F));
EXPECT_FALSE(isa<sandboxir::User>(Arg0));
EXPECT_FALSE(isa<sandboxir::User>(BB));
EXPECT_TRUE(isa<sandboxir::User>(AddI));
@@ -180,8 +180,8 @@ define i32 @foo(i32 %v0, i32 %v1) {
BS << "\n";
I0->getOperandUse(0).dump(BS);
EXPECT_EQ(Buff, R"IR(
-Def: i32 %v0 ; SB1. (Argument)
-User: %add0 = add i32 %v0, %v1 ; SB4. (Opaque)
+Def: i32 %v0 ; SB2. (Argument)
+User: %add0 = add i32 %v0, %v1 ; SB5. (Opaque)
OperandNo: 0
)IR");
#endif // NDEBUG
@@ -398,10 +398,10 @@ bb1:
EXPECT_EQ(Buff, R"IR(
void @foo(i32 %arg0, i32 %arg1) {
bb0:
- br label %bb1 ; SB3. (Br)
+ br label %bb1 ; SB4. (Br)
bb1:
- ret void ; SB5. (Ret)
+ ret void ; SB6. (Ret)
}
)IR");
}
@@ -466,7 +466,7 @@ bb1:
BB0.dump(BS);
EXPECT_EQ(Buff, R"IR(
bb0:
- br label %bb1 ; SB2. (Br)
+ br label %bb1 ; SB3. (Br)
)IR");
}
#endif // NDEBUG
@@ -836,3 +836,203 @@ define i8 @foo(i8 %val) {
sandboxir::ReturnInst::create(Val, /*InsertAtEnd=*/BB, Ctx));
EXPECT_EQ(NewRet4->getReturnValue(), Val);
}
+
+TEST_F(SandboxIRTest, CallBase) {
+ parseIR(C, R"IR(
+declare void @bar1(i8)
+declare void @bar2()
+declare void @bar3()
+declare void @variadic(ptr, ...)
+
+define i8 @foo(i8 %arg0, i32 %arg1, ptr %indirectFoo) {
+ %call = call i8 @foo(i8 %arg0, i32 %arg1)
+ call void @bar1(i8 %arg0)
+ call void @bar2()
+ call void %indirectFoo()
+ call void @bar2() noreturn
+ tail call fastcc void @bar2()
+ call void (ptr, ...) @variadic(ptr %indirectFoo, i32 1)
+ ret i8 %call
+}
+)IR");
+ llvm::Function &LLVMF = *M->getFunction("foo");
+ unsigned ArgIdx = 0;
+ llvm::Argument *LLVMArg0 = LLVMF.getArg(ArgIdx++);
+ llvm::Argument *LLVMArg1 = LLVMF.getArg(ArgIdx++);
+ llvm::BasicBlock *LLVMBB = &*LLVMF.begin();
+ SmallVector<llvm::CallBase *, 8> LLVMCalls;
+ auto LLVMIt = LLVMBB->begin();
+ while (isa<llvm::CallBase>(&*LLVMIt))
+ LLVMCalls.push_back(cast<llvm::CallBase>(&*LLVMIt++));
+
+ sandboxir::Context Ctx(C);
+ sandboxir::Function &F = *Ctx.createFunction(&LLVMF);
+
+ for (llvm::CallBase *LLVMCall : LLVMCalls) {
+ // Check classof(Instruction *).
+ auto *Call = cast<sandboxir::CallBase>(Ctx.getValue(LLVMCall));
+ // Check classof(Value *).
+ EXPECT_TRUE(isa<sandboxir::CallBase>((sandboxir::Value *)Call));
+ // Check getFunctionType().
+ EXPECT_EQ(Call->getFunctionType(), LLVMCall->getFunctionType());
+ // Check data_ops().
+ EXPECT_EQ(range_size(Call->data_ops()), range_size(LLVMCall->data_ops()));
+ auto DataOpIt = Call->data_operands_begin();
+ for (llvm::Use &LLVMUse : LLVMCall->data_ops()) {
+ Value *LLVMOp = LLVMUse.get();
+ sandboxir::Use Use = *DataOpIt++;
+ EXPECT_EQ(Ctx.getValue(LLVMOp), Use.get());
+ // Check isDataOperand().
+ EXPECT_EQ(Call->isDataOperand(Use), LLVMCall->isDataOperand(&LLVMUse));
+ // Check getDataOperandNo().
+ EXPECT_EQ(Call->getDataOperandNo(Use),
+ LLVMCall->getDataOperandNo(&LLVMUse));
+ // Check isArgOperand().
+ EXPECT_EQ(Call->isArgOperand(Use), LLVMCall->isArgOperand(&LLVMUse));
+ // Check isCallee().
+ EXPECT_EQ(Call->isCallee(Use), LLVMCall->isCallee(&LLVMUse));
+ }
+ // Check data_operands_empty().
+ EXPECT_EQ(Call->data_operands_empty(), LLVMCall->data_operands_empty());
+ // Check data_operands_size().
+ EXPECT_EQ(Call->data_operands_size(), LLVMCall->data_operands_size());
+ // Check getNumTotalBundleOperands().
+ EXPECT_EQ(Call->getNumTotalBundleOperands(),
+ LLVMCall->getNumTotalBundleOperands());
+ // Check args().
+ EXPECT_EQ(range_size(Call->args()), range_size(LLVMCall->args()));
+ auto ArgIt = Call->arg_begin();
+ for (llvm::Use &LLVMUse : LLVMCall->args()) {
+ Value *LLVMArg = LLVMUse.get();
+ sandboxir::Use Use = *ArgIt++;
+ EXPECT_EQ(Ctx.getValue(LLVMArg), Use.get());
+ }
+ // Check arg_empty().
+ EXPECT_EQ(Call->arg_empty(), LLVMCall->arg_empty());
+ // Check arg_size().
+ EXPECT_EQ(Call->arg_size(), LLVMCall->arg_size());
+ for (unsigned ArgIdx = 0, E = Call->arg_size(); ArgIdx != E; ++ArgIdx) {
+ // Check getArgOperand().
+ EXPECT_EQ(Call->getArgOperand(ArgIdx),
+ Ctx.getValue(LLVMCall->getArgOperand(ArgIdx)));
+ // Check getArgOperandUse().
+ sandboxir::Use Use = Call->getArgOperandUse(ArgIdx);
+ llvm::Use &LLVMUse = LLVMCall->getArgOperandUse(ArgIdx);
+ EXPECT_EQ(Use.get(), Ctx.getValue(LLVMUse.get()));
+ // Check getArgOperandNo().
+ EXPECT_EQ(Call->getArgOperandNo(Use),
+ LLVMCall->getArgOperandNo(&LLVMUse));
+ }
+ // Check hasArgument().
+ SmallVector<llvm::Value *> TestArgs(
+ {LLVMArg0, LLVMArg1, &LLVMF, LLVMBB, LLVMCall});
+ for (llvm::Value *LLVMV : TestArgs) {
+ sandboxir::Value *V = Ctx.getValue(LLVMV);
+ EXPECT_EQ(Call->hasArgument(V), LLVMCall->hasArgument(LLVMV));
+ }
+ // Check getCalledOperand().
+ EXPECT_EQ(Call->getCalledOperand(),
+ Ctx.getValue(LLVMCall->getCalledOperand()));
+ // Check getCalledOperandUse().
+ EXPECT_EQ(Call->getCalledOperandUse().get(),
+ Ctx.getValue(LLVMCall->getCalledOperandUse()));
+ // Check getCalledFunction().
+ if (LLVMCall->getCalledFunction() == nullptr)
+ EXPECT_EQ(Call->getCalledFunction(), nullptr);
+ else {
+ auto *LLVMCF = cast<llvm::Function>(LLVMCall->getCalledFunction());
+ (void)LLVMCF;
+ EXPECT_EQ(Call->getCalledFunction(),
+ cast<sandboxir::Function>(
+ Ctx.getValue(LLVMCall->getCalledFunction())));
+ }
+ // Check isIndirectCall().
+ EXPECT_EQ(Call->isIndirectCall(), LLVMCall->isIndirectCall());
+ // Check getCaller().
+ EXPECT_EQ(Call->getCaller(), Ctx.getValue(LLVMCall->getCaller()));
+ // Check isMustTailCall().
+ EXPECT_EQ(Call->isMustTailCall(), LLVMCall->isMustTailCall());
+ // Check isTailCall().
+ EXPECT_EQ(Call->isTailCall(), LLVMCall->isTailCall());
+ // Check getIntrinsicID().
+ EXPECT_EQ(Call->getIntrinsicID(), LLVMCall->getIntrinsicID());
+ // Check getCallingConv().
+ EXPECT_EQ(Call->getCallingConv(), LLVMCall->getCallingConv());
+ // Check isInlineAsm().
+ EXPECT_EQ(Call->isInlineAsm(), LLVMCall->isInlineAsm());
+ }
+
+ auto *Arg0 = F.getArg(0);
+ auto *Arg1 = F.getArg(1);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *Call0 = cast<sandboxir::CallBase>(&*It++);
+ [[maybe_unused]] auto *Call1 = cast<sandboxir::CallBase>(&*It++);
+ auto *Call2 = cast<sandboxir::CallBase>(&*It++);
+ // Check setArgOperand
+ Call0->setArgOperand(0, Arg1);
+ EXPECT_EQ(Call0->getArgOperand(0), Arg1);
+ Call0->setArgOperand(0, Arg0);
+ EXPECT_EQ(Call0->getArgOperand(0), Arg0);
+
+ auto *Bar3F = Ctx.createFunction(M->getFunction("bar3"));
+
+ // Check setCalledOperand
+ auto *SvOp = Call0->getCalledOperand();
+ Call0->setCalledOperand(Bar3F);
+ EXPECT_EQ(Call0->getCalledOperand(), Bar3F);
+ Call0->setCalledOperand(SvOp);
+ // Check setCalledFunction
+ Call2->setCalledFunction(Bar3F);
+ EXPECT_EQ(Call2->getCalledFunction(), Bar3F);
+}
+
+TEST_F(SandboxIRTest, CallInst) {
+ parseIR(C, R"IR(
+define i8 @foo(i8 %arg) {
+ %call = call i8 @foo(i8 %arg)
+ ret i8 %call
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto &F = *Ctx.createFunction(&LLVMF);
+ unsigned ArgIdx = 0;
+ auto *Arg0 = F.getArg(ArgIdx++);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *Call = cast<sandboxir::CallInst>(&*It++);
+ auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+ EXPECT_EQ(Call->getNumOperands(), 2u);
+ EXPECT_EQ(Ret->getOpcode(), sandboxir::Instruction::Opcode::Ret);
+ FunctionType *FTy = F.getFunctionType();
+ SmallVector<sandboxir::Value *, 1> Args;
+ Args.push_back(Arg0);
+ {
+ // Check create() WhereIt.
+ auto *Call = cast<sandboxir::CallInst>(sandboxir::CallInst::create(
+ FTy, &F, Args, /*WhereIt=*/Ret->getIterator(), BB, Ctx));
+ EXPECT_EQ(Call->getNextNode(), Ret);
+ EXPECT_EQ(Call->getCalledFunction(), &F);
+ EXPECT_EQ(range_size(Call->args()), 1u);
+ EXPECT_EQ(Call->getArgOperand(0), Arg0);
+ }
+ {
+ // Check create() InsertBefore.
+ auto *Call = cast<sandboxir::CallInst>(
+ sandboxir::CallInst::create(FTy, &F, Args, /*InsertBefore=*/Ret, Ctx));
+ EXPECT_EQ(Call->getNextNode(), Ret);
+ EXPECT_EQ(Call->getCalledFunction(), &F);
+ EXPECT_EQ(range_size(Call->args()), 1u);
+ EXPECT_EQ(Call->getArgOperand(0), Arg0);
+ }
+ {
+ // Check create() InsertAtEnd.
+ auto *Call = cast<sandboxir::CallInst>(
+ sandboxir::CallInst::create(FTy, &F, Args, /*InsertAtEnd=*/BB, Ctx));
+ EXPECT_EQ(Call->getPrevNode(), Ret);
+ EXPECT_EQ(Call->getCalledFunction(), &F);
+ EXPECT_EQ(range_size(Call->args()), 1u);
+ EXPECT_EQ(Call->getArgOperand(0), Arg0);
+ }
+}
diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp
index dd9dcd543236..5111d5f38798 100644
--- a/llvm/unittests/SandboxIR/TrackerTest.cpp
+++ b/llvm/unittests/SandboxIR/TrackerTest.cpp
@@ -69,6 +69,34 @@ define void @foo(ptr %ptr) {
EXPECT_EQ(Ld->getOperand(0), Gep0);
}
+TEST_F(TrackerTest, SetUse) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %arg) {
+ %ld = load i8, ptr %ptr
+ %add = add i8 %ld, %arg
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(&LLVMF);
+ unsigned ArgIdx = 0;
+ auto *Arg0 = F->getArg(ArgIdx++);
+ auto *BB = &*F->begin();
+ auto &Tracker = Ctx.getTracker();
+ Tracker.save();
+ auto It = BB->begin();
+ auto *Ld = &*It++;
+ auto *Add = &*It++;
+
+ Ctx.save();
+ sandboxir::Use Use = Add->getOperandUse(0);
+ Use.set(Arg0);
+ EXPECT_EQ(Add->getOperand(0), Arg0);
+ Ctx.revert();
+ EXPECT_EQ(Add->getOperand(0), Ld);
+}
+
TEST_F(TrackerTest, SwapOperands) {
parseIR(C, R"IR(
define void @foo(i1 %cond) {
@@ -413,3 +441,50 @@ define i32 @foo(i32 %arg) {
EXPECT_EQ(&*It++, Ret);
EXPECT_EQ(It, BB->end());
}
+
+TEST_F(TrackerTest, CallBaseSetters) {
+ parseIR(C, R"IR(
+declare void @bar1(i8)
+declare void @bar2(i8)
+
+define void @foo(i8 %arg0, i8 %arg1) {
+ call void @bar1(i8 %arg0)
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+
+ auto *F = Ctx.createFunction(&LLVMF);
+ unsigned ArgIdx = 0;
+ auto *Arg0 = F->getArg(ArgIdx++);
+ auto *Arg1 = F->getArg(ArgIdx++);
+ auto *BB = &*F->begin();
+ auto It = BB->begin();
+ auto *Call = cast<sandboxir::CallBase>(&*It++);
+ [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+ // Check setArgOperand().
+ Ctx.save();
+ Call->setArgOperand(0, Arg1);
+ EXPECT_EQ(Call->getArgOperand(0), Arg1);
+ Ctx.revert();
+ EXPECT_EQ(Call->getArgOperand(0), Arg0);
+
+ auto *Bar1F = Call->getCalledFunction();
+ auto *Bar2F = Ctx.createFunction(M->getFunction("bar2"));
+
+ // Check setCalledOperand().
+ Ctx.save();
+ Call->setCalledOperand(Bar2F);
+ EXPECT_EQ(Call->getCalledOperand(), Bar2F);
+ Ctx.revert();
+ EXPECT_EQ(Call->getCalledOperand(), Bar1F);
+
+ // Check setCalledFunction().
+ Ctx.save();
+ Call->setCalledFunction(Bar2F);
+ EXPECT_EQ(Call->getCalledFunction(), Bar2F);
+ Ctx.revert();
+ EXPECT_EQ(Call->getCalledFunction(), Bar1F);
+}
diff --git a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
index 527fbe5cf628..890706bf1bb2 100644
--- a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
+++ b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
@@ -906,6 +906,43 @@ struct VectorReductionToFPDotProd final
}
};
+struct VectorStepOpConvert final : OpConversionPattern<vector::StepOp> {
+ using OpConversionPattern::OpConversionPattern;
+
+ LogicalResult
+ matchAndRewrite(vector::StepOp stepOp, OpAdaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
+ Type dstType = typeConverter.convertType(stepOp.getType());
+ if (!dstType)
+ return failure();
+
+ Location loc = stepOp.getLoc();
+ int64_t numElements = stepOp.getType().getNumElements();
+ auto intType =
+ rewriter.getIntegerType(typeConverter.getIndexTypeBitwidth());
+
+ // Input vectors of size 1 are converted to scalars by the type converter.
+ // We just create a constant in this case.
+ if (numElements == 1) {
+ Value zero = spirv::ConstantOp::getZero(intType, loc, rewriter);
+ rewriter.replaceOp(stepOp, zero);
+ return success();
+ }
+
+ SmallVector<Value> source;
+ source.reserve(numElements);
+ for (int64_t i = 0; i < numElements; ++i) {
+ Attribute intAttr = rewriter.getIntegerAttr(intType, i);
+ Value constOp = rewriter.create<spirv::ConstantOp>(loc, intType, intAttr);
+ source.push_back(constOp);
+ }
+ rewriter.replaceOpWithNewOp<spirv::CompositeConstructOp>(stepOp, dstType,
+ source);
+ return success();
+ }
+};
+
} // namespace
#define CL_INT_MAX_MIN_OPS \
spirv::CLUMaxOp, spirv::CLUMinOp, spirv::CLSMaxOp, spirv::CLSMinOp
@@ -929,8 +966,9 @@ void mlir::populateVectorToSPIRVPatterns(SPIRVTypeConverter &typeConverter,
VectorReductionFloatMinMax<GL_FLOAT_MAX_MIN_OPS>, VectorShapeCast,
VectorInsertStridedSliceOpConvert, VectorShuffleOpConvert,
VectorInterleaveOpConvert, VectorDeinterleaveOpConvert,
- VectorSplatPattern, VectorLoadOpConverter, VectorStoreOpConverter>(
- typeConverter, patterns.getContext(), PatternBenefit(1));
+ VectorSplatPattern, VectorLoadOpConverter, VectorStoreOpConverter,
+ VectorStepOpConvert>(typeConverter, patterns.getContext(),
+ PatternBenefit(1));
// Make sure that the more specialized dot product pattern has higher benefit
// than the generic one that extracts all elements.
diff --git a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
index edad20874993..dd0ed77470a2 100644
--- a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
+++ b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
@@ -794,6 +794,32 @@ func.func @shape_cast_size1_vector(%arg0 : vector<f32>) -> vector<1xf32> {
// -----
+// CHECK-LABEL: @step()
+// CHECK: %[[CST0:.*]] = spirv.Constant 0 : i32
+// CHECK: %[[CST1:.*]] = spirv.Constant 1 : i32
+// CHECK: %[[CST2:.*]] = spirv.Constant 2 : i32
+// CHECK: %[[CST3:.*]] = spirv.Constant 3 : i32
+// CHECK: %[[CONSTRUCT:.*]] = spirv.CompositeConstruct %[[CST0]], %[[CST1]], %[[CST2]], %[[CST3]] : (i32, i32, i32, i32) -> vector<4xi32>
+// CHECK: %[[CAST:.*]] = builtin.unrealized_conversion_cast %[[CONSTRUCT]] : vector<4xi32> to vector<4xindex>
+// CHECK: return %[[CAST]] : vector<4xindex>
+func.func @step() -> vector<4xindex> {
+ %0 = vector.step : vector<4xindex>
+ return %0 : vector<4xindex>
+}
+
+// -----
+
+// CHECK-LABEL: @step_size1()
+// CHECK: %[[CST0:.*]] = spirv.Constant 0 : i32
+// CHECK: %[[CAST:.*]] = builtin.unrealized_conversion_cast %[[CST0]] : i32 to vector<1xindex>
+// CHECK: return %[[CAST]] : vector<1xindex>
+func.func @step_size1() -> vector<1xindex> {
+ %0 = vector.step : vector<1xindex>
+ return %0 : vector<1xindex>
+}
+
+// -----
+
module attributes {
spirv.target_env = #spirv.target_env<
#spirv.vce<v1.0, [Shader], [SPV_KHR_storage_buffer_storage_class]>, #spirv.resource_limits<>>
diff --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp
index d594823410f5..0b9a1a916e1c 100644
--- a/polly/lib/Analysis/ScopBuilder.cpp
+++ b/polly/lib/Analysis/ScopBuilder.cpp
@@ -2770,7 +2770,7 @@ isl::set ScopBuilder::getNonHoistableCtx(MemoryAccess *Access,
auto &DL = scop->getFunction().getDataLayout();
if (isSafeToLoadUnconditionally(LI->getPointerOperand(), LI->getType(),
- LI->getAlign(), DL)) {
+ LI->getAlign(), DL, nullptr)) {
SafeToLoad = isl::set::universe(AccessRelation.get_space().range());
} else if (BB != LI->getParent()) {
// Skip accesses in non-affine subregions as they might not be executed
diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp
index eab7bd83e6a4..79db3965de02 100644
--- a/polly/lib/Analysis/ScopDetection.cpp
+++ b/polly/lib/Analysis/ScopDetection.cpp
@@ -490,7 +490,8 @@ bool ScopDetection::onlyValidRequiredInvariantLoads(
for (auto NonAffineRegion : Context.NonAffineSubRegionSet) {
if (isSafeToLoadUnconditionally(Load->getPointerOperand(),
- Load->getType(), Load->getAlign(), DL))
+ Load->getType(), Load->getAlign(), DL,
+ nullptr))
continue;
if (NonAffineRegion->contains(Load) &&