[InstCombine] narrow width of rotate patterns, part 2 (PR39624)

The sub-pattern for the shift amount in a rotate can take on
several different forms, and there's apparently no way to
canonicalize those without seeing the entire rotate sequence.

This is the form noted in:
https://bugs.llvm.org/show_bug.cgi?id=39624

https://rise4fun.com/Alive/qnT

  %zx = zext i8 %x to i32
  %maskedShAmt = and i32 %shAmt, 7
  %shl = shl i32 %zx, %maskedShAmt
  %negShAmt = sub i32 0, %shAmt
  %maskedNegShAmt = and i32 %negShAmt, 7
  %shr = lshr i32 %zx, %maskedNegShAmt
  %rot = or i32 %shl, %shr
  %r = trunc i32 %rot to i8
  =>
  %truncShAmt = trunc i32 %shAmt to i8
  %maskedShAmt2 = and i8 %truncShAmt, 7
  %shl2 = shl i8 %x, %maskedShAmt2
  %negShAmt2 = sub i8 0, %truncShAmt
  %maskedNegShAmt2 = and i8 %negShAmt2, 7
  %shr2 = lshr i8 %x, %maskedNegShAmt2
  %r = or i8 %shl2, %shr2

llvm-svn: 346713
This commit is contained in:
Sanjay Patel 2018-11-12 22:11:09 +00:00
parent e44a55dc98
commit 98e427ccf2
2 changed files with 36 additions and 32 deletions

View File

@ -522,6 +522,14 @@ Instruction *InstCombiner::narrowRotate(TruncInst &Trunc) {
if (match(R, m_OneUse(m_Sub(m_SpecificInt(Width), m_Specific(L)))))
return L;
// The shift amount may be masked with negation:
// (shl ShVal, (X & (Width - 1))) | (lshr ShVal, ((-X) & (Width - 1)))
Value *X;
unsigned Mask = Width - 1;
if (match(L, m_And(m_Value(X), m_SpecificInt(Mask))) &&
match(R, m_And(m_Neg(m_Specific(X)), m_SpecificInt(Mask))))
return X;
return nullptr;
};

View File

@ -240,14 +240,13 @@ define i8 @rotateright_8_neg_mask_commute(i8 %v, i8 %shamt) {
define i16 @rotateright_16_neg_mask_wide_amount(i16 %v, i32 %shamt) {
; CHECK-LABEL: @rotateright_16_neg_mask_wide_amount(
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT:%.*]]
; CHECK-NEXT: [[RSHAMT:%.*]] = and i32 [[SHAMT]], 15
; CHECK-NEXT: [[LSHAMT:%.*]] = and i32 [[NEG]], 15
; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[V:%.*]] to i32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[LSHAMT]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CONV]], [[RSHAMT]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]]
; CHECK-NEXT: [[RET:%.*]] = trunc i32 [[OR]] to i16
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[SHAMT:%.*]] to i16
; CHECK-NEXT: [[TMP2:%.*]] = sub i16 0, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = and i16 [[TMP1]], 15
; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP2]], 15
; CHECK-NEXT: [[TMP5:%.*]] = lshr i16 [[V:%.*]], [[TMP3]]
; CHECK-NEXT: [[TMP6:%.*]] = shl i16 [[V]], [[TMP4]]
; CHECK-NEXT: [[RET:%.*]] = or i16 [[TMP5]], [[TMP6]]
; CHECK-NEXT: ret i16 [[RET]]
;
%neg = sub i32 0, %shamt
@ -263,14 +262,13 @@ define i16 @rotateright_16_neg_mask_wide_amount(i16 %v, i32 %shamt) {
define i16 @rotateright_16_neg_mask_wide_amount_commute(i16 %v, i32 %shamt) {
; CHECK-LABEL: @rotateright_16_neg_mask_wide_amount_commute(
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT:%.*]]
; CHECK-NEXT: [[RSHAMT:%.*]] = and i32 [[SHAMT]], 15
; CHECK-NEXT: [[LSHAMT:%.*]] = and i32 [[NEG]], 15
; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[V:%.*]] to i32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[LSHAMT]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CONV]], [[RSHAMT]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
; CHECK-NEXT: [[RET:%.*]] = trunc i32 [[OR]] to i16
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[SHAMT:%.*]] to i16
; CHECK-NEXT: [[TMP2:%.*]] = sub i16 0, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = and i16 [[TMP1]], 15
; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP2]], 15
; CHECK-NEXT: [[TMP5:%.*]] = shl i16 [[V:%.*]], [[TMP4]]
; CHECK-NEXT: [[TMP6:%.*]] = lshr i16 [[V]], [[TMP3]]
; CHECK-NEXT: [[RET:%.*]] = or i16 [[TMP5]], [[TMP6]]
; CHECK-NEXT: ret i16 [[RET]]
;
%neg = sub i32 0, %shamt
@ -286,14 +284,13 @@ define i16 @rotateright_16_neg_mask_wide_amount_commute(i16 %v, i32 %shamt) {
define i8 @rotateleft_8_neg_mask_wide_amount(i8 %v, i32 %shamt) {
; CHECK-LABEL: @rotateleft_8_neg_mask_wide_amount(
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT:%.*]]
; CHECK-NEXT: [[LSHAMT:%.*]] = and i32 [[SHAMT]], 7
; CHECK-NEXT: [[RSHAMT:%.*]] = and i32 [[NEG]], 7
; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[V:%.*]] to i32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[LSHAMT]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CONV]], [[RSHAMT]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]]
; CHECK-NEXT: [[RET:%.*]] = trunc i32 [[OR]] to i8
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[SHAMT:%.*]] to i8
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 0, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = and i8 [[TMP1]], 7
; CHECK-NEXT: [[TMP4:%.*]] = and i8 [[TMP2]], 7
; CHECK-NEXT: [[TMP5:%.*]] = lshr i8 [[V:%.*]], [[TMP4]]
; CHECK-NEXT: [[TMP6:%.*]] = shl i8 [[V]], [[TMP3]]
; CHECK-NEXT: [[RET:%.*]] = or i8 [[TMP5]], [[TMP6]]
; CHECK-NEXT: ret i8 [[RET]]
;
%neg = sub i32 0, %shamt
@ -309,14 +306,13 @@ define i8 @rotateleft_8_neg_mask_wide_amount(i8 %v, i32 %shamt) {
define i8 @rotateleft_8_neg_mask_wide_amount_commute(i8 %v, i32 %shamt) {
; CHECK-LABEL: @rotateleft_8_neg_mask_wide_amount_commute(
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[SHAMT:%.*]]
; CHECK-NEXT: [[LSHAMT:%.*]] = and i32 [[SHAMT]], 7
; CHECK-NEXT: [[RSHAMT:%.*]] = and i32 [[NEG]], 7
; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[V:%.*]] to i32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CONV]], [[LSHAMT]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CONV]], [[RSHAMT]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
; CHECK-NEXT: [[RET:%.*]] = trunc i32 [[OR]] to i8
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[SHAMT:%.*]] to i8
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 0, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = and i8 [[TMP1]], 7
; CHECK-NEXT: [[TMP4:%.*]] = and i8 [[TMP2]], 7
; CHECK-NEXT: [[TMP5:%.*]] = shl i8 [[V:%.*]], [[TMP3]]
; CHECK-NEXT: [[TMP6:%.*]] = lshr i8 [[V]], [[TMP4]]
; CHECK-NEXT: [[RET:%.*]] = or i8 [[TMP5]], [[TMP6]]
; CHECK-NEXT: ret i8 [[RET]]
;
%neg = sub i32 0, %shamt