Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3242,6 +3242,73 @@ Builder->getInt(CI->getValue()-1)); } + + // If the immediately dominating branch condition is a sign bit check, + // turn it into the appropriate icmp eq/ne Op0 0 instruction. + if (!I.isEquality()) { + BasicBlock *Parent = I.getParent(); + DomTreeNode *Node = DT ? DT->getNode(Parent) : nullptr; + DomTreeNode *IDomNode = Node ? Node->getIDom() : nullptr; + BasicBlock *IDom = IDomNode ? IDomNode->getBlock() : nullptr; + auto *BI = + IDom ? dyn_cast_or_null(IDom->getTerminator()) : nullptr; + ICmpInst::Predicate Pred; + BasicBlock *TrueBB, *FalseBB; + ConstantInt *CI2; + bool TrueIfSigned = false; + if (BI && + match(BI, m_Br(m_ICmp(Pred, m_Specific(Op0), m_ConstantInt(CI2)), + TrueBB, FalseBB)) && + isSignBitCheck(Pred, CI2, TrueIfSigned)) { + if ((TrueIfSigned && Parent == FalseBB) || + (!TrueIfSigned && Parent == TrueBB)) { + // Also ensure that the edge dominates the compare instruction + // to guarantee that the dominating condition holds in 'Parent'. + BasicBlockEdge Edge(IDom, Parent); + if (Edge.isSingleEdge() && DT->dominates(Edge, Parent)) { + if (CI->isZero()) { + switch (I.getPredicate()) { + default: + break; + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_ULT: + return replaceInstUsesWith(I, Builder->getFalse()); + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_UGT: + return new ICmpInst(ICmpInst::ICMP_NE, Op0, CI); + case ICmpInst::ICMP_SLE: + case ICmpInst::ICMP_ULE: + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, CI); + } + } + if (CI->isOne()) { + switch (I.getPredicate()) { + default: + break; + case ICmpInst::ICMP_SGE: + case ICmpInst::ICMP_UGE: + return new ICmpInst(ICmpInst::ICMP_NE, Op0, + Builder->getInt(CI->getValue() - 1)); + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_ULT: + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + Builder->getInt(CI->getValue() - 1)); + } + } + if (CI->isMinusOne()) { + switch (I.getPredicate()) { + default: + break; + case ICmpInst::ICMP_SLE: + case ICmpInst::ICMP_ULE: + return replaceInstUsesWith(I, Builder->getFalse()); + } + } + } + } + } + } + if (I.isEquality()) { ConstantInt *CI2; if (match(Op0, m_AShr(m_ConstantInt(CI2), m_Value(A))) || Index: test/Transforms/InstCombine/icmp.ll =================================================================== --- test/Transforms/InstCombine/icmp.ll +++ test/Transforms/InstCombine/icmp.ll @@ -1956,3 +1956,77 @@ %cmp = icmp uge i32 %addx, %addy ret i1 %cmp } + +; CHECK-LABEL: @idom_sign_bit_check_edge_dominates +define void @idom_sign_bit_check_edge_dominates(i64 %a) { +entry: + %cmp = icmp slt i64 %a, 0 + br i1 %cmp, label %land.lhs.true, label %lor.rhs + +land.lhs.true: ; preds = %entry + br label %lor.end + +; CHECK-LABEL: lor.rhs: +; CHECK-NOT: icmp sgt i64 %a, 0 +; CHECK: icmp eq i64 %a, 0 +lor.rhs: ; preds = %entry + %cmp2 = icmp sgt i64 %a, 0 + br i1 %cmp2, label %land.rhs, label %lor.end + +land.rhs: ; preds = %lor.rhs + br label %lor.end + +lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true + ret void +} + +; CHECK-LABEL: @idom_sign_bit_check_edge_not_dominates +define void @idom_sign_bit_check_edge_not_dominates(i64 %a) { +entry: + %cmp = icmp slt i64 %a, 0 + br i1 %cmp, label %land.lhs.true, label %lor.rhs + +land.lhs.true: ; preds = %entry + br i1 undef, label %lor.end, label %lor.rhs + +; CHECK-LABEL: lor.rhs: +; CHECK: icmp sgt i64 %a, 0 +; CHECK-NOT: icmp eq i64 %a, 0 +lor.rhs: ; preds = %land.lhs.true, %entry + %cmp2 = icmp sgt i64 %a, 0 + br i1 %cmp2, label %land.rhs, label %lor.end + +land.rhs: ; preds = %lor.rhs + br label %lor.end + +lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true + ret void +} + +; CHECK-LABEL: @idom_sign_bit_check_edge_dominates_select +define void @idom_sign_bit_check_edge_dominates_select(i64 %a, i64 %b) { +entry: + %cmp = icmp slt i64 %a, 0 + br i1 %cmp, label %land.lhs.true, label %lor.rhs + +land.lhs.true: ; preds = %entry + br label %lor.end + +; CHECK-LABEL: lor.rhs: +; CHECK-NOT: [[B:%.*]] = icmp sgt i64 %a, 0 +; CHECK: [[C:%.*]] = icmp eq i64 %a, %b +; CHECK-NOT: [[D:%.*]] = select i1 [[B]], i64 %a, i64 0 +; CHECK-NOT: icmp ne i64 [[D]], %b +; CHECK-NEXT: br i1 [[C]], label %lor.end, label %land.rhs +lor.rhs: ; preds = %entry + %cmp2 = icmp sgt i64 %a, 0 + %select = select i1 %cmp2, i64 %a, i64 0 + %cmp3 = icmp ne i64 %select, %b + br i1 %cmp3, label %land.rhs, label %lor.end + +land.rhs: ; preds = %lor.rhs + br label %lor.end + +lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true + ret void +}