diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1644,13 +1644,24 @@ default: break; case Intrinsic::abs: computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q); - // Otherwise, if this call is undefined for INT_MIN, the result is - // positive. - if (match(II->getArgOperand(1), m_One())) - Known.Zero.setSignBit(); + + // If the source's MSB is zero then we know the rest of the bits. + if (Known2.isNonNegative()) { + Known.Zero |= Known2.Zero; + Known.One |= Known2.One; + break; + } + // Absolute value preserves trailing zero count. Known.Zero.setLowBits(Known2.Zero.countTrailingOnes()); - // FIXME: Handle known negative/non-negative input? + + // If this call is undefined for INT_MIN, the result is positive. We + // also know it can't be INT_MIN if there is a set bit that isn't the + // sign bit. + Known2.One.clearSignBit(); + if (match(II->getArgOperand(1), m_One()) || Known2.One.getBoolValue()) + Known.Zero.setSignBit(); + // FIXME: Handle known negative input? // FIXME: Calculate the negated Known bits and combine them? break; case Intrinsic::bitreverse: diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll --- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll +++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll @@ -2,6 +2,7 @@ ; RUN: opt < %s -instcombine -S | FileCheck %s declare i32 @llvm.abs.i32(i32, i1) +declare <4 x i32> @llvm.abs.v4i32(<4 x i32>, i1) define i1 @abs_nsw_must_be_positive(i32 %x) { ; CHECK-LABEL: @abs_nsw_must_be_positive( @@ -12,6 +13,15 @@ ret i1 %c2 } +define <4 x i1> @abs_nsw_must_be_positive_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_nsw_must_be_positive_vec( +; CHECK-NEXT: ret <4 x i1> +; + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %x, i1 true) + %c2 = icmp sge <4 x i32> %abs, zeroinitializer + ret <4 x i1> %c2 +} + ; Negative test, no nsw provides no information about the sign bit of the result. define i1 @abs_nonsw(i32 %x) { ; CHECK-LABEL: @abs_nonsw( @@ -24,6 +34,17 @@ ret i1 %c2 } +define <4 x i1> @abs_nonsw_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_nonsw_vec( +; CHECK-NEXT: [[ABS:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 false) +; CHECK-NEXT: [[C2:%.*]] = icmp sgt <4 x i32> [[ABS]], +; CHECK-NEXT: ret <4 x i1> [[C2]] +; + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %x, i1 false) + %c2 = icmp sge <4 x i32> %abs, zeroinitializer + ret <4 x i1> %c2 +} + ; abs preserves trailing zeros so the second and is unneeded define i32 @abs_trailing_zeros(i32 %x) { ; CHECK-LABEL: @abs_trailing_zeros( @@ -37,6 +58,18 @@ ret i32 %and2 } +define <4 x i32> @abs_trailing_zeros_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_trailing_zeros_vec( +; CHECK-NEXT: [[AND:%.*]] = and <4 x i32> [[X:%.*]], +; CHECK-NEXT: [[ABS:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[AND]], i1 false) +; CHECK-NEXT: ret <4 x i32> [[ABS]] +; + %and = and <4 x i32> %x, + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %and, i1 false) + %and2 = and <4 x i32> %abs, + ret <4 x i32> %and2 +} + ; negative test, can't remove the second and based on trailing zeroes. ; FIXME: Could remove the first and using demanded bits. define i32 @abs_trailing_zeros_negative(i32 %x) { @@ -52,12 +85,25 @@ ret i32 %and2 } +define <4 x i32> @abs_trailing_zeros_negative_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_trailing_zeros_negative_vec( +; CHECK-NEXT: [[AND:%.*]] = and <4 x i32> [[X:%.*]], +; CHECK-NEXT: [[ABS:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[AND]], i1 false) +; CHECK-NEXT: [[AND2:%.*]] = and <4 x i32> [[ABS]], +; CHECK-NEXT: ret <4 x i32> [[AND2]] +; + %and = and <4 x i32> %x, + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %and, i1 false) + %and2 = and <4 x i32> %abs, + ret <4 x i32> %and2 +} + ; Make sure we infer this add doesn't overflow. The input to the abs has 3 ; sign bits, the abs reduces this to 2 sign bits. define i32 @abs_signbits(i30 %x) { ; CHECK-LABEL: @abs_signbits( -; CHECK-NEXT: [[AND:%.*]] = sext i30 [[X:%.*]] to i32 -; CHECK-NEXT: [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[AND]], i1 false) +; CHECK-NEXT: [[EXT:%.*]] = sext i30 [[X:%.*]] to i32 +; CHECK-NEXT: [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[EXT]], i1 false) ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[ABS]], 1 ; CHECK-NEXT: ret i32 [[ADD]] ; @@ -66,3 +112,56 @@ %add = add i32 %abs, 1 ret i32 %add } + +define <4 x i32> @abs_signbits_vec(<4 x i30> %x) { +; CHECK-LABEL: @abs_signbits_vec( +; CHECK-NEXT: [[EXT:%.*]] = sext <4 x i30> [[X:%.*]] to <4 x i32> +; CHECK-NEXT: [[ABS:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[EXT]], i1 false) +; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[ABS]], +; CHECK-NEXT: ret <4 x i32> [[ADD]] +; + %ext = sext <4 x i30> %x to <4 x i32> + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %ext, i1 false) + %add = add <4 x i32> %abs, + ret <4 x i32> %add +} + +define i1 @abs_known_positive_input_compare(i31 %x) { +; CHECK-LABEL: @abs_known_positive_input_compare( +; CHECK-NEXT: ret i1 true +; + %zext = zext i31 %x to i32 + %abs = call i32 @llvm.abs.i32(i32 %zext, i1 false) + %c2 = icmp sge i32 %abs, 0 + ret i1 %c2 +} + +define <4 x i1> @abs_known_positive_input_compare_vec(<4 x i31> %x) { +; CHECK-LABEL: @abs_known_positive_input_compare_vec( +; CHECK-NEXT: ret <4 x i1> +; + %zext = zext <4 x i31> %x to <4 x i32> + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %zext, i1 false) + %c2 = icmp sge <4 x i32> %abs, zeroinitializer + ret <4 x i1> %c2 +} + +define i1 @abs_known_not_int_min(i32 %x) { +; CHECK-LABEL: @abs_known_not_int_min( +; CHECK-NEXT: ret i1 true +; + %or = or i32 %x, 1 + %abs = call i32 @llvm.abs.i32(i32 %or, i1 false) + %c2 = icmp sge i32 %abs, 0 + ret i1 %c2 +} + +define <4 x i1> @abs_known_not_int_min_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_known_not_int_min_vec( +; CHECK-NEXT: ret <4 x i1> +; + %or = or <4 x i32> %x, + %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %or, i1 false) + %c2 = icmp sge <4 x i32> %abs, zeroinitializer + ret <4 x i1> %c2 +}