Index: llvm/include/llvm/CodeGen/GlobalISel/Utils.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -373,6 +373,23 @@ bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP); +/// \returns Whether or not \p Val would be a true value if it was extended to +/// \p ExtTy. +/// +/// \p IsFP is true if the true value is floating point. +/// \p IsSignExtended is true if the extension should be signed. +bool isExtendedTrueVal(const APInt &Val, const LLT ExtTy, + const TargetLowering &TLI, bool IsFP, + bool IsSignExtended); +/// \returns Whether or not \p Val would be a true value if it was extended from +/// \p OrigTy to \p ExtTy. +/// +/// \p IsFP is true if the true value is floating point. +/// \p IsSignExtended is true if the extension should be signed. +bool isExtendedTrueVal(int64_t Val, const LLT OrigTy, const LLT ExtTy, + const TargetLowering &TLI, bool IsFP, + bool IsSignExtended); + /// Returns an integer representing true, as defined by the /// TargetBooleanContents. int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP); Index: llvm/lib/CodeGen/GlobalISel/Utils.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -971,6 +971,26 @@ llvm_unreachable("Invalid boolean contents"); } +bool llvm::isExtendedTrueVal(const APInt &Val, const LLT ExtTy, + const TargetLowering &TLI, bool IsFP, + bool IsSignExtended) { + unsigned OrigWidth = Val.getBitWidth(); + unsigned ExtWidth = ExtTy.getScalarSizeInBits(); + assert(ExtWidth >= OrigWidth && "Extension cannot be smaller than width!"); + APInt ExtVal = + IsSignExtended ? Val.sextOrSelf(ExtWidth) : Val.zextOrSelf(ExtWidth); + return ExtVal == APInt(ExtWidth, getICmpTrueVal(TLI, ExtTy.isVector(), IsFP)); +} + +bool llvm::isExtendedTrueVal(int64_t Val, const LLT OrigTy, const LLT ExtTy, + const TargetLowering &TLI, bool IsFP, + bool IsSignExtended) { + assert(OrigTy.isVector() == ExtTy.isVector() && + "OrigTy and ExtTy must both be vectors or scalars!"); + return isExtendedTrueVal(APInt(OrigTy.getScalarSizeInBits(), Val), ExtTy, TLI, + IsFP, IsSignExtended); +} + int64_t llvm::getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP) { switch (TLI.getBooleanContents(IsVector, IsFP)) { Index: llvm/unittests/CodeGen/GlobalISel/GISelUtilsTest.cpp =================================================================== --- llvm/unittests/CodeGen/GlobalISel/GISelUtilsTest.cpp +++ llvm/unittests/CodeGen/GlobalISel/GISelUtilsTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "GISelMITest.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "gtest/gtest.h" @@ -20,6 +21,8 @@ static const LLT P0 = LLT::pointer(0, 64); static const LLT P1 = LLT::pointer(1, 32); +static const LLT V2S1 = LLT::vector(2, 1); + static const LLT V2S8 = LLT::vector(2, 8); static const LLT V4S8 = LLT::vector(4, 8); static const LLT V8S8 = LLT::vector(8, 8); @@ -241,4 +244,54 @@ EXPECT_EQ(V4P1, getLCMType(P1, V2S64)); } +TEST_F(AArch64GISelMITest, ExtendedTrueTest) { + setUp(); + if (!TM) + return; + const auto &TLI = *B.getMF().getSubtarget().getTargetLowering(); + // Test extended true/false for s1. This should only return true for 1, + // regardless of any other inputs, because we only have one bit. + for (auto IsFP : {true, false}) { + for (auto IsSignExtended : {true, false}) { + for (auto Ty : {S1, V2S1}) { + // 1 and -1 both work, because these are all-ones values. + EXPECT_TRUE(isExtendedTrueVal(1, Ty, Ty, TLI, IsFP, IsSignExtended)); + EXPECT_TRUE(isExtendedTrueVal(-1, Ty, Ty, TLI, IsFP, IsSignExtended)); + EXPECT_FALSE(isExtendedTrueVal(0, Ty, Ty, TLI, IsFP, IsSignExtended)); + } + + // ZeroOrOneBooleanContent + EXPECT_TRUE(isExtendedTrueVal(1, S32, S32, TLI, IsFP, IsSignExtended)); + EXPECT_TRUE(isExtendedTrueVal(1, S32, S64, TLI, IsFP, IsSignExtended)); + EXPECT_FALSE(isExtendedTrueVal(0, S32, S64, TLI, IsFP, IsSignExtended)); + EXPECT_FALSE(isExtendedTrueVal(-1, S32, S64, TLI, IsFP, IsSignExtended)); + + // ZeroOrNegativeOneBooleanContent + EXPECT_TRUE( + isExtendedTrueVal(-1, V2S32, V2S32, TLI, IsFP, IsSignExtended)); + EXPECT_FALSE( + isExtendedTrueVal(0, V2S32, V2S64, TLI, IsFP, IsSignExtended)); + EXPECT_FALSE( + isExtendedTrueVal(1, V2S32, V2S64, TLI, IsFP, IsSignExtended)); + } + + // Test differing behaviour between SExt + ZExt. + const bool SExt = true; + const bool ZExt = false; + // ZeroOrOneBooleanContent + EXPECT_TRUE(isExtendedTrueVal(1, S1, S32, TLI, IsFP, ZExt)); + EXPECT_FALSE(isExtendedTrueVal(1, S1, S32, TLI, IsFP, SExt)); + + // ZeroOrNegativeOneBooleanContent + EXPECT_FALSE(isExtendedTrueVal(1, V2S1, V2S32, TLI, IsFP, ZExt)); + EXPECT_FALSE(isExtendedTrueVal(-1, V2S1, V2S32, TLI, IsFP, ZExt)); + EXPECT_FALSE(isExtendedTrueVal(-1, V2S32, V2S64, TLI, IsFP, ZExt)); + + EXPECT_TRUE(isExtendedTrueVal(1, V2S1, V2S32, TLI, IsFP, SExt)); + EXPECT_TRUE(isExtendedTrueVal(-1, V2S1, V2S32, TLI, IsFP, SExt)); + EXPECT_TRUE(isExtendedTrueVal(-1, V2S32, V2S64, TLI, IsFP, SExt)); + EXPECT_TRUE(isExtendedTrueVal(0xFFFFFFFF, V2S32, V2S64, TLI, IsFP, SExt)); + EXPECT_FALSE(isExtendedTrueVal(0xFFFFFFFE, V2S32, V2S64, TLI, IsFP, SExt)); + } } +} // namespace