[llvm] [SLP] Use static_assert() rather than assert() where possible (PR #180867)
Ryan Buchner via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 11 13:46:13 PST 2026
https://github.com/bababuck updated https://github.com/llvm/llvm-project/pull/180867
>From fa7428d187b07f7c0c64e3f9a3a578fbccd655e0 Mon Sep 17 00:00:00 2001
From: bababuck <rbuchner at qti.qualcomm.com>
Date: Tue, 3 Feb 2026 16:56:54 -0800
Subject: [PATCH 1/7] [SLP] Use static_assert() rather than assert() where
possible
Tests for is_sorted_constexpr were generated by AI.
---
llvm/include/llvm/ADT/STLExtras.h | 16 ++++++++++
.../Transforms/Vectorize/SLPVectorizer.cpp | 7 +++--
llvm/unittests/ADT/STLExtrasTest.cpp | 29 +++++++++++++++++++
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 23da931a63de1..62e1ee94758a7 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1975,6 +1975,22 @@ template <typename R> bool is_sorted(R &&Range) {
return std::is_sorted(adl_begin(Range), adl_end(Range));
}
+/// Check if elements in a range \p R are sorted with respect to a comparator \p
+/// C. constexpr allows use in static_assert
+/// TODO: Use std::is_sorted once upgraded to Cpp20
+template <typename It, typename Cmp = std::less<>>
+constexpr bool is_sorted_constexpr(It First, It Last, Cmp C = Cmp{}) {
+ if (First == Last)
+ return true;
+ It Prev = First;
+ for (It I = std::next(First); I != Last; ++I) {
+ if (C(*I, *Prev))
+ return false;
+ Prev = I;
+ }
+ return true;
+}
+
/// Provide wrappers to std::includes which take ranges instead of having to
/// pass begin/end explicitly.
/// This function checks if the sorted range \p R2 is a subsequence of the
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 1f92cc15135b4..1560503fcbf22 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -954,6 +954,9 @@ class BinOpSameOpcodeHelper {
constexpr static std::initializer_list<unsigned> SupportedOp = {
Instruction::Add, Instruction::Sub, Instruction::Mul, Instruction::Shl,
Instruction::AShr, Instruction::And, Instruction::Or, Instruction::Xor};
+ static_assert(llvm::is_sorted_constexpr(SupportedOp.begin(),
+ SupportedOp.end()) &&
+ "SupportedOp is not sorted.");
enum : MaskType {
ShlBIT = 0b1,
AShrBIT = 0b10,
@@ -1157,9 +1160,7 @@ class BinOpSameOpcodeHelper {
public:
BinOpSameOpcodeHelper(const Instruction *MainOp,
const Instruction *AltOp = nullptr)
- : MainOp(MainOp), AltOp(AltOp) {
- assert(is_sorted(SupportedOp) && "SupportedOp is not sorted.");
- }
+ : MainOp(MainOp), AltOp(AltOp) {}
bool add(const Instruction *I) {
assert(isa<BinaryOperator>(I) &&
"BinOpSameOpcodeHelper only accepts BinaryOperator.");
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index fe71945e4a794..1312f31057491 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1937,4 +1937,33 @@ TEST(STLExtrasTest, AdjacentFind) {
EXPECT_EQ(*std::next(It13), 3);
}
+// Compile-time tests for llvm::is_sorted_constexpr
+static constexpr std::array<int, 0> CEmpty{};
+static_assert(is_sorted_constexpr(CEmpty.begin(), CEmpty.end()),
+ "Empty range should be sorted");
+
+static constexpr std::array<int, 1> CSingle{{42}};
+static_assert(is_sorted_constexpr(CSingle.begin(), CSingle.end()),
+ "Single element range should be sorted");
+static_assert(is_sorted_constexpr(CSingle.begin(), CSingle.end(),
+ std::greater<>()),
+ "Single element range should be sorted with std::greater");
+
+static constexpr std::array<int, 5> CSorted{{1, 2, 2, 3, 5}};
+static_assert(is_sorted_constexpr(CSorted.begin(), CSorted.end()),
+ "Non-descending order with duplicates should be sorted");
+static_assert(is_sorted_constexpr(CSorted.begin(), CSorted.end(),
+ std::less<>()),
+ "Explicit std::less non-descending order should be sorted");
+static_assert(!is_sorted_constexpr(CSorted.begin(), CSorted.end(),
+ std::greater<>()),
+ "Non-descending order should not be sorted by std::greater");
+
+static constexpr std::array<int, 5> CUnsorted{{1, 3, 2, 4, 5}};
+static_assert(!is_sorted_constexpr(CUnsorted.begin(), CUnsorted.end()),
+ "Unsorted range should not be sorted");
+
+static constexpr std::array<int, 5> CDesc{{9, 7, 7, 3, 0}};
+static_assert(is_sorted_constexpr(CDesc.begin(), CDesc.end(), std::greater<>()),
+ "Non-ascending order with std::greater should be sorted");
} // namespace
>From 5d4dfa7b51fc413004d9270b9acc4be6aa527de7 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 08:45:39 -0800
Subject: [PATCH 2/7] [SLP] Revert SLP, this is now an ADT only MR
---
llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 1560503fcbf22..1f92cc15135b4 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -954,9 +954,6 @@ class BinOpSameOpcodeHelper {
constexpr static std::initializer_list<unsigned> SupportedOp = {
Instruction::Add, Instruction::Sub, Instruction::Mul, Instruction::Shl,
Instruction::AShr, Instruction::And, Instruction::Or, Instruction::Xor};
- static_assert(llvm::is_sorted_constexpr(SupportedOp.begin(),
- SupportedOp.end()) &&
- "SupportedOp is not sorted.");
enum : MaskType {
ShlBIT = 0b1,
AShrBIT = 0b10,
@@ -1160,7 +1157,9 @@ class BinOpSameOpcodeHelper {
public:
BinOpSameOpcodeHelper(const Instruction *MainOp,
const Instruction *AltOp = nullptr)
- : MainOp(MainOp), AltOp(AltOp) {}
+ : MainOp(MainOp), AltOp(AltOp) {
+ assert(is_sorted(SupportedOp) && "SupportedOp is not sorted.");
+ }
bool add(const Instruction *I) {
assert(isa<BinaryOperator>(I) &&
"BinOpSameOpcodeHelper only accepts BinaryOperator.");
>From a34793e21aaba0986f7888d4ca9c38cab444b3eb Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 08:50:40 -0800
Subject: [PATCH 3/7] [ADT] Move is_sorted_constexpr() to STLForwardCompat.h
---
llvm/include/llvm/ADT/STLExtras.h | 16 ----------------
llvm/include/llvm/ADT/STLForwardCompat.h | 17 +++++++++++++++++
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 62e1ee94758a7..23da931a63de1 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1975,22 +1975,6 @@ template <typename R> bool is_sorted(R &&Range) {
return std::is_sorted(adl_begin(Range), adl_end(Range));
}
-/// Check if elements in a range \p R are sorted with respect to a comparator \p
-/// C. constexpr allows use in static_assert
-/// TODO: Use std::is_sorted once upgraded to Cpp20
-template <typename It, typename Cmp = std::less<>>
-constexpr bool is_sorted_constexpr(It First, It Last, Cmp C = Cmp{}) {
- if (First == Last)
- return true;
- It Prev = First;
- for (It I = std::next(First); I != Last; ++I) {
- if (C(*I, *Prev))
- return false;
- Prev = I;
- }
- return true;
-}
-
/// Provide wrappers to std::includes which take ranges instead of having to
/// pass begin/end explicitly.
/// This function checks if the sorted range \p R2 is a subsequence of the
diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h
index d61c880747502..6a60f3beaf181 100644
--- a/llvm/include/llvm/ADT/STLForwardCompat.h
+++ b/llvm/include/llvm/ADT/STLForwardCompat.h
@@ -18,6 +18,7 @@
#define LLVM_ADT_STLFORWARDCOMPAT_H
#include "llvm/Support/Compiler.h"
+#include <functional>
#include <optional>
#include <tuple>
#include <type_traits>
@@ -158,6 +159,22 @@ invoke(FnT &&Fn, ArgsT &&...Args) { // NOLINT(readability-identifier-naming)
std::forward_as_tuple(std::forward<ArgsT>(Args)...));
}
+/// Check if elements in a range \p R are sorted with respect to a comparator \p
+/// C. constexpr allows use in static_assert
+/// TODO: Use std::is_sorted once upgraded to C++20 since that becomes constexpr
+template <typename It, typename Cmp = std::less<>>
+constexpr bool is_sorted_constexpr(It First, It Last, Cmp C = Cmp{}) {
+ if (First == Last)
+ return true;
+ It Prev = First;
+ for (It I = std::next(First); I != Last; ++I) {
+ if (C(*I, *Prev))
+ return false;
+ Prev = I;
+ }
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Features from C++23
//===----------------------------------------------------------------------===//
>From 82d1a53aec92ebda5041a59da16b54fa0b4c96ae Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 10:03:29 -0800
Subject: [PATCH 4/7] [ADT] Update is_sorted_constexpr() to operate on a Range
---
llvm/include/llvm/ADT/STLForwardCompat.h | 10 ++++++----
llvm/unittests/ADT/STLExtrasTest.cpp | 20 ++++++++------------
2 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h
index 6a60f3beaf181..9afffbcb8c848 100644
--- a/llvm/include/llvm/ADT/STLForwardCompat.h
+++ b/llvm/include/llvm/ADT/STLForwardCompat.h
@@ -162,12 +162,14 @@ invoke(FnT &&Fn, ArgsT &&...Args) { // NOLINT(readability-identifier-naming)
/// Check if elements in a range \p R are sorted with respect to a comparator \p
/// C. constexpr allows use in static_assert
/// TODO: Use std::is_sorted once upgraded to C++20 since that becomes constexpr
-template <typename It, typename Cmp = std::less<>>
-constexpr bool is_sorted_constexpr(It First, It Last, Cmp C = Cmp{}) {
+template <typename R, typename Cmp = std::less<>>
+constexpr bool is_sorted_constexpr(R &&Range, Cmp C = Cmp{}) {
+ auto First = adl_begin(Range);
+ auto Last = adl_end(Range);
if (First == Last)
return true;
- It Prev = First;
- for (It I = std::next(First); I != Last; ++I) {
+ auto Prev = First;
+ for (auto I = std::next(First); I != Last; ++I) {
if (C(*I, *Prev))
return false;
Prev = I;
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 1312f31057491..a52d13ca4f983 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1939,31 +1939,27 @@ TEST(STLExtrasTest, AdjacentFind) {
// Compile-time tests for llvm::is_sorted_constexpr
static constexpr std::array<int, 0> CEmpty{};
-static_assert(is_sorted_constexpr(CEmpty.begin(), CEmpty.end()),
- "Empty range should be sorted");
+static_assert(is_sorted_constexpr(CEmpty), "Empty range should be sorted");
static constexpr std::array<int, 1> CSingle{{42}};
-static_assert(is_sorted_constexpr(CSingle.begin(), CSingle.end()),
+static_assert(is_sorted_constexpr(CSingle),
"Single element range should be sorted");
-static_assert(is_sorted_constexpr(CSingle.begin(), CSingle.end(),
- std::greater<>()),
+static_assert(is_sorted_constexpr(CSingle, std::greater<>()),
"Single element range should be sorted with std::greater");
static constexpr std::array<int, 5> CSorted{{1, 2, 2, 3, 5}};
-static_assert(is_sorted_constexpr(CSorted.begin(), CSorted.end()),
+static_assert(is_sorted_constexpr(CSorted),
"Non-descending order with duplicates should be sorted");
-static_assert(is_sorted_constexpr(CSorted.begin(), CSorted.end(),
- std::less<>()),
+static_assert(is_sorted_constexpr(CSorted, std::less<>()),
"Explicit std::less non-descending order should be sorted");
-static_assert(!is_sorted_constexpr(CSorted.begin(), CSorted.end(),
- std::greater<>()),
+static_assert(!is_sorted_constexpr(CSorted, std::greater<>()),
"Non-descending order should not be sorted by std::greater");
static constexpr std::array<int, 5> CUnsorted{{1, 3, 2, 4, 5}};
-static_assert(!is_sorted_constexpr(CUnsorted.begin(), CUnsorted.end()),
+static_assert(!is_sorted_constexpr(CUnsorted),
"Unsorted range should not be sorted");
static constexpr std::array<int, 5> CDesc{{9, 7, 7, 3, 0}};
-static_assert(is_sorted_constexpr(CDesc.begin(), CDesc.end(), std::greater<>()),
+static_assert(is_sorted_constexpr(CDesc, std::greater<>()),
"Non-ascending order with std::greater should be sorted");
} // namespace
>From 6c70cf44d859511d1abd73a9cf10bea63ba3e0e6 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 11:39:37 -0800
Subject: [PATCH 5/7] [ADT] Use typespace identifier for is_sorted_constexpr()
in unittest
---
llvm/unittests/ADT/STLExtrasTest.cpp | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index a52d13ca4f983..a76336febd2a0 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1939,27 +1939,28 @@ TEST(STLExtrasTest, AdjacentFind) {
// Compile-time tests for llvm::is_sorted_constexpr
static constexpr std::array<int, 0> CEmpty{};
-static_assert(is_sorted_constexpr(CEmpty), "Empty range should be sorted");
+static_assert(llvm::is_sorted_constexpr(CEmpty),
+ "Empty range should be sorted");
static constexpr std::array<int, 1> CSingle{{42}};
-static_assert(is_sorted_constexpr(CSingle),
+static_assert(llvm::is_sorted_constexpr(CSingle),
"Single element range should be sorted");
-static_assert(is_sorted_constexpr(CSingle, std::greater<>()),
+static_assert(llvm::is_sorted_constexpr(CSingle, std::greater<>()),
"Single element range should be sorted with std::greater");
static constexpr std::array<int, 5> CSorted{{1, 2, 2, 3, 5}};
-static_assert(is_sorted_constexpr(CSorted),
+static_assert(llvm::is_sorted_constexpr(CSorted),
"Non-descending order with duplicates should be sorted");
-static_assert(is_sorted_constexpr(CSorted, std::less<>()),
+static_assert(llvm::is_sorted_constexpr(CSorted, std::less<>()),
"Explicit std::less non-descending order should be sorted");
-static_assert(!is_sorted_constexpr(CSorted, std::greater<>()),
+static_assert(!llvm::is_sorted_constexpr(CSorted, std::greater<>()),
"Non-descending order should not be sorted by std::greater");
static constexpr std::array<int, 5> CUnsorted{{1, 3, 2, 4, 5}};
-static_assert(!is_sorted_constexpr(CUnsorted),
+static_assert(!llvm::is_sorted_constexpr(CUnsorted),
"Unsorted range should not be sorted");
static constexpr std::array<int, 5> CDesc{{9, 7, 7, 3, 0}};
-static_assert(is_sorted_constexpr(CDesc, std::greater<>()),
+static_assert(llvm::is_sorted_constexpr(CDesc, std::greater<>()),
"Non-ascending order with std::greater should be sorted");
} // namespace
>From f4b65cb1464dada93dd18aa9abd461cdb34eef59 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 11:44:38 -0800
Subject: [PATCH 6/7] [ADT] Move tests to STLForwardCompatTest.cpp
---
llvm/unittests/ADT/STLExtrasTest.cpp | 26 --------------------
llvm/unittests/ADT/STLForwardCompatTest.cpp | 27 +++++++++++++++++++++
2 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index a76336febd2a0..fe71945e4a794 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1937,30 +1937,4 @@ TEST(STLExtrasTest, AdjacentFind) {
EXPECT_EQ(*std::next(It13), 3);
}
-// Compile-time tests for llvm::is_sorted_constexpr
-static constexpr std::array<int, 0> CEmpty{};
-static_assert(llvm::is_sorted_constexpr(CEmpty),
- "Empty range should be sorted");
-
-static constexpr std::array<int, 1> CSingle{{42}};
-static_assert(llvm::is_sorted_constexpr(CSingle),
- "Single element range should be sorted");
-static_assert(llvm::is_sorted_constexpr(CSingle, std::greater<>()),
- "Single element range should be sorted with std::greater");
-
-static constexpr std::array<int, 5> CSorted{{1, 2, 2, 3, 5}};
-static_assert(llvm::is_sorted_constexpr(CSorted),
- "Non-descending order with duplicates should be sorted");
-static_assert(llvm::is_sorted_constexpr(CSorted, std::less<>()),
- "Explicit std::less non-descending order should be sorted");
-static_assert(!llvm::is_sorted_constexpr(CSorted, std::greater<>()),
- "Non-descending order should not be sorted by std::greater");
-
-static constexpr std::array<int, 5> CUnsorted{{1, 3, 2, 4, 5}};
-static_assert(!llvm::is_sorted_constexpr(CUnsorted),
- "Unsorted range should not be sorted");
-
-static constexpr std::array<int, 5> CDesc{{9, 7, 7, 3, 0}};
-static_assert(llvm::is_sorted_constexpr(CDesc, std::greater<>()),
- "Non-ascending order with std::greater should be sorted");
} // namespace
diff --git a/llvm/unittests/ADT/STLForwardCompatTest.cpp b/llvm/unittests/ADT/STLForwardCompatTest.cpp
index 8831062109cb3..cbd1899083d1b 100644
--- a/llvm/unittests/ADT/STLForwardCompatTest.cpp
+++ b/llvm/unittests/ADT/STLForwardCompatTest.cpp
@@ -605,5 +605,32 @@ TEST(STLForwardCompatTest, BindFrontBindBack) {
EXPECT_TRUE(any_of(V, Spec1));
}
+// Compile-time tests for llvm::is_sorted_constexpr
+static constexpr std::array<int, 0> CEmpty{};
+static_assert(llvm::is_sorted_constexpr(CEmpty),
+ "Empty range should be sorted");
+
+static constexpr std::array<int, 1> CSingle{{42}};
+static_assert(llvm::is_sorted_constexpr(CSingle),
+ "Single element range should be sorted");
+static_assert(llvm::is_sorted_constexpr(CSingle, std::greater<>()),
+ "Single element range should be sorted with std::greater");
+
+static constexpr std::array<int, 5> CSorted{{1, 2, 2, 3, 5}};
+static_assert(llvm::is_sorted_constexpr(CSorted),
+ "Non-descending order with duplicates should be sorted");
+static_assert(llvm::is_sorted_constexpr(CSorted, std::less<>()),
+ "Explicit std::less non-descending order should be sorted");
+static_assert(!llvm::is_sorted_constexpr(CSorted, std::greater<>()),
+ "Non-descending order should not be sorted by std::greater");
+
+static constexpr std::array<int, 5> CUnsorted{{1, 3, 2, 4, 5}};
+static_assert(!llvm::is_sorted_constexpr(CUnsorted),
+ "Unsorted range should not be sorted");
+
+static constexpr std::array<int, 5> CDesc{{9, 7, 7, 3, 0}};
+static_assert(llvm::is_sorted_constexpr(CDesc, std::greater<>()),
+ "Non-ascending order with std::greater should be sorted");
+
} // namespace
} // namespace llvm
>From 6c8039ce7b1f8831a8132e60b24c4e4fed4e9821 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 11 Feb 2026 13:18:48 -0800
Subject: [PATCH 7/7] [ADT] Use std::begin/std::end rather than adt_begin and
adt_end
This addition is for forward compatibility, not for ADT compatibility.
---
llvm/include/llvm/ADT/STLForwardCompat.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h
index 9afffbcb8c848..d08e7dbfa4aaf 100644
--- a/llvm/include/llvm/ADT/STLForwardCompat.h
+++ b/llvm/include/llvm/ADT/STLForwardCompat.h
@@ -164,8 +164,8 @@ invoke(FnT &&Fn, ArgsT &&...Args) { // NOLINT(readability-identifier-naming)
/// TODO: Use std::is_sorted once upgraded to C++20 since that becomes constexpr
template <typename R, typename Cmp = std::less<>>
constexpr bool is_sorted_constexpr(R &&Range, Cmp C = Cmp{}) {
- auto First = adl_begin(Range);
- auto Last = adl_end(Range);
+ auto First = std::begin(Range);
+ auto Last = std::end(Range);
if (First == Last)
return true;
auto Prev = First;
More information about the llvm-commits
mailing list