[llvm] 3348b84 - Make enum iteration with seq safe by default
Jakub Kuderski via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 3 17:57:34 PDT 2021
Author: Jakub Kuderski
Date: 2021-11-03T20:52:21-04:00
New Revision: 3348b841d36e6a189e1bcb30de41b7a8ec8c6991
URL: https://github.com/llvm/llvm-project/commit/3348b841d36e6a189e1bcb30de41b7a8ec8c6991
DIFF: https://github.com/llvm/llvm-project/commit/3348b841d36e6a189e1bcb30de41b7a8ec8c6991.diff
LOG: Make enum iteration with seq safe by default
By default `llvm::seq` would happily iterate over enums, which may be unsafe if the enum values are not continuous. This patch disable enum iteration with `llvm::seq` and `llvm::seq_inclusive` and adds two new functions: `enum_seq` and `enum_seq_inclusive`.
To make sure enum iteration is safe, we require users to declare their enum types as iterable by specializing `enum_iteration_traits<SomeEnum>`. Because it's not always possible to add these traits next to enum definition (e.g., for enums defined in external libraries), we provide an escape hatch to allow iteration on per-callsite basis by passing `force_iteration_on_noniterable_enum`.
The main benefit of this approach is that these global declarations via traits can appear just next to enum definitions, making easy to spot when enums are miss-labeled, e.g., after introducing new enum values, whereas `force_iteration_on_noniterable_enum` should stand out and be easy to grep for.
This emerged from a discussion with gchatelet@ about reusing llvm's `Sequence.h` in lieu of https://github.com/GPUOpen-Drivers/llpc/blob/dev/lgc/interface/lgc/EnumIterator.h.
Reviewed By: dblaikie, gchatelet, aaron.ballman
Differential Revision: https://reviews.llvm.org/D107378
Added:
Modified:
llvm/include/llvm/ADT/Sequence.h
llvm/include/llvm/IR/InstrTypes.h
llvm/include/llvm/IR/Instructions.h
llvm/include/llvm/Support/MachineValueType.h
llvm/tools/llvm-exegesis/lib/X86/Target.cpp
llvm/unittests/ADT/SequenceTest.cpp
llvm/unittests/IR/ConstantRangeTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/Sequence.h b/llvm/include/llvm/ADT/Sequence.h
index 9fcb3034ee73f..fdbf397984d0b 100644
--- a/llvm/include/llvm/ADT/Sequence.h
+++ b/llvm/include/llvm/ADT/Sequence.h
@@ -31,6 +31,50 @@
///
/// Prints: `0 1 2 3 `.
///
+/// Similar to `seq` and `seq_inclusive`, the `enum_seq` and
+/// `enum_seq_inclusive` functions produce sequences of enum values that can be
+/// iterated over.
+/// To enable iteration with enum types, you need to either mark enums as safe
+/// to iterate on by specializing `enum_iteration_traits`, or opt into
+/// potentially unsafe iteration at every callsite by passing
+/// `force_iteration_on_noniterable_enum`.
+///
+/// Examples with enum types:
+/// ```
+/// namespace X {
+/// enum class MyEnum : unsigned {A = 0, B, C};
+/// } // namespace X
+///
+/// template <> struct enum_iteration_traits<X::MyEnum> {
+/// static contexpr bool is_iterable = true;
+/// };
+///
+/// class MyClass {
+/// public:
+/// enum Safe { D = 3, E, F };
+/// enum MaybeUnsafe { G = 1, H = 2, I = 4 };
+/// };
+///
+/// template <> struct enum_iteration_traits<MyClass::Safe> {
+/// static contexpr bool is_iterable = true;
+/// };
+/// ```
+///
+/// ```
+/// for (auto v : enum_seq(MyClass::Safe::D, MyClass::Safe::F))
+/// outs() << int(v) << " ";
+/// ```
+///
+/// Prints: `3 4 `.
+///
+/// ```
+/// for (auto v : enum_seq(MyClass::MaybeUnsafe::H, MyClass::MaybeUnsafe::I,
+/// force_iteration_on_noniterable_enum))
+/// outs() << int(v) << " ";
+/// ```
+///
+/// Prints: `2 3 `.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SEQUENCE_H
@@ -39,12 +83,31 @@
#include <cassert> // assert
#include <iterator> // std::random_access_iterator_tag
#include <limits> // std::numeric_limits
-#include <type_traits> // std::underlying_type, std::is_enum
+#include <type_traits> // std::is_integral, std::is_enum, std::underlying_type,
+ // std::enable_if
#include "llvm/Support/MathExtras.h" // AddOverflow / SubOverflow
namespace llvm {
+// Enum traits that marks enums as safe or unsafe to iterate over.
+// By default, enum types are *not* considered safe for iteration.
+// To allow iteration for your enum type, provide a specialization with
+// `is_iterable` set to `true` in the `llvm` namespace.
+// Alternatively, you can pass the `force_iteration_on_noniterable_enum` tag
+// to `enum_seq` or `enum_seq_inclusive`.
+template <typename EnumT> struct enum_iteration_traits {
+ static constexpr bool is_iterable = false;
+};
+
+struct force_iteration_on_noniterable_enum_t {
+ explicit force_iteration_on_noniterable_enum_t() = default;
+};
+
+// TODO: Make this `inline` once we update to C++17 to avoid ORD violations.
+constexpr force_iteration_on_noniterable_enum_t
+ force_iteration_on_noniterable_enum;
+
namespace detail {
// Returns whether a value of type U can be represented with type T.
@@ -234,27 +297,81 @@ template <typename T> struct iota_range {
iterator PastEndValue;
};
-/// Iterate over an integral/enum type from Begin up to - but not including -
-/// End.
-/// Note on enum iteration: `seq` will generate each consecutive value, even if
-/// no enumerator with that value exists.
+/// Iterate over an integral type from Begin up to - but not including - End.
/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
/// iteration).
-template <typename T> auto seq(T Begin, T End) {
+template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
+ !std::is_enum<T>::value>>
+auto seq(T Begin, T End) {
return iota_range<T>(Begin, End, false);
}
-/// Iterate over an integral/enum type from Begin to End inclusive.
-/// Note on enum iteration: `seq_inclusive` will generate each consecutive
-/// value, even if no enumerator with that value exists.
+/// Iterate over an integral type from Begin to End inclusive.
/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
/// iteration).
-template <typename T> auto seq_inclusive(T Begin, T End) {
+template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
+ !std::is_enum<T>::value>>
+auto seq_inclusive(T Begin, T End) {
return iota_range<T>(Begin, End, true);
}
+/// Iterate over an enum type from Begin up to - but not including - End.
+/// Note: `enum_seq` will generate each consecutive value, even if no
+/// enumerator with that value exists.
+/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
+/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
+/// iteration).
+template <typename EnumT,
+ typename = std::enable_if_t<std::is_enum<EnumT>::value>>
+auto enum_seq(EnumT Begin, EnumT End) {
+ static_assert(enum_iteration_traits<EnumT>::is_iterable,
+ "Enum type is not marked as iterable.");
+ return iota_range<EnumT>(Begin, End, false);
+}
+
+/// Iterate over an enum type from Begin up to - but not including - End, even
+/// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
+/// Note: `enum_seq` will generate each consecutive value, even if no
+/// enumerator with that value exists.
+/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
+/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
+/// iteration).
+template <typename EnumT,
+ typename = std::enable_if_t<std::is_enum<EnumT>::value>>
+auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
+ return iota_range<EnumT>(Begin, End, false);
+}
+
+/// Iterate over an enum type from Begin to End inclusive.
+/// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
+/// enumerator with that value exists.
+/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
+/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
+/// iteration).
+template <typename EnumT,
+ typename = std::enable_if_t<std::is_enum<EnumT>::value>>
+auto enum_seq_inclusive(EnumT Begin, EnumT End) {
+ static_assert(enum_iteration_traits<EnumT>::is_iterable,
+ "Enum type is not marked as iterable.");
+ return iota_range<EnumT>(Begin, End, true);
+}
+
+/// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
+/// is not marked as safely iterable by `enum_iteration_traits`.
+/// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
+/// enumerator with that value exists.
+/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
+/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
+/// iteration).
+template <typename EnumT,
+ typename = std::enable_if_t<std::is_enum<EnumT>::value>>
+auto enum_seq_inclusive(EnumT Begin, EnumT End,
+ force_iteration_on_noniterable_enum_t) {
+ return iota_range<EnumT>(Begin, End, true);
+}
+
} // end namespace llvm
#endif // LLVM_ADT_SEQUENCE_H
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index a2180a8d4b2a3..143a87f4997d3 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -755,6 +756,20 @@ class CmpInst : public Instruction {
using PredicateField =
Bitfield::Element<Predicate, 0, 6, LAST_ICMP_PREDICATE>;
+ /// Returns the sequence of all FCmp predicates.
+ static auto FCmpPredicates() {
+ return enum_seq_inclusive(Predicate::FIRST_FCMP_PREDICATE,
+ Predicate::LAST_FCMP_PREDICATE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ /// Returns the sequence of all ICmp predicates.
+ static auto ICmpPredicates() {
+ return enum_seq_inclusive(Predicate::FIRST_ICMP_PREDICATE,
+ Predicate::LAST_ICMP_PREDICATE,
+ force_iteration_on_noniterable_enum);
+ }
+
protected:
CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred,
Value *LHS, Value *RHS, const Twine &Name = "",
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 3c7911d251364..59a783dbdf8d8 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1339,6 +1339,10 @@ class ICmpInst: public CmpInst {
return P == ICMP_SLE || P == ICMP_ULE;
}
+ /// Returns the sequence of all ICmp predicates.
+ ///
+ static auto predicates() { return ICmpPredicates(); }
+
/// Exchange the two operands to this instruction in such a way that it does
/// not modify the semantics of the instruction. The predicate value may be
/// changed to retain the same result if the predicate is order dependent
@@ -1461,6 +1465,10 @@ class FCmpInst: public CmpInst {
Op<0>().swap(Op<1>());
}
+ /// Returns the sequence of all FCmp predicates.
+ ///
+ static auto predicates() { return FCmpPredicates(); }
+
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Instruction *I) {
return I->getOpcode() == Instruction::FCmp;
diff --git a/llvm/include/llvm/Support/MachineValueType.h b/llvm/include/llvm/Support/MachineValueType.h
index 5c73cece85c3f..ce10a4c58dfe8 100644
--- a/llvm/include/llvm/Support/MachineValueType.h
+++ b/llvm/include/llvm/Support/MachineValueType.h
@@ -1405,51 +1405,61 @@ namespace llvm {
/// SimpleValueType Iteration
/// @{
static auto all_valuetypes() {
- return seq_inclusive(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto integer_valuetypes() {
- return seq_inclusive(MVT::FIRST_INTEGER_VALUETYPE,
- MVT::LAST_INTEGER_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_VALUETYPE,
+ MVT::LAST_INTEGER_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto fp_valuetypes() {
- return seq_inclusive(MVT::FIRST_FP_VALUETYPE, MVT::LAST_FP_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_FP_VALUETYPE, MVT::LAST_FP_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_VECTOR_VALUETYPE,
- MVT::LAST_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_VECTOR_VALUETYPE,
+ MVT::LAST_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto fixedlen_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE,
- MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto scalable_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_SCALABLE_VECTOR_VALUETYPE,
- MVT::LAST_SCALABLE_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto integer_fixedlen_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE,
- MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto fp_fixedlen_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE,
- MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto integer_scalable_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE,
- MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
static auto fp_scalable_vector_valuetypes() {
- return seq_inclusive(MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE,
- MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE);
+ return enum_seq_inclusive(MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
}
/// @}
};
diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index 1be119a508d54..9d3fe2dbfbd59 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -918,8 +918,9 @@ std::vector<InstructionTemplate> ExegesisX86Target::generateInstructionVariants(
continue;
case X86::OperandType::OPERAND_COND_CODE: {
Exploration = true;
- auto CondCodes =
- seq_inclusive(X86::CondCode::COND_O, X86::CondCode::LAST_VALID_COND);
+ auto CondCodes = enum_seq_inclusive(X86::CondCode::COND_O,
+ X86::CondCode::LAST_VALID_COND,
+ force_iteration_on_noniterable_enum);
Choices.reserve(CondCodes.size());
for (int CondCode : CondCodes)
Choices.emplace_back(MCOperand::createImm(CondCode));
diff --git a/llvm/unittests/ADT/SequenceTest.cpp b/llvm/unittests/ADT/SequenceTest.cpp
index 8ac1e208a946c..71fae0b56ffda 100644
--- a/llvm/unittests/ADT/SequenceTest.cpp
+++ b/llvm/unittests/ADT/SequenceTest.cpp
@@ -16,6 +16,7 @@
using namespace llvm;
using testing::ElementsAre;
+using testing::IsEmpty;
namespace {
@@ -68,17 +69,6 @@ TYPED_TEST(StrongIntTest, Operations) {
EXPECT_EQ(Actual - (Actual + 2), -2);
}
-TEST(StrongIntTest, Enums) {
- enum UntypedEnum { A = 3 };
- EXPECT_EQ(CheckedInt::from(A).to<UntypedEnum>(), A);
-
- enum TypedEnum : uint32_t { B = 3 };
- EXPECT_EQ(CheckedInt::from(B).to<TypedEnum>(), B);
-
- enum class ScopedEnum : uint16_t { C = 3 };
- EXPECT_EQ(CheckedInt::from(ScopedEnum::C).to<ScopedEnum>(), ScopedEnum::C);
-}
-
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
TEST(StrongIntDeathTest, OutOfBounds) {
// Values above 'INTMAX_MAX' are not representable.
@@ -215,4 +205,94 @@ TEST(SequenceTest, Dereference) {
EXPECT_EQ(Backward[2], 7);
}
-} // anonymous namespace
+enum UntypedEnum { A = 3 };
+enum TypedEnum : uint32_t { B = 3 };
+
+namespace X {
+enum class ScopedEnum : uint16_t { C = 3 };
+} // namespace X
+
+struct S {
+ enum NestedEnum { D = 4 };
+ enum NestedEnum2 { E = 5 };
+
+private:
+ enum NestedEnum3 { F = 6 };
+ friend struct llvm::enum_iteration_traits<NestedEnum3>;
+
+public:
+ static auto getNestedEnum3() { return NestedEnum3::F; }
+};
+
+} // namespace
+
+namespace llvm {
+
+template <> struct enum_iteration_traits<UntypedEnum> {
+ static constexpr bool is_iterable = true;
+};
+
+template <> struct enum_iteration_traits<TypedEnum> {
+ static constexpr bool is_iterable = true;
+};
+
+template <> struct enum_iteration_traits<X::ScopedEnum> {
+ static constexpr bool is_iterable = true;
+};
+
+template <> struct enum_iteration_traits<S::NestedEnum> {
+ static constexpr bool is_iterable = true;
+};
+
+template <> struct enum_iteration_traits<S::NestedEnum3> {
+ static constexpr bool is_iterable = true;
+};
+
+} // namespace llvm
+
+namespace {
+
+TEST(StrongIntTest, Enums) {
+ EXPECT_EQ(CheckedInt::from(A).to<UntypedEnum>(), A);
+ EXPECT_EQ(CheckedInt::from(B).to<TypedEnum>(), B);
+ EXPECT_EQ(CheckedInt::from(X::ScopedEnum::C).to<X::ScopedEnum>(),
+ X::ScopedEnum::C);
+}
+
+TEST(SequenceTest, IterableEnums) {
+ EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A), IsEmpty());
+ EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A),
+ ElementsAre(UntypedEnum::A));
+
+ EXPECT_THAT(enum_seq(TypedEnum::B, TypedEnum::B), IsEmpty());
+ EXPECT_THAT(enum_seq_inclusive(TypedEnum::B, TypedEnum::B),
+ ElementsAre(TypedEnum::B));
+
+ EXPECT_THAT(enum_seq(X::ScopedEnum::C, X::ScopedEnum::C), IsEmpty());
+ EXPECT_THAT(enum_seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C),
+ ElementsAre(X::ScopedEnum::C));
+
+ EXPECT_THAT(enum_seq_inclusive(S::NestedEnum::D, S::NestedEnum::D),
+ ElementsAre(S::NestedEnum::D));
+ EXPECT_THAT(enum_seq_inclusive(S::getNestedEnum3(), S::getNestedEnum3()),
+ ElementsAre(S::getNestedEnum3()));
+}
+
+TEST(SequenceTest, NonIterableEnums) {
+ EXPECT_THAT(enum_seq(S::NestedEnum2::E, S::NestedEnum2::E,
+ force_iteration_on_noniterable_enum),
+ IsEmpty());
+ EXPECT_THAT(enum_seq_inclusive(S::NestedEnum2::E, S::NestedEnum2::E,
+ force_iteration_on_noniterable_enum),
+ ElementsAre(S::NestedEnum2::E));
+
+ // Check that this also works with enums marked as iterable.
+ EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A,
+ force_iteration_on_noniterable_enum),
+ IsEmpty());
+ EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A,
+ force_iteration_on_noniterable_enum),
+ ElementsAre(UntypedEnum::A));
+}
+
+} // namespace
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 7bf7e0b4c9278..f88e9869bf24a 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1572,8 +1572,7 @@ void ICmpTestImpl(CmpInst::Predicate Pred) {
}
TEST(ConstantRange, ICmp) {
- for (auto Pred : seq_inclusive(CmpInst::Predicate::FIRST_ICMP_PREDICATE,
- CmpInst::Predicate::LAST_ICMP_PREDICATE))
+ for (auto Pred : ICmpInst::predicates())
ICmpTestImpl(Pred);
}
@@ -2531,8 +2530,7 @@ void testConstantRangeICmpPredEquivalence(ICmpInst::Predicate SrcPred, T Func) {
}
TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfICmpPredicate) {
- for (auto Pred : seq_inclusive(ICmpInst::Predicate::FIRST_ICMP_PREDICATE,
- ICmpInst::Predicate::LAST_ICMP_PREDICATE)) {
+ for (auto Pred : ICmpInst::predicates()) {
if (ICmpInst::isEquality(Pred))
continue;
ICmpInst::Predicate FlippedSignednessPred =
@@ -2548,8 +2546,7 @@ TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfICmpPredicate) {
}
TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfInvertedICmpPredicate) {
- for (auto Pred : seq_inclusive(ICmpInst::Predicate::FIRST_ICMP_PREDICATE,
- ICmpInst::Predicate::LAST_ICMP_PREDICATE)) {
+ for (auto Pred : ICmpInst::predicates()) {
if (ICmpInst::isEquality(Pred))
continue;
ICmpInst::Predicate InvertedFlippedSignednessPred =
@@ -2567,8 +2564,7 @@ TEST_F(ConstantRangeTest, areInsensitiveToSignednessOfInvertedICmpPredicate) {
}
TEST_F(ConstantRangeTest, getEquivalentPredWithFlippedSignedness) {
- for (auto Pred : seq_inclusive(ICmpInst::Predicate::FIRST_ICMP_PREDICATE,
- ICmpInst::Predicate::LAST_ICMP_PREDICATE)) {
+ for (auto Pred : ICmpInst::predicates()) {
if (ICmpInst::isEquality(Pred))
continue;
testConstantRangeICmpPredEquivalence(
More information about the llvm-commits
mailing list