Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2397,5 +2397,25 @@ if (Instruction *CastedXor = foldCastedBitwiseLogic(I)) return CastedXor; + // Canonicalize the shifty way to code absolute value to the common pattern. + // There are 4 potential commuted variants. Move the 'ashr' candidate to Op1. + // We're relying on the fact that we only do this transform when the shift has + // exactly 2 uses and the add has exactly 1 use (otherwise, we might increase + // instructions). + if (Op0->getNumUses() == 2) + std::swap(Op0, Op1); + + const APInt *ShAmt; + Type *Ty = I.getType(); + if (match(Op1, m_AShr(m_Value(A), m_APInt(ShAmt))) && + Op1->getNumUses() == 2 && *ShAmt == Ty->getScalarSizeInBits() - 1 && + match(Op0, m_OneUse(m_c_Add(m_Specific(A), m_Specific(Op1))))) { + // B = ashr i32 A, 31 ; smear the sign bit + // 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); + } + return Changed ? &I : nullptr; } Index: test/Transforms/InstCombine/abs-1.ll =================================================================== --- test/Transforms/InstCombine/abs-1.ll +++ test/Transforms/InstCombine/abs-1.ll @@ -48,9 +48,9 @@ define i8 @shifty_abs_commute0(i8 %x) { ; CHECK-LABEL: @shifty_abs_commute0( -; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 %x, 7 -; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SIGNBIT]], %x -; CHECK-NEXT: [[ABS:%.*]] = xor i8 [[ADD]], [[SIGNBIT]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 %x, 0 +; CHECK-NEXT: [[TMP2:%.*]] = sub i8 0, %x +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[TMP1]], i8 [[TMP2]], i8 %x ; CHECK-NEXT: ret i8 [[ABS]] ; %signbit = ashr i8 %x, 7 @@ -61,9 +61,9 @@ define <2 x i8> @shifty_abs_commute1(<2 x i8> %x) { ; CHECK-LABEL: @shifty_abs_commute1( -; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i8> %x, -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[SIGNBIT]], %x -; CHECK-NEXT: [[ABS:%.*]] = xor <2 x i8> [[SIGNBIT]], [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> %x, zeroinitializer +; CHECK-NEXT: [[TMP2:%.*]] = sub <2 x i8> zeroinitializer, %x +; CHECK-NEXT: [[ABS:%.*]] = select <2 x i1> [[TMP1]], <2 x i8> [[TMP2]], <2 x i8> %x ; CHECK-NEXT: ret <2 x i8> [[ABS]] ; %signbit = ashr <2 x i8> %x, @@ -75,9 +75,9 @@ define <2 x i8> @shifty_abs_commute2(<2 x i8> %x) { ; CHECK-LABEL: @shifty_abs_commute2( ; CHECK-NEXT: [[Y:%.*]] = mul <2 x i8> %x, -; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i8> [[Y]], -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[Y]], [[SIGNBIT]] -; CHECK-NEXT: [[ABS:%.*]] = xor <2 x i8> [[SIGNBIT]], [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[Y]], zeroinitializer +; CHECK-NEXT: [[TMP2:%.*]] = sub <2 x i8> zeroinitializer, [[Y]] +; CHECK-NEXT: [[ABS:%.*]] = select <2 x i1> [[TMP1]], <2 x i8> [[TMP2]], <2 x i8> [[Y]] ; CHECK-NEXT: ret <2 x i8> [[ABS]] ; %y = mul <2 x i8> %x, ; extra op to thwart complexity-based canonicalization @@ -90,9 +90,9 @@ define i8 @shifty_abs_commute3(i8 %x) { ; CHECK-LABEL: @shifty_abs_commute3( ; CHECK-NEXT: [[Y:%.*]] = mul i8 %x, 3 -; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[Y]], 7 -; CHECK-NEXT: [[ADD:%.*]] = add i8 [[Y]], [[SIGNBIT]] -; CHECK-NEXT: [[ABS:%.*]] = xor i8 [[ADD]], [[SIGNBIT]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[Y]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = sub i8 0, [[Y]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[TMP1]], i8 [[TMP2]], i8 [[Y]] ; CHECK-NEXT: ret i8 [[ABS]] ; %y = mul i8 %x, 3 ; extra op to thwart complexity-based canonicalization