summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp6
-rw-r--r--llvm/test/Transforms/InstCombine/abs-1.ll28
2 files changed, 33 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 368402b57cb..22e7b360d0e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2748,7 +2748,11 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
// xor (add A, B), B ; add -1 and flip bits if negative
// --> (A < 0) ? -A : A
Value *Cmp = Builder.CreateICmpSLT(A, ConstantInt::getNullValue(Ty));
- return SelectInst::Create(Cmp, Builder.CreateNeg(A), A);
+ // Copy the nuw/nsw flags from the add to the negate.
+ auto *Add = cast<BinaryOperator>(Op0);
+ Value *Neg = Builder.CreateNeg(A, "", Add->hasNoUnsignedWrap(),
+ Add->hasNoSignedWrap());
+ return SelectInst::Create(Cmp, Neg, A);
}
// Eliminate a bitwise 'not' op of 'not' min/max by inverting the min/max:
diff --git a/llvm/test/Transforms/InstCombine/abs-1.ll b/llvm/test/Transforms/InstCombine/abs-1.ll
index 5cd5868d67a..96bf555c72e 100644
--- a/llvm/test/Transforms/InstCombine/abs-1.ll
+++ b/llvm/test/Transforms/InstCombine/abs-1.ll
@@ -59,6 +59,34 @@ define i8 @shifty_abs_commute0(i8 %x) {
ret i8 %abs
}
+define i8 @shifty_abs_commute0_nsw(i8 %x) {
+; CHECK-LABEL: @shifty_abs_commute0_nsw(
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 %x, 0
+; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i8 0, %x
+; CHECK-NEXT: [[ABS:%.*]] = select i1 [[TMP1]], i8 [[TMP2]], i8 %x
+; CHECK-NEXT: ret i8 [[ABS]]
+;
+ %signbit = ashr i8 %x, 7
+ %add = add nsw i8 %signbit, %x
+ %abs = xor i8 %add, %signbit
+ ret i8 %abs
+}
+
+; The nuw flag creates a contradiction. If the shift produces all 1s, the only
+; way for the add to not wrap is for %x to be 0, but then the shift couldn't
+; have produced all 1s. We partially optimize this.
+define i8 @shifty_abs_commute0_nuw(i8 %x) {
+; CHECK-LABEL: @shifty_abs_commute0_nuw(
+; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i8 %x, 0
+; CHECK-NEXT: [[ABS:%.*]] = select i1 [[TMP1]], i8 %x, i8 0
+; CHECK-NEXT: ret i8 [[ABS]]
+;
+ %signbit = ashr i8 %x, 7
+ %add = add nuw i8 %signbit, %x
+ %abs = xor i8 %add, %signbit
+ ret i8 %abs
+}
+
define <2 x i8> @shifty_abs_commute1(<2 x i8> %x) {
; CHECK-LABEL: @shifty_abs_commute1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> %x, zeroinitializer
OpenPOWER on IntegriCloud