1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00

[InstCombine] try harder to form rotate (funnel shift) (PR20750)

We have a similar match for patterns ending in a truncate. This
should be ok for all targets because the default expansion would
still likely be better from replacing 2 'and' ops with 1.

Attempt to show the logic equivalence in Alive (which doesn't
currently have funnel-shift in its vocabulary AFAICT):

  %shamt = zext i8 %i to i32
  %m = and i32 %shamt, 31
  %neg = sub i32 0, %shamt
  %and4 = and i32 %neg, 31
  %shl = shl i32 %v, %m
  %shr = lshr i32 %v, %and4
  %or = or i32 %shr, %shl
  =>
  %a = and i8 %i, 31
  %shamt2 = zext i8 %a to i32
  %neg2 = sub i32 0, %shamt2
  %and4 = and i32 %neg2, 31
  %shl = shl i32 %v, %shamt2
  %shr = lshr i32 %v, %and4
  %or = or i32 %shr, %shl

https://rise4fun.com/Alive/V9r

llvm-svn: 360605
This commit is contained in:
Sanjay Patel 2019-05-13 17:28:19 +00:00
parent 31828c19d0
commit c3aa82cda9
2 changed files with 11 additions and 14 deletions

View File

@ -1898,6 +1898,13 @@ static Instruction *matchRotate(Instruction &Or) {
match(R, m_And(m_Neg(m_Specific(X)), m_SpecificInt(Mask))))
return X;
// Similar to above, but the shift amount may be extended after masking,
// so return the extended value as the parameter for the intrinsic.
if (match(L, m_ZExt(m_And(m_Value(X), m_SpecificInt(Mask)))) &&
match(R, m_And(m_Neg(m_ZExt(m_And(m_Specific(X), m_SpecificInt(Mask)))),
m_SpecificInt(Mask))))
return L;
return nullptr;
};

View File

@ -710,13 +710,8 @@ define i32 @rotl_constant_expr(i32 %shamt) {
define i32 @rotateleft32_doubleand1(i32 %v, i8 %r) {
; CHECK-LABEL: @rotateleft32_doubleand1(
; CHECK-NEXT: [[M:%.*]] = and i8 [[R:%.*]], 31
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[M]] to i32
; CHECK-NEXT: [[NEG:%.*]] = sub nsw i32 0, [[Z]]
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NEG]], 31
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[V:%.*]], [[Z]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V]], [[AND2]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]]
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[R:%.*]] to i32
; CHECK-NEXT: [[OR:%.*]] = call i32 @llvm.fshl.i32(i32 [[V:%.*]], i32 [[V]], i32 [[Z]])
; CHECK-NEXT: ret i32 [[OR]]
;
%m = and i8 %r, 31
@ -731,13 +726,8 @@ define i32 @rotateleft32_doubleand1(i32 %v, i8 %r) {
define i32 @rotateright32_doubleand1(i32 %v, i16 %r) {
; CHECK-LABEL: @rotateright32_doubleand1(
; CHECK-NEXT: [[M:%.*]] = and i16 [[R:%.*]], 31
; CHECK-NEXT: [[Z:%.*]] = zext i16 [[M]] to i32
; CHECK-NEXT: [[NEG:%.*]] = sub nsw i32 0, [[Z]]
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NEG]], 31
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[V:%.*]], [[AND2]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V]], [[Z]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[SHL]]
; CHECK-NEXT: [[Z:%.*]] = zext i16 [[R:%.*]] to i32
; CHECK-NEXT: [[OR:%.*]] = call i32 @llvm.fshr.i32(i32 [[V:%.*]], i32 [[V]], i32 [[Z]])
; CHECK-NEXT: ret i32 [[OR]]
;
%m = and i16 %r, 31