Skip to content

Commit

Permalink
[ConstantRange] Add initial support for binaryXor.
Browse files Browse the repository at this point in the history
The initial implementation just delegates to APInt's implementation of
XOR for single element ranges and conservatively returns the full set
otherwise.

Reviewers: nikic, spatel, lebedev.ri

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D76453
  • Loading branch information
fhahn committed Mar 24, 2020
1 parent 0b59982 commit 7caba33
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/ConstantRange.h
Expand Up @@ -409,6 +409,10 @@ class LLVM_NODISCARD ConstantRange {
/// from a binary-or of a value in this range by a value in \p Other.
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.
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/IR/ConstantRange.cpp
Expand Up @@ -802,6 +802,8 @@ ConstantRange ConstantRange::binaryOp(Instruction::BinaryOps BinOp,
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:
Expand Down Expand Up @@ -1211,6 +1213,18 @@ ConstantRange::binaryOr(const ConstantRange &Other) const {
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())
Expand Down
16 changes: 16 additions & 0 deletions llvm/unittests/IR/ConstantRangeTest.cpp
Expand Up @@ -2317,4 +2317,20 @@ TEST_F(ConstantRangeTest, castOps) {
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

0 comments on commit 7caba33

Please sign in to comment.