return BinaryOperator::CreateNSWNeg(
Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
+ // abs(X) / X --> X > -1 ? 1 : -1
+ // X / abs(X) --> X > -1 ? 1 : -1
+ if (match(&I, m_c_BinOp(
+ m_OneUse(m_Intrinsic<Intrinsic::abs>(m_Value(X), m_One())),
+ m_Deferred(X)))) {
+ Constant *NegOne = ConstantInt::getAllOnesValue(Ty);
+ Value *Cond = Builder.CreateICmpSGT(X, NegOne);
+ return SelectInst::Create(Cond, ConstantInt::get(Ty, 1), NegOne);
+ }
+
// If the sign bits of both operands are zero (i.e. we can prove they are
// unsigned inputs), turn this into a udiv.
APInt Mask(APInt::getSignMask(Ty->getScalarSizeInBits()));
define i32 @sdiv_abs_nsw(i32 %x) {
; CHECK-LABEL: @sdiv_abs_nsw(
-; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
-; CHECK-NEXT: [[R:%.*]] = sdiv i32 [[A]], [[X]]
+; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTINV]], i32 1, i32 -1
; CHECK-NEXT: ret i32 [[R]]
;
%a = call i32 @llvm.abs.i32(i32 %x, i1 true)
define <4 x i32> @sdiv_abs_nsw_vec(<4 x i32> %x) {
; CHECK-LABEL: @sdiv_abs_nsw_vec(
-; CHECK-NEXT: [[A:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 true)
-; CHECK-NEXT: [[R:%.*]] = sdiv <4 x i32> [[X]], [[A]]
+; CHECK-NEXT: [[DOTINV:%.*]] = icmp sgt <4 x i32> [[X:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[DOTINV]], <4 x i32> <i32 1, i32 1, i32 1, i32 1>, <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
; CHECK-NEXT: ret <4 x i32> [[R]]
;
%a = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %x, i1 true)
ret <4 x i32> %r
}
+; Negative test - requires poison int min (nsw)
+
define i32 @sdiv_abs(i32 %x) {
; CHECK-LABEL: @sdiv_abs(
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
ret i32 %r
}
+; Negative test
+
define i32 @sdiv_abs_extra_use(i32 %x) {
; CHECK-LABEL: @sdiv_abs_extra_use(
; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)