diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 1859dad4ec00b..1a3355cb42edb 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -7602,6 +7602,51 @@ Instruction *InstCombinerImpl::foldICmpCommutative(CmpPredicate Pred, } } + // abs(X) u> K --> K >= 0 ? `X + K u> 2 * K` : `false` + // If abs(INT_MIN) is poison: + // abs(X) u< K --> K >= 1 ? `X + (K - 1) u<= 2 * (K - 1)` : K != 0 + { + Value *X; + ConstantInt *C, *K; + bool Frozen = false; + if ((match(Op0, + m_Intrinsic(m_Value(X), m_ConstantInt(C))) || + (Frozen = match(Op0, m_Freeze(m_Intrinsic( + m_Value(X), m_ConstantInt(C)))))) && + match(Op1, m_ConstantInt(K))) { + const APInt KValue = K->getValue(); + + if (Pred == CmpInst::ICMP_UGT) { + if (KValue.isNegative()) + return replaceInstUsesWith(CxtI, + ConstantInt::getFalse(CxtI.getType())); + + Value *XPlusK = Builder.CreateAdd(X, K); + if (Frozen) + XPlusK = Builder.CreateFreeze(XPlusK); + return replaceInstUsesWith( + CxtI, Builder.CreateICmpUGT( + XPlusK, ConstantInt::get(K->getType(), 2 * KValue))); + } + + if (Pred == CmpInst::ICMP_ULT && !C->getValue().isZero()) { + if (KValue.slt(1)) + return replaceInstUsesWith( + CxtI, KValue.isZero() ? ConstantInt::getFalse(CxtI.getType()) + : ConstantInt::getTrue(CxtI.getType())); + + Value *XPlusKDec = + Builder.CreateAdd(X, ConstantInt::get(K->getType(), KValue - 1)); + if (Frozen) + XPlusKDec = Builder.CreateFreeze(XPlusKDec); + return replaceInstUsesWith( + CxtI, + Builder.CreateICmpULE( + XPlusKDec, ConstantInt::get(K->getType(), 2 * (KValue - 1)))); + } + } + } + const SimplifyQuery Q = SQ.getWithInstruction(&CxtI); if (Value *V = foldICmpWithLowBitMaskedVal(Pred, Op0, Op1, Q, *this)) return replaceInstUsesWith(CxtI, V); diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll index 763d82652dd5d..7355a7a71dada 100644 --- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll +++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll @@ -997,3 +997,99 @@ define i8 @abs_diff_sle_y_x(i8 %x, i8 %y) { %cond = select i1 %cmp, i8 %sub, i8 %sub1 ret i8 %cond } + +define i1 @abs_cmp_ule_no_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ule_no_poison( +; CHECK-NEXT: [[X_ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X_ABS]], 32 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 0) + %cmp = icmp ule i32 %x.abs, 31 + ret i1 %cmp +} + +define i1 @abs_cmp_ule_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ule_poison( +; CHECK-NEXT: [[X_ABS_FREEZE:%.*]] = freeze i32 [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X_ABS_FREEZE]], 31 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 63 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 1) + %x.abs.freeze = freeze i32 %x.abs + %cmp = icmp ule i32 %x.abs.freeze, 31 + ret i1 %cmp +} + +define i1 @abs_cmp_ult_no_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ult_no_poison( +; CHECK-NEXT: [[X_ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X_ABS]], 32 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 0) + %cmp = icmp ult i32 %x.abs, 32 + ret i1 %cmp +} + +define i1 @abs_cmp_ult_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ult_poison( +; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X_FR]], 31 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 63 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 1) + %x.abs.freeze = freeze i32 %x.abs + %cmp = icmp ult i32 %x.abs.freeze, 32 + ret i1 %cmp +} + +define i1 @abs_cmp_uge_no_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_uge_no_poison( +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -31 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -61 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 0) + %cmp = icmp ugt i32 %x.abs, 30 + ret i1 %cmp +} + +define i1 @abs_cmp_uge_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_uge_poison( +; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X_FR]], -31 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -61 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 1) + %x.abs.freeze = freeze i32 %x.abs + %cmp = icmp ugt i32 %x.abs.freeze, 30 + ret i1 %cmp +} + +define i1 @abs_cmp_ugt_no_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ugt_no_poison( +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -63 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 0) + %cmp = icmp ugt i32 %x.abs, 31 + ret i1 %cmp +} + +define i1 @abs_cmp_ugt_poison(i32 %x) { +; CHECK-LABEL: @abs_cmp_ugt_poison( +; CHECK-NEXT: [[X:%.*]] = freeze i32 [[X1:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -63 +; CHECK-NEXT: ret i1 [[CMP]] +; + %x.abs = call i32 @llvm.abs.i32(i32 %x, i1 1) + %x.abs.freeze = freeze i32 %x.abs + %cmp = icmp ugt i32 %x.abs.freeze, 31 + ret i1 %cmp +}