Skip to content

Commit

Permalink
InstCombine/Select: remove redundant code (NFC) (#112388)
Browse files Browse the repository at this point in the history
InstCombinerImpl::foldSelectInstWithICmp has some inlined code for
select-icmp-xor simplification, but this simplification is already done
by other code, via another path:

  (X & Y) == 0 ? X : X ^ Y ->
  ((X & Y) == 0 ? 0 : Y) ^ X ->
  (X & Y) ^ X ->
  X & ~Y

Cover the cases that it claims to simplify, and demonstrate that
stripping it doesn't cause test changes.
  • Loading branch information
artagnon authored Oct 16, 2024
1 parent 0936195 commit 682fa79
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 50 deletions.
50 changes: 0 additions & 50 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1954,56 +1954,6 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
return &SI;
}

// FIXME: This code is nearly duplicated in InstSimplify. Using/refactoring
// decomposeBitTestICmp() might help.
if (TrueVal->getType()->isIntOrIntVectorTy()) {
unsigned BitWidth =
DL.getTypeSizeInBits(TrueVal->getType()->getScalarType());
APInt MinSignedValue = APInt::getSignedMinValue(BitWidth);
Value *X;
const APInt *Y, *C;
bool TrueWhenUnset;
bool IsBitTest = false;
if (ICmpInst::isEquality(Pred) &&
match(CmpLHS, m_And(m_Value(X), m_Power2(Y))) &&
match(CmpRHS, m_Zero())) {
IsBitTest = true;
TrueWhenUnset = Pred == ICmpInst::ICMP_EQ;
} else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) {
X = CmpLHS;
Y = &MinSignedValue;
IsBitTest = true;
TrueWhenUnset = false;
} else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) {
X = CmpLHS;
Y = &MinSignedValue;
IsBitTest = true;
TrueWhenUnset = true;
}
if (IsBitTest) {
Value *V = nullptr;
// (X & Y) == 0 ? X : X ^ Y --> X & ~Y
if (TrueWhenUnset && TrueVal == X &&
match(FalseVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C)
V = Builder.CreateAnd(X, ~(*Y));
// (X & Y) != 0 ? X ^ Y : X --> X & ~Y
else if (!TrueWhenUnset && FalseVal == X &&
match(TrueVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C)
V = Builder.CreateAnd(X, ~(*Y));
// (X & Y) == 0 ? X ^ Y : X --> X | Y
else if (TrueWhenUnset && FalseVal == X &&
match(TrueVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C)
V = Builder.CreateOr(X, *Y);
// (X & Y) != 0 ? X : X ^ Y --> X | Y
else if (!TrueWhenUnset && TrueVal == X &&
match(FalseVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C)
V = Builder.CreateOr(X, *Y);

if (V)
return replaceInstUsesWith(SI, V);
}
}

if (Instruction *V =
foldSelectICmpAndAnd(SI.getType(), ICI, TrueVal, FalseVal, Builder))
return V;
Expand Down
190 changes: 190 additions & 0 deletions llvm/test/Transforms/InstCombine/select-icmp-xor.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=instcombine -S %s | FileCheck %s

define i8 @select_icmp_eq_pow2(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_eq_pow2(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = and i8 [[X]], -5
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 4
%icmp = icmp eq i8 %and, 0
%xor = xor i8 %x, 4
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_eq_pow2_flipped(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_eq_pow2_flipped(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = or i8 [[X]], 4
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 4
%icmp = icmp eq i8 %and, 0
%xor = xor i8 %x, 4
%sel = select i1 %icmp, i8 %xor, i8 %x
ret i8 %sel
}

define i8 @select_icmp_eq_not_pow2(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_eq_not_pow2(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], 5
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 5
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP]], i8 [[X]], i8 [[XOR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 5
%icmp = icmp eq i8 %and, 0
%xor = xor i8 %x, 5
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_ne_pow2(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_ne_pow2(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = and i8 [[X]], -5
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 4
%icmp = icmp ne i8 %and, 0
%xor = xor i8 %x, 4
%sel = select i1 %icmp, i8 %xor, i8 %x
ret i8 %sel
}

define i8 @select_icmp_ne_pow2_flipped(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_ne_pow2_flipped(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = or i8 [[X]], 4
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 4
%icmp = icmp ne i8 %and, 0
%xor = xor i8 %x, 4
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_ne_not_pow2(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_ne_not_pow2(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], 5
; CHECK-NEXT: [[ICMP_NOT:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 5
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP_NOT]], i8 [[X]], i8 [[XOR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%and = and i8 %x, 5
%icmp = icmp ne i8 %and, 0
%xor = xor i8 %x, 5
%sel = select i1 %icmp, i8 %xor, i8 %x
ret i8 %sel
}

define i8 @select_icmp_slt_zero_smin(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_slt_zero_smin(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = or i8 [[X]], -128
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp slt i8 %x, 0
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_slt_zero_smin_flipped(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_slt_zero_smin_flipped(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = and i8 [[X]], 127
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp slt i8 %x, 0
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %xor, i8 %x
ret i8 %sel
}

define i8 @select_icmp_slt_not_zero(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_slt_not_zero(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[ICMP:%.*]] = icmp slt i8 [[X]], 1
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -128
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP]], i8 [[X]], i8 [[XOR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp slt i8 %x, 1
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_slt_not_smin(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_slt_not_smin(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[ICMP:%.*]] = icmp slt i8 [[X]], 0
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -127
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP]], i8 [[X]], i8 [[XOR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp slt i8 %x, 0
%xor = xor i8 %x, -127
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_sgt_allones_smin(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_sgt_allones_smin(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = and i8 [[X]], 127
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp sgt i8 %x, 255
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_sgt_allones_smin_flipped(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_sgt_allones_smin_flipped(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SEL:%.*]] = or i8 [[X]], -128
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp sgt i8 %x, 255
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %xor, i8 %x
ret i8 %sel
}

define i8 @select_icmp_sgt_not_allones(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_sgt_not_allones(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[ICMP:%.*]] = icmp sgt i8 [[X]], -2
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -128
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP]], i8 [[X]], i8 [[XOR]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp sgt i8 %x, 254
%xor = xor i8 %x, -128
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

define i8 @select_icmp_sgt_not_smin(i8 %x) {
; CHECK-LABEL: define i8 @select_icmp_sgt_not_smin(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -127
; CHECK-NEXT: [[ICMP1:%.*]] = icmp slt i8 [[X]], 0
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ICMP1]], i8 [[XOR]], i8 [[X]]
; CHECK-NEXT: ret i8 [[SEL]]
;
%icmp = icmp sgt i8 %x, 255
%xor = xor i8 %x, -127
%sel = select i1 %icmp, i8 %x, i8 %xor
ret i8 %sel
}

0 comments on commit 682fa79

Please sign in to comment.