Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2748,7 +2748,11 @@ // 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(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: Index: llvm/trunk/test/Transforms/InstCombine/abs-1.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/abs-1.ll +++ llvm/trunk/test/Transforms/InstCombine/abs-1.ll @@ -59,6 +59,34 @@ 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