Skip to content

Commit

Permalink
[InstCombine] Perform "eq of parts" fold with logical ops
Browse files Browse the repository at this point in the history
The pattern matched here is too complex for the general logical
and/or to bitwise and/or conversion to trigger. However, the
fold is poison-safe, so match it with a select root as well:

https://alive2.llvm.org/ce/z/vNzzSg
https://alive2.llvm.org/ce/z/Beyumt
  • Loading branch information
nikic committed Aug 22, 2021
1 parent be4b836 commit fafe5a6
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 30 deletions.
8 changes: 4 additions & 4 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,8 +1113,8 @@ static Value *extractIntPart(const IntPart &P, IRBuilderBase &Builder) {
/// (icmp eq X0, Y0) & (icmp eq X1, Y1) -> icmp eq X01, Y01
/// (icmp ne X0, Y0) | (icmp ne X1, Y1) -> icmp ne X01, Y01
/// where X0, X1 and Y0, Y1 are adjacent parts extracted from an integer.
static Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd,
InstCombiner::BuilderTy &Builder) {
Value *InstCombinerImpl::foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1,
bool IsAnd) {
if (!Cmp0->hasOneUse() || !Cmp1->hasOneUse())
return nullptr;

Expand Down Expand Up @@ -1262,7 +1262,7 @@ Value *InstCombinerImpl::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS,
foldUnsignedUnderflowCheck(RHS, LHS, /*IsAnd=*/true, Q, Builder))
return X;

if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/true, Builder))
if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/true))
return X;

// This only handles icmp of constants: (icmp1 A, C1) & (icmp2 B, C2).
Expand Down Expand Up @@ -2496,7 +2496,7 @@ Value *InstCombinerImpl::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
foldUnsignedUnderflowCheck(RHS, LHS, /*IsAnd=*/false, Q, Builder))
return X;

if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/false, Builder))
if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/false))
return X;

// (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0)
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &Or);
Value *foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &Xor);

Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd);

/// Optimize (fcmp)&(fcmp) or (fcmp)|(fcmp).
/// NOTE: Unlike most of instcombine, this returns a Value which should
/// already be inserted into the function.
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2755,11 +2755,16 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
/* IsAnd */ IsAnd))
return I;

if (auto *ICmp0 = dyn_cast<ICmpInst>(CondVal))
if (auto *ICmp1 = dyn_cast<ICmpInst>(Op1))
if (auto *ICmp0 = dyn_cast<ICmpInst>(CondVal)) {
if (auto *ICmp1 = dyn_cast<ICmpInst>(Op1)) {
if (auto *V = foldAndOrOfICmpsOfAndWithPow2(ICmp0, ICmp1, &SI, IsAnd,
/* IsLogical */ true))
return replaceInstUsesWith(SI, V);

if (auto *V = foldEqOfParts(ICmp0, ICmp1, IsAnd))
return replaceInstUsesWith(SI, V);
}
}
}

// select (select a, true, b), c, false -> select a, c, false
Expand Down
36 changes: 12 additions & 24 deletions llvm/test/Transforms/InstCombine/eq-of-parts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -356,18 +356,12 @@ define i1 @eq_21_extra_use_eq2(i32 %x, i32 %y) {

define i1 @eq_21_logical(i32 %x, i32 %y) {
; CHECK-LABEL: @eq_21_logical(
; CHECK-NEXT: [[X_321:%.*]] = lshr i32 [[X:%.*]], 8
; CHECK-NEXT: [[X_1:%.*]] = trunc i32 [[X_321]] to i8
; CHECK-NEXT: [[X_32:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: [[X_2:%.*]] = trunc i32 [[X_32]] to i8
; CHECK-NEXT: [[Y_321:%.*]] = lshr i32 [[Y:%.*]], 8
; CHECK-NEXT: [[Y_1:%.*]] = trunc i32 [[Y_321]] to i8
; CHECK-NEXT: [[Y_32:%.*]] = lshr i32 [[Y]], 16
; CHECK-NEXT: [[Y_2:%.*]] = trunc i32 [[Y_32]] to i8
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i8 [[X_1]], [[Y_1]]
; CHECK-NEXT: [[C_2:%.*]] = icmp eq i8 [[X_2]], [[Y_2]]
; CHECK-NEXT: [[C_210:%.*]] = select i1 [[C_2]], i1 [[C_1]], i1 false
; CHECK-NEXT: ret i1 [[C_210]]
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 8
; CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[Y:%.*]], 8
; CHECK-NEXT: [[TMP4:%.*]] = trunc i32 [[TMP3]] to i16
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i16 [[TMP2]], [[TMP4]]
; CHECK-NEXT: ret i1 [[TMP5]]
;
%x.321 = lshr i32 %x, 8
%x.1 = trunc i32 %x.321 to i8
Expand Down Expand Up @@ -1027,18 +1021,12 @@ define i1 @ne_21_extra_use_ne2(i32 %x, i32 %y) {

define i1 @ne_21_logical(i32 %x, i32 %y) {
; CHECK-LABEL: @ne_21_logical(
; CHECK-NEXT: [[X_321:%.*]] = lshr i32 [[X:%.*]], 8
; CHECK-NEXT: [[X_1:%.*]] = trunc i32 [[X_321]] to i8
; CHECK-NEXT: [[X_32:%.*]] = lshr i32 [[X]], 16
; CHECK-NEXT: [[X_2:%.*]] = trunc i32 [[X_32]] to i8
; CHECK-NEXT: [[Y_321:%.*]] = lshr i32 [[Y:%.*]], 8
; CHECK-NEXT: [[Y_1:%.*]] = trunc i32 [[Y_321]] to i8
; CHECK-NEXT: [[Y_32:%.*]] = lshr i32 [[Y]], 16
; CHECK-NEXT: [[Y_2:%.*]] = trunc i32 [[Y_32]] to i8
; CHECK-NEXT: [[C_1:%.*]] = icmp ne i8 [[X_1]], [[Y_1]]
; CHECK-NEXT: [[C_2:%.*]] = icmp ne i8 [[X_2]], [[Y_2]]
; CHECK-NEXT: [[C_210:%.*]] = select i1 [[C_2]], i1 true, i1 [[C_1]]
; CHECK-NEXT: ret i1 [[C_210]]
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 8
; CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[Y:%.*]], 8
; CHECK-NEXT: [[TMP4:%.*]] = trunc i32 [[TMP3]] to i16
; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i16 [[TMP2]], [[TMP4]]
; CHECK-NEXT: ret i1 [[TMP5]]
;
%x.321 = lshr i32 %x, 8
%x.1 = trunc i32 %x.321 to i8
Expand Down

0 comments on commit fafe5a6

Please sign in to comment.