diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -410,6 +410,10 @@ ConstantRange binaryOr(const ConstantRange &Other) const; /// Return a new range representing the possible values resulting + /// from a binary-xor of a value in this range by a value in \p Other. + ConstantRange binaryXor(const ConstantRange &Other) const; + + /// Return a new range representing the possible values resulting /// from a left shift of a value in this range by a value in \p Other. /// TODO: This isn't fully implemented yet. ConstantRange shl(const ConstantRange &Other) const; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -802,6 +802,8 @@ return binaryAnd(Other); case Instruction::Or: return binaryOr(Other); + case Instruction::Xor: + return binaryXor(Other); // Note: floating point operations applied to abstract ranges are just // ideal integer operations with a lossy representation case Instruction::FAdd: @@ -1211,6 +1213,18 @@ return getNonEmpty(std::move(umax), APInt::getNullValue(getBitWidth())); } +ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return getEmpty(); + + // Use APInt's implementation of XOR for single element ranges. + if (isSingleElement() && Other.isSingleElement()) + return {*getSingleElement() ^ *Other.getSingleElement()}; + + // TODO: replace this with something less conservative + return getFull(); +} + ConstantRange ConstantRange::shl(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -2317,4 +2317,20 @@ EXPECT_EQ(64u, IntToPtr.getBitWidth()); EXPECT_TRUE(IntToPtr.isFullSet()); } + +TEST_F(ConstantRangeTest, binaryXor) { + // Single element ranges. + ConstantRange R16(APInt(8, 16)); + ConstantRange R20(APInt(8, 20)); + EXPECT_EQ(*R16.binaryXor(R16).getSingleElement(), APInt(8, 0)); + EXPECT_EQ(*R16.binaryXor(R20).getSingleElement(), APInt(8, 16 ^ 20)); + + // Ranges with more than a single element. Handled conservatively for now. + ConstantRange R16_35(APInt(8, 16), APInt(8, 35)); + ConstantRange R0_99(APInt(8, 0), APInt(8, 99)); + EXPECT_TRUE(R16_35.binaryXor(R16_35).isFullSet()); + EXPECT_TRUE(R16_35.binaryXor(R0_99).isFullSet()); + EXPECT_TRUE(R0_99.binaryXor(R16_35).isFullSet()); +} + } // anonymous namespace