[libcxx-commits] [libcxx] [libc++] Add a utility for checking the output of commands (PR #65917)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 20 10:20:50 PST 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/65917

>From 7fa8cf5bc5f6a90ff05859a887cf5fecd31a164a Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 6 Sep 2023 08:31:36 -0700
Subject: [PATCH] [libc++] Add a utility for checking the output of commands

---
 libcxx/test/CMakeLists.txt                    |   1 +
 libcxx/test/configs/cmake-bridge.cfg.in       |   1 +
 .../copy_move_codegen.sh.cpp                  |  21 +++
 .../clang_tidy/proper_version_checks.sh.cpp   |  29 ++++
 .../utility.intcmp/cmp_equal.codegen.sh.cpp   |  78 +++++++++++
 .../utility.intcmp/cmp_greater.codegen.sh.cpp |  78 +++++++++++
 .../cmp_greater_equal.codegen.sh.cpp          |  78 +++++++++++
 .../utility.intcmp/cmp_less.codegen.sh.cpp    |  78 +++++++++++
 .../cmp_less_equal.codegen.sh.cpp             |  78 +++++++++++
 .../cmp_not_equal.codegen.sh.cpp              |  78 +++++++++++
 .../utility.unreachable.codegen.sh.cpp        |  22 +++
 libcxx/test/tools/CMakeLists.txt              |   6 +-
 libcxx/test/tools/check_output/CMakeLists.txt |  22 +++
 .../test/tools/check_output/check_output.cpp  | 131 ++++++++++++++++++
 .../proper_version_checks.cpp                 |   3 -
 15 files changed, 699 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_equal.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater_equal.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less_equal.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_not_equal.codegen.sh.cpp
 create mode 100644 libcxx/test/libcxx/utilities/utility/utility.unreachable.codegen.sh.cpp
 create mode 100644 libcxx/test/tools/check_output/CMakeLists.txt
 create mode 100644 libcxx/test/tools/check_output/check_output.cpp

diff --git a/libcxx/test/CMakeLists.txt b/libcxx/test/CMakeLists.txt
index f4e577aed57de3..5ab843e8c1319b 100644
--- a/libcxx/test/CMakeLists.txt
+++ b/libcxx/test/CMakeLists.txt
@@ -42,6 +42,7 @@ add_custom_target(install-cxx-test-suite-prefix
                               cxx
                               cxx_experimental
                               cxx-modules
+                              check_output
                       COMMAND ${CMAKE_COMMAND} -E make_directory "${LIBCXX_TESTING_INSTALL_PREFIX}"
                       COMMAND "${CMAKE_COMMAND}"
                               -DCMAKE_INSTALL_COMPONENT=cxx-headers
diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in
index 61f821a7e4f6b8..31ebcfe9821531 100644
--- a/libcxx/test/configs/cmake-bridge.cfg.in
+++ b/libcxx/test/configs/cmake-bridge.cfg.in
@@ -31,3 +31,4 @@ config.substitutions.append(('%{lib-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIB
 config.substitutions.append(('%{module-dir}', '@LIBCXX_TESTING_INSTALL_PREFIX@/@LIBCXX_INSTALL_MODULES_DIR@'))
 config.substitutions.append(('%{test-tools-dir}', '@LIBCXX_TEST_TOOLS_PATH@'))
 config.substitutions.append(('%{benchmark_flags}', '-I @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/include -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib64 -l benchmark'))
+config.substitutions.append(('%{check-output}', os.path.join('@CMAKE_BINARY_DIR@', 'bin/check_output') + " %s"))
diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp
new file mode 100644
index 00000000000000..86168b7f86752c
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_codegen.sh.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <algorithm>
+
+int* test1(int* first, int* last, int* out) {
+  // CHECK:      define dso_local void
+  // CHECK-SAME: test
+  // CHECK:      tail call void @llvm.memmove
+  return std::copy(first, last, out);
+}
diff --git a/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp
new file mode 100644
index 00000000000000..cc3c90f4f0ea61
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/clang_tidy/proper_version_checks.sh.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-clang-tidy
+
+// RUN: %{clang-tidy} %s -header-filter=.* --checks='-*,libcpp-cpp-version-check' --load=%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin -- %{compile_flags} -fno-modules 2>&1 | %{check-output}
+
+#include <__config>
+
+// CHECK: warning: _LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version
+#if _LIBCPP_STD_VER > 14
+#endif
+
+// CHECK: warning: Use _LIBCPP_STD_VER instead of __cplusplus to constrain based on the C++ version
+#if __cplusplus >= 201103L
+#endif
+
+// CHECK: warning: _LIBCPP_STD_VER >= 11 is always true. Did you mean '#ifndef _LIBCPP_CXX03_LANG'?
+#if _LIBCPP_STD_VER >= 11
+#endif
+
+// CHECK: warning: Not a valid value for _LIBCPP_STD_VER. Use 14, 17, 20, 23, or 26
+#if _LIBCPP_STD_VER >= 12
+#endif
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_equal.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_equal.codegen.sh.cpp
new file mode 100644
index 00000000000000..e391b8b4df2558
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_equal.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_equal_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_i16_i16
+  // CHECK-NEXT: %3 = icmp eq i16 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
+
+bool cmp_equal_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_i32_i32
+  // CHECK-NEXT: %3 = icmp eq i32 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
+
+bool cmp_equal_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_u32_i32
+  // CHECK-NEXT: %3 = icmp sgt i32 %1, -1
+  // CHECK-NEXT: %4 = icmp eq i32 %0, %1
+  // CHECK-NEXT: %5 = and i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
+
+bool cmp_equal_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_i32_u64
+  // CHECK-NEXT: %3 = icmp sgt i32 %0, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp eq i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
+
+bool cmp_equal_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_u32_i64
+  // CHECK-NEXT: %3 = icmp sgt i64 %1, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp eq i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
+
+bool cmp_equal_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_equal_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp eq i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_equal(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater.codegen.sh.cpp
new file mode 100644
index 00000000000000..a8eb5b9d69e354
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_greater_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_i16_i16
+  // CHECK-NEXT: %3 = icmp slt i16 %1, %0
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
+
+bool cmp_greater_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_i32_i32
+  // CHECK-NEXT: %3 = icmp slt i32 %1, %0
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
+
+bool cmp_greater_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_u32_i32
+  // CHECK-NEXT: %3 = icmp slt i32 %1, 0
+  // CHECK-NEXT: %4 = icmp ult i32 %1, %0
+  // CHECK-NEXT: %5 = or i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
+
+bool cmp_greater_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_i32_u64
+  // CHECK-NEXT: %3 = icmp sgt i32 %0, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ugt i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
+
+bool cmp_greater_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_u32_i64
+  // CHECK-NEXT: %3 = icmp slt i64 %1, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ugt i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
+
+bool cmp_greater_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp ugt i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_greater(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater_equal.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater_equal.codegen.sh.cpp
new file mode 100644
index 00000000000000..d6b580c4908c75
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_greater_equal.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_greater_equal_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_i16_i16
+  // CHECK-NEXT: %3 = icmp sge i16 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
+
+bool cmp_greater_equal_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_i32_i32
+  // CHECK-NEXT: %3 = icmp sge i32 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
+
+bool cmp_greater_equal_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_u32_i32
+  // CHECK-NEXT: %3 = icmp slt i32 %1, 0
+  // CHECK-NEXT: %4 = icmp uge i32 %0, %1
+  // CHECK-NEXT: %5 = or i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
+
+bool cmp_greater_equal_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_i32_u64
+  // CHECK-NEXT: %3 = icmp sgt i32 %0, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp uge i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
+
+bool cmp_greater_equal_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_u32_i64
+  // CHECK-NEXT: %3 = icmp slt i64 %1, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp uge i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
+
+bool cmp_greater_equal_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_greater_equal_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp uge i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_greater_equal(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less.codegen.sh.cpp
new file mode 100644
index 00000000000000..fc4834aa109593
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_less_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_i16_i16
+  // CHECK-NEXT: %3 = icmp slt i16 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
+
+bool cmp_less_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_i32_i32
+  // CHECK-NEXT: %3 = icmp slt i32 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
+
+bool cmp_less_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_u32_i32
+  // CHECK-NEXT: %3 = icmp sgt i32 %1, -1
+  // CHECK-NEXT: %4 = icmp ult i32 %0, %1
+  // CHECK-NEXT: %5 = and i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
+
+bool cmp_less_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_i32_u64
+  // CHECK-NEXT: %3 = icmp slt i32 %0, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ult i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
+
+bool cmp_less_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_u32_i64
+  // CHECK-NEXT: %3 = icmp sgt i64 %1, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ult i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
+
+bool cmp_less_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp ult i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_less(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less_equal.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less_equal.codegen.sh.cpp
new file mode 100644
index 00000000000000..bc4ca08023b5ef
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_less_equal.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_less_equal_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_i16_i16
+  // CHECK-NEXT: %3 = icmp sge i16 %1, %0
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
+
+bool cmp_less_equal_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_i32_i32
+  // CHECK-NEXT: %3 = icmp sge i32 %1, %0
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
+
+bool cmp_less_equal_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_u32_i32
+  // CHECK-NEXT: %3 = icmp sgt i32 %1, -1
+  // CHECK-NEXT: %4 = icmp uge i32 %1, %0
+  // CHECK-NEXT: %5 = and i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
+
+bool cmp_less_equal_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_i32_u64
+  // CHECK-NEXT: %3 = icmp slt i32 %0, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ule i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
+
+bool cmp_less_equal_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_u32_i64
+  // CHECK-NEXT: %3 = icmp sgt i64 %1, -1
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ule i64 %4, %1
+  // CHECK-NEXT: %6 = and i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
+
+bool cmp_less_equal_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_less_equal_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp ule i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_less_equal(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_not_equal.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_not_equal.codegen.sh.cpp
new file mode 100644
index 00000000000000..3a061a65fd9b75
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.intcmp/cmp_not_equal.codegen.sh.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <cstdint>
+#include <utility>
+
+bool cmp_not_equal_i16_i16(int16_t lhs, int16_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_i16_i16
+  // CHECK-NEXT: %3 = icmp ne i16 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
+
+bool cmp_not_equal_i32_i32(int32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_i32_i32
+  // CHECK-NEXT: %3 = icmp ne i32 %0, %1
+  // CHECK-NEXT: ret i1 %3
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
+
+bool cmp_not_equal_u32_i32(uint32_t lhs, int32_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_u32_i32
+  // CHECK-NEXT: %3 = icmp slt i32 %1, 0
+  // CHECK-NEXT: %4 = icmp ne i32 %0, %1
+  // CHECK-NEXT: %5 = or i1 %3, %4
+  // CHECK-NEXT: ret i1 %5
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
+
+bool cmp_not_equal_i32_u64(int32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_i32_u64
+  // CHECK-NEXT: %3 = icmp slt i32 %0, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ne i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
+
+bool cmp_not_equal_u32_i64(uint32_t lhs, int64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_u32_i64
+  // CHECK-NEXT: %3 = icmp slt i64 %1, 0
+  // CHECK-NEXT: %4 = zext i32 %0 to i64
+  // CHECK-NEXT: %5 = icmp ne i64 %4, %1
+  // CHECK-NEXT: %6 = or i1 %3, %5
+  // CHECK-NEXT: ret i1 %6
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
+
+bool cmp_not_equal_u32_u64(uint32_t lhs, uint64_t rhs) {
+  // CHECK:      define dso_local noundef zeroext
+  // CHECK-SAME: cmp_not_equal_u32_u64
+  // CHECK-NEXT: %3 = zext i32 %0 to i64
+  // CHECK-NEXT: %4 = icmp ne i64 %3, %1
+  // CHECK-NEXT: ret i1 %4
+  // CHECK-NEXT: }
+  return std::cmp_not_equal(lhs, rhs);
+}
diff --git a/libcxx/test/libcxx/utilities/utility/utility.unreachable.codegen.sh.cpp b/libcxx/test/libcxx/utilities/utility/utility.unreachable.codegen.sh.cpp
new file mode 100644
index 00000000000000..c3a367763997f6
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/utility.unreachable.codegen.sh.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test is checking the LLVM IR
+// REQUIRES: clang
+
+// RUN: %{cxx} %s %{compile_flags} -O3 -c -S -emit-llvm -o - | %{check-output}
+
+#include <utility>
+
+[[noreturn]] void test() {
+  // CHECK:      define dso_local void
+  // CHECK-SAME: test
+  // CHECK-NEXT: unreachable
+  // CHECK-NEXT: }
+  std::unreachable();
+}
diff --git a/libcxx/test/tools/CMakeLists.txt b/libcxx/test/tools/CMakeLists.txt
index 6d99c53ad46d9f..d1d7442e99d004 100644
--- a/libcxx/test/tools/CMakeLists.txt
+++ b/libcxx/test/tools/CMakeLists.txt
@@ -3,6 +3,8 @@ set(LIBCXX_TEST_TOOLS_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
 
 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
   message(STATUS "Clang-tidy tests are disabled due to non-clang based compiler.")
-  return()
+else()
+  add_subdirectory(clang_tidy_checks)
 endif()
-add_subdirectory(clang_tidy_checks)
+
+add_subdirectory(check_output)
diff --git a/libcxx/test/tools/check_output/CMakeLists.txt b/libcxx/test/tools/check_output/CMakeLists.txt
new file mode 100644
index 00000000000000..e1fe1a018e00e7
--- /dev/null
+++ b/libcxx/test/tools/check_output/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+add_executable(check_output check_output.cpp)
+
+# Link against libc++
+if (TARGET cxx_shared)
+  target_link_libraries(check_output PRIVATE cxx_shared)
+elseif (TARGET cxx_static)
+  target_link_libraries(check_output PRIVATE cxx_static)
+else()
+  message(FATAL "Neither cxx_shared nor cxx_static are available to be linked against")
+endif()
+
+# put the binary into <build>/bin
+set_target_properties(check_output PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+
+# set the language mode
+set_target_properties(check_output PROPERTIES
+                      CXX_STANDARD 23
+                      CXX_STANDARD_REQUIRED YES
+                      CXX_EXTENSIONS NO)
+
+target_compile_options(check_output PRIVATE -Werror=missing-prototypes)
diff --git a/libcxx/test/tools/check_output/check_output.cpp b/libcxx/test/tools/check_output/check_output.cpp
new file mode 100644
index 00000000000000..36c6944c2d33e9
--- /dev/null
+++ b/libcxx/test/tools/check_output/check_output.cpp
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <iterator>
+#include <print>
+#include <ranges>
+#include <string>
+
+using namespace std::string_view_literals;
+
+enum class Result {
+  success,
+  mismatch,
+  no_match_found,
+  unknown_matcher,
+  invalid_use,
+};
+
+namespace co {
+namespace {
+[[noreturn]] void exit(Result result) { std::exit(static_cast<int>(result)); }
+
+[[noreturn]] void print_failure(int line, std::string_view stdin_content, std::string_view matcher) {
+  std::print("Failed to match: `{}`\nRemaining data:\n{}", matcher, stdin_content);
+  co::exit(Result::mismatch);
+}
+
+bool is_newline(char c) { return c == '\n'; }
+
+bool isblank(char c) { return std::isblank(c); }
+
+bool consume_front(std::string_view& sv, std::string_view start) {
+  if (!sv.starts_with(start))
+    return false;
+  sv.remove_prefix(start.size());
+  return true;
+}
+} // namespace
+} // namespace co
+
+int main(int argc, char** argv) {
+  if (argc != 2) {
+    std::print(stderr, "check_output has to be used as `<command> | ./check_output %s`\n");
+    co::exit(Result::invalid_use);
+  }
+
+  std::string file_content_data = [&] {
+    std::ifstream file(argv[1]);
+    if (!file) {
+      std::print(stderr, "Failed to open file: {}\n", argv[1]);
+      co::exit(Result::invalid_use);
+    }
+    return std::string{std::istreambuf_iterator<char>{file}, {}};
+  }();
+  std::string_view file_content = file_content_data; // Don't copy the data around all the time
+
+  std::string stdin_content_data = [&] {
+    std::cin >> std::noskipws;
+    return std::string{std::istream_iterator<char>{std::cin}, {}};
+  }();
+  std::string_view stdin_content = stdin_content_data; // Don't copy the data around all the time
+
+  size_t match_count = 0;
+  auto drop_blanks   = std::views::drop_while(co::isblank);
+
+  while (!file_content.empty()) {
+    auto marker = std::ranges::search(file_content, "// CHECK"sv);
+    if (marker.empty()) {
+      if (match_count == 0) {
+        std::print(stderr, "No matcher found!\n");
+        co::exit(Result::no_match_found);
+      }
+      co::exit(Result::success);
+    }
+    file_content.remove_prefix(marker.end() - file_content.begin());
+
+    const auto get_match = [&]() {
+      return std::string_view(file_content.begin(), std::ranges::find(file_content, '\n'));
+    };
+
+    if (co::consume_front(file_content, ":")) {
+      auto match = get_match();
+      auto found = std::ranges::search(
+          stdin_content | std::views::drop_while(std::not_fn(co::is_newline)) | std::views::drop(1),
+          match | drop_blanks);
+      if (found.empty()) {
+        co::print_failure(1, stdin_content, match);
+      }
+      ++match_count;
+      stdin_content.remove_prefix(found.end() - stdin_content.begin());
+    } else if (co::consume_front(file_content, "-SAME:")) {
+      auto match    = get_match();
+      auto haystack = std::string_view(stdin_content.begin(), std::ranges::find(stdin_content, '\n'));
+      auto found    = std::ranges::search(haystack, match | drop_blanks);
+      if (found.empty()) {
+        co::print_failure(1, stdin_content, match);
+      }
+      stdin_content.remove_prefix(found.end() - stdin_content.begin());
+    } else if (co::consume_front(file_content, "-NEXT:")) {
+      auto match    = get_match();
+      auto haystack = [&] {
+        auto begin = std::ranges::find(stdin_content, '\n');
+        if (begin == stdin_content.end()) {
+          co::print_failure(1, stdin_content, match);
+        }
+        ++begin;
+        return std::string_view(begin, std::ranges::find(begin, stdin_content.end(), '\n'));
+      }();
+      auto found = std::ranges::search(haystack, match | drop_blanks);
+      if (found.empty())
+        co::print_failure(1, stdin_content, match);
+      stdin_content.remove_prefix(found.end() - stdin_content.begin());
+    } else {
+      std::print(stderr,
+                 "Unkown matcher type {} found",
+                 std::string_view(file_content.begin(), std::ranges::find(file_content, ':')));
+      co::exit(Result::unknown_matcher);
+    }
+  }
+
+  co::exit(Result::success);
+}
diff --git a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
index 15093a4357bb7d..1c4de838f21876 100644
--- a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
+++ b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
@@ -36,9 +36,6 @@ class proper_version_checks_callbacks : public clang::PPCallbacks {
         clang::CharSourceRange::getTokenRange(condition_range),
         preprocessor_.getSourceManager(),
         preprocessor_.getLangOpts());
-    if (preprocessor_.getSourceManager().isInMainFile(location))
-      return;
-
     if (condition.starts_with("_LIBCPP_STD_VER") && condition.find(">") != std::string_view::npos &&
         condition.find(">=") == std::string_view::npos)
       check_.diag(location, "_LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version");



More information about the libcxx-commits mailing list