Skip to content

Commit 583fba3

Browse files
actinksdtcxzyw
andauthored
[InstCombine] fold icmp of select with invertible shl (#147182)
Proof: https://alive2.llvm.org/ce/z/a5fzlJ Closes #146642 --------- Co-authored-by: Yingwei Zheng <[email protected]>
1 parent 06c8ee6 commit 583fba3

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5886,6 +5886,12 @@ static void collectOffsetOp(Value *V, SmallVectorImpl<OffsetOp> &Offsets,
58865886
Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1));
58875887
Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0));
58885888
break;
5889+
case Instruction::Shl:
5890+
if (Inst->hasNoSignedWrap())
5891+
Offsets.emplace_back(Instruction::AShr, Inst->getOperand(1));
5892+
if (Inst->hasNoUnsignedWrap())
5893+
Offsets.emplace_back(Instruction::LShr, Inst->getOperand(1));
5894+
break;
58895895
case Instruction::Select:
58905896
if (AllowRecursion) {
58915897
collectOffsetOp(Inst->getOperand(1), Offsets, /*AllowRecursion=*/false);
@@ -5942,9 +5948,31 @@ static Instruction *foldICmpEqualityWithOffset(ICmpInst &I,
59425948
collectOffsetOp(Op1, OffsetOps, /*AllowRecursion=*/true);
59435949

59445950
auto ApplyOffsetImpl = [&](Value *V, unsigned BinOpc, Value *RHS) -> Value * {
5951+
switch (BinOpc) {
5952+
// V = shl nsw X, RHS => X = ashr V, RHS
5953+
case Instruction::AShr: {
5954+
const APInt *CV, *CRHS;
5955+
if (!(match(V, m_APInt(CV)) && match(RHS, m_APInt(CRHS)) &&
5956+
CV->ashr(*CRHS).shl(*CRHS) == *CV) &&
5957+
!match(V, m_NSWShl(m_Value(), m_Specific(RHS))))
5958+
return nullptr;
5959+
break;
5960+
}
5961+
// V = shl nuw X, RHS => X = lshr V, RHS
5962+
case Instruction::LShr: {
5963+
const APInt *CV, *CRHS;
5964+
if (!(match(V, m_APInt(CV)) && match(RHS, m_APInt(CRHS)) &&
5965+
CV->lshr(*CRHS).shl(*CRHS) == *CV) &&
5966+
!match(V, m_NUWShl(m_Value(), m_Specific(RHS))))
5967+
return nullptr;
5968+
break;
5969+
}
5970+
default:
5971+
break;
5972+
}
5973+
59455974
Value *Simplified = simplifyBinOp(BinOpc, V, RHS, SQ);
5946-
// Avoid infinite loops by checking if RHS is an identity for the BinOp.
5947-
if (!Simplified || Simplified == V)
5975+
if (!Simplified)
59485976
return nullptr;
59495977
// Reject constant expressions as they don't simplify things.
59505978
if (isa<Constant>(Simplified) && !match(Simplified, m_ImmConstant()))

llvm/test/Transforms/InstCombine/icmp-select.ll

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,3 +835,120 @@ define i1 @discr_eq_constantexpr(ptr %p) {
835835
%cmp = icmp eq i64 %sub, -1
836836
ret i1 %cmp
837837
}
838+
839+
define i1 @shl_nsw_eq_simplify_zero_to_self(i8 %a, i1 %cond) {
840+
; CHECK-LABEL: @shl_nsw_eq_simplify_zero_to_self(
841+
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[COND:%.*]] to i8
842+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
843+
; CHECK-NEXT: ret i1 [[CMP]]
844+
;
845+
%shl = shl nsw i8 %a, 3
846+
%sel = select i1 %cond, i8 8, i8 0
847+
%cmp = icmp eq i8 %shl, %sel
848+
ret i1 %cmp
849+
}
850+
851+
define i1 @shl_nsw_eq(i8 %a, i1 %cond) {
852+
; CHECK-LABEL: @shl_nsw_eq(
853+
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 -15
854+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
855+
; CHECK-NEXT: ret i1 [[CMP]]
856+
;
857+
%shl = shl nsw i8 %a, 3
858+
%sel = select i1 %cond, i8 8, i8 -120
859+
%cmp = icmp eq i8 %shl, %sel
860+
ret i1 %cmp
861+
}
862+
863+
define i1 @shl_nuw_eq(i8 %a, i1 %cond) {
864+
; CHECK-LABEL: @shl_nuw_eq(
865+
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 17
866+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
867+
; CHECK-NEXT: ret i1 [[CMP]]
868+
;
869+
%shl = shl nuw i8 %a, 3
870+
%sel = select i1 %cond, i8 8, i8 -120
871+
%cmp = icmp eq i8 %shl, %sel
872+
ret i1 %cmp
873+
}
874+
875+
define i1 @shl_nsw_failed_to_simplify(i8 %a, i1 %cond) {
876+
; CHECK-LABEL: @shl_nsw_failed_to_simplify(
877+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[A:%.*]], 1
878+
; CHECK-NEXT: [[NOT_COND:%.*]] = xor i1 [[COND:%.*]], true
879+
; CHECK-NEXT: [[CMP:%.*]] = select i1 [[NOT_COND]], i1 [[CMP1]], i1 false
880+
; CHECK-NEXT: ret i1 [[CMP]]
881+
;
882+
%shl = shl nsw i8 %a, 4
883+
%sel = select i1 %cond, i8 8, i8 16
884+
%cmp = icmp eq i8 %shl, %sel
885+
ret i1 %cmp
886+
}
887+
888+
define i1 @shl_nuw_failed_to_simplify(i8 %a, i1 %cond) {
889+
; CHECK-LABEL: @shl_nuw_failed_to_simplify(
890+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[A:%.*]], 4
891+
; CHECK-NEXT: [[NOT_COND:%.*]] = xor i1 [[COND:%.*]], true
892+
; CHECK-NEXT: [[CMP:%.*]] = select i1 [[NOT_COND]], i1 [[CMP1]], i1 false
893+
; CHECK-NEXT: ret i1 [[CMP]]
894+
;
895+
%shl = shl nuw i8 %a, 3
896+
%sel = select i1 %cond, i8 -1, i8 32
897+
%cmp = icmp eq i8 %shl, %sel
898+
ret i1 %cmp
899+
}
900+
901+
define i1 @shl_failed_to_simplify(i8 %a, i1 %cond) {
902+
; CHECK-LABEL: @shl_failed_to_simplify(
903+
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[A:%.*]], 3
904+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i8 8, i8 32
905+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL]], [[SEL]]
906+
; CHECK-NEXT: ret i1 [[CMP]]
907+
;
908+
%shl = shl i8 %a, 3
909+
%sel = select i1 %cond, i8 8, i8 32
910+
%cmp = icmp eq i8 %shl, %sel
911+
ret i1 %cmp
912+
}
913+
914+
define i1 @shl_nuw_ne(i8 %a, i8 %b, i8 %c, i1 %cond) {
915+
; CHECK-LABEL: @shl_nuw_ne(
916+
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 [[B:%.*]], i8 4
917+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], [[A:%.*]]
918+
; CHECK-NEXT: ret i1 [[CMP]]
919+
;
920+
%shl_a = shl nuw i8 %a, 3
921+
%shl_b = shl nuw i8 %b, 3
922+
%sel = select i1 %cond, i8 %shl_b, i8 32
923+
%cmp = icmp ne i8 %sel, %shl_a
924+
ret i1 %cmp
925+
}
926+
927+
define i1 @shl_const_phi_failed_to_simplify(i64 %indvars, i32 %conv) {
928+
; CHECK-LABEL: @shl_const_phi_failed_to_simplify(
929+
; CHECK-NEXT: entry:
930+
; CHECK-NEXT: [[CMP_SLT:%.*]] = icmp slt i64 [[INDVARS:%.*]], 1
931+
; CHECK-NEXT: br i1 [[CMP_SLT]], label [[END:%.*]], label [[THEN:%.*]]
932+
; CHECK: then:
933+
; CHECK-NEXT: br label [[END]]
934+
; CHECK: end:
935+
; CHECK-NEXT: [[CONST_PHI:%.*]] = phi i32 [ 0, [[THEN]] ], [ 65535, [[ENTRY:%.*]] ]
936+
; CHECK-NEXT: [[SHL_NUW:%.*]] = shl nuw i32 [[CONV:%.*]], 31
937+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP_SLT]], i32 [[CONST_PHI]], i32 [[SHL_NUW]]
938+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[SEL]], 0
939+
; CHECK-NEXT: ret i1 [[CMP]]
940+
;
941+
entry:
942+
%cmp_slt = icmp slt i64 %indvars, 1
943+
br i1 %cmp_slt, label %end, label %then
944+
945+
then:
946+
br label %end
947+
948+
end:
949+
%const_phi = phi i32 [ 0, %then ], [ 65535, %entry ]
950+
%shl_nuw = shl nuw i32 %conv, 31
951+
%sel = select i1 %cmp_slt, i32 %const_phi, i32 %shl_nuw
952+
%cmp = icmp eq i32 %sel, 0
953+
ret i1 %cmp
954+
}

0 commit comments

Comments
 (0)