Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1429,11 +1429,19 @@ bool OrOfShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) && match(Op1, m_LogicalShift(m_Value(), m_Value())); - // (A & B) | (C & D) -> bswap if possible. - bool OrOfAnds = match(Op0, m_And(m_Value(), m_Value())) && - match(Op1, m_And(m_Value(), m_Value())); - - if (!OrOfOrs && !OrOfShifts && !OrOfAnds) + // (A << B) | (C & D) -> bswap if possible. + // The bigger pattern here is ((A & C1) << C2) | ((B >> C2) & C1), which is a + // part of the bswap idiom for specific values of C1, C2 (e.g. C1 = 16711935, + // C2 = 8 for i32). + // Note the different canonic forms for 'shl's and 'shr's. For each of them + // the canonic form is set such that the 'and' constants are minimal (the + // 'and' is before the shift for 'shl' and after the shift for 'shr'). + bool OrOfShiftAndAnd = (match(Op0, m_And(m_Value(), m_Value())) && + match(Op1, m_LogicalShift(m_Value(), m_Value()))) || + (match(Op0, m_LogicalShift(m_Value(), m_Value())) && + match(Op1, m_And(m_Value(), m_Value()))); + + if (!OrOfOrs && !OrOfShifts && !OrOfShiftAndAnd) return nullptr; SmallVector Insts; Index: test/Transforms/InstCombine/bswap.ll =================================================================== --- test/Transforms/InstCombine/bswap.ll +++ test/Transforms/InstCombine/bswap.ll @@ -98,14 +98,7 @@ ; PR23863 define i32 @test7(i32 %x) { ; CHECK-LABEL: @test7( -; CHECK-NEXT: [[SHL:%.*]] = shl i32 %x, 16 -; CHECK-NEXT: [[SHR:%.*]] = lshr i32 %x, 16 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] -; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[OR]], 16711935 -; CHECK-NEXT: [[SHL3:%.*]] = shl nuw i32 [[TMP1]], 8 -; CHECK-NEXT: [[AND4:%.*]] = lshr i32 [[OR]], 8 -; CHECK-NEXT: [[SHR5:%.*]] = and i32 [[AND4]], 16711935 -; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHL3]], [[SHR5]] +; CHECK-NEXT: [[OR6:%.*]] = call i32 @llvm.bswap.i32(i32 %x) ; CHECK-NEXT: ret i32 [[OR6]] ; %shl = shl i32 %x, 16 @@ -148,13 +141,9 @@ define i16 @test10(i32 %a) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 %a, 8 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[SHR1]], 255 -; CHECK-NEXT: [[TMP1:%.*]] = and i32 %a, 255 -; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[TMP1]], 8 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND1]], [[SHL1]] -; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[OR]] to i16 -; CHECK-NEXT: ret i16 [[CONV]] +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %a to i16 +; CHECK-NEXT: [[REV:%.*]] = call i16 @llvm.bswap.i16(i16 [[TRUNC]]) +; CHECK-NEXT: ret i16 [[REV]] ; %shr1 = lshr i32 %a, 8 %and1 = and i32 %shr1, 255