Index: llvm/include/llvm/ADT/Sequence.h =================================================================== --- llvm/include/llvm/ADT/Sequence.h +++ llvm/include/llvm/ADT/Sequence.h @@ -24,6 +24,30 @@ namespace llvm { +template struct iterable_enum_traits { + static constexpr bool is_iterable = true; +}; + +template struct enum_with_traits { + EnumT value; + static constexpr bool is_iterable = TraitsT::is_iterable; + using enum_type = EnumT; + using underlying_type = std::underlying_type_t; +}; + +template auto add_enum_traits(EnumT value); + +template +enum_with_traits> +make_iterable_enum(EnumT value) { + return {value}; +} + +#define DECLARE_ITERABLE_ENUM(ENUM) \ + inline auto add_enum_traits(ENUM value) { \ + return llvm::make_iterable_enum(value); \ + } + namespace detail { // Returns whether a value of type U can be represented with type T. @@ -220,8 +244,20 @@ /// 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 auto seq(T Begin, T End) { - return iota_range(Begin, End, false); +template ::value, bool> = 0> +auto seq(Integral Begin, Integral End) { + return iota_range(Begin, End, false); +} + +template auto seq(enum_with_traits Begin, enum_with_traits End) { + return iota_range(Begin.value, End.value, false); +} + +template ::value, bool> = 0> +auto seq(Enum Begin, Enum End) { + return seq(add_enum_traits(Begin), add_enum_traits(End)); } /// Iterate over an integral/enum type from Begin to End inclusive. @@ -230,8 +266,23 @@ /// 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 auto seq_inclusive(T Begin, T End) { - return iota_range(Begin, End, true); + +template ::value, bool> = 0> +auto seq_inclusive(Integral Begin, Integral End) { + return iota_range(Begin, End, true); +} + +template +auto seq_inclusive(enum_with_traits Begin, + enum_with_traits End) { + return iota_range(Begin.value, End.value, true); +} + +template ::value, bool> = 0> +auto seq_inclusive(Enum Begin, Enum End) { + return seq_inclusive(add_enum_traits(Begin), add_enum_traits(End)); } } // end namespace llvm Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ 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" @@ -2357,6 +2358,8 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(FuncletPadInst, Value) +DECLARE_ITERABLE_ENUM(CmpInst::Predicate) + } // end namespace llvm #endif // LLVM_IR_INSTRTYPES_H Index: llvm/include/llvm/Support/MachineValueType.h =================================================================== --- llvm/include/llvm/Support/MachineValueType.h +++ llvm/include/llvm/Support/MachineValueType.h @@ -1402,6 +1402,9 @@ static MVT getVT(Type *Ty, bool HandleUnknown = false); public: + + friend DECLARE_ITERABLE_ENUM(MVT::SimpleValueType) + /// SimpleValueType Iteration /// @{ static auto all_valuetypes() { Index: llvm/tools/llvm-exegesis/lib/X86/Target.cpp =================================================================== --- llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -33,6 +33,9 @@ #endif namespace llvm { + +// DECLARE_ITERABLE_ENUM(X86::CondCode); + namespace exegesis { static cl::OptionCategory @@ -619,13 +622,13 @@ public: X86SavedState() { #ifdef __x86_64__ -# if defined(_MSC_VER) +#if defined(_MSC_VER) _fxsave64(FPState); Eflags = __readeflags(); -# elif defined(__GNUC__) +#elif defined(__GNUC__) __builtin_ia32_fxsave64(FPState); Eflags = __builtin_ia32_readeflags_u64(); -# endif +#endif #else llvm_unreachable("X86 exegesis running on non-X86 target"); #endif @@ -635,15 +638,15 @@ // Restoring the X87 state does not flush pending exceptions, make sure // these exceptions are flushed now. #ifdef __x86_64__ -# if defined(_MSC_VER) +#if defined(_MSC_VER) _clearfp(); _fxrstor64(FPState); __writeeflags(Eflags); -# elif defined(__GNUC__) +#elif defined(__GNUC__) asm volatile("fwait"); __builtin_ia32_fxrstor64(FPState); __builtin_ia32_writeeflags_u64(Eflags); -# endif +#endif #else llvm_unreachable("X86 exegesis running on non-X86 target"); #endif @@ -919,7 +922,7 @@ case X86::OperandType::OPERAND_COND_CODE: { Exploration = true; auto CondCodes = - seq_inclusive(X86::CondCode::COND_O, X86::CondCode::LAST_VALID_COND); + seq_inclusive(make_iterable_enum(X86::CondCode::COND_O), make_iterable_enum(X86::CondCode::LAST_VALID_COND)); Choices.reserve(CondCodes.size()); for (int CondCode : CondCodes) Choices.emplace_back(MCOperand::createImm(CondCode)); Index: llvm/unittests/ADT/SequenceTest.cpp =================================================================== --- llvm/unittests/ADT/SequenceTest.cpp +++ llvm/unittests/ADT/SequenceTest.cpp @@ -68,17 +68,6 @@ EXPECT_EQ(Actual - (Actual + 2), -2); } -TEST(StrongIntTest, Enums) { - enum UntypedEnum { A = 3 }; - EXPECT_EQ(CheckedInt::from(A).to(), A); - - enum TypedEnum : uint32_t { B = 3 }; - EXPECT_EQ(CheckedInt::from(B).to(), B); - - enum class ScopedEnum : uint16_t { C = 3 }; - EXPECT_EQ(CheckedInt::from(ScopedEnum::C).to(), ScopedEnum::C); -} - #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) TEST(StrongIntDeathTest, OutOfBounds) { // Values above 'INTMAX_MAX' are not representable. @@ -215,4 +204,28 @@ EXPECT_EQ(Backward[2], 7); } -} // anonymous namespace +enum UntypedEnum { A = 3 }; +enum TypedEnum : uint32_t { B = 3 }; + +DECLARE_ITERABLE_ENUM(UntypedEnum) +DECLARE_ITERABLE_ENUM(TypedEnum) + +namespace X { +enum class ScopedEnum : uint16_t { C = 3 }; +DECLARE_ITERABLE_ENUM(X::ScopedEnum) +} // namespace X + +enum class ScopedEnum2 : uint16_t { C = 3 }; + +TEST(StrongIntTest, Enums) { + EXPECT_EQ(CheckedInt::from(A).to(), A); + EXPECT_EQ(CheckedInt::from(B).to(), B); + EXPECT_EQ(CheckedInt::from(X::ScopedEnum::C).to(), X::ScopedEnum::C); +} + +TEST(StrongIntTest, EnumEscapeHatch) { + EXPECT_FALSE(llvm::empty(seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C))); + EXPECT_FALSE(llvm::empty(seq_inclusive(make_iterable_enum(ScopedEnum2::C), + make_iterable_enum(ScopedEnum2::C)))); +} +} // namespace