}
}
+ // A funnel shift (rotate) can be decomposed into simpler shifts. See if we
+ // are mixing in another shift that is redundant with the funnel shift.
+
+ // (fshl X, ?, Y) | (shl X, Y) --> fshl X, ?, Y
+ // (shl X, Y) | (fshl X, ?, Y) --> fshl X, ?, Y
+ if (match(Op0,
+ m_Intrinsic<Intrinsic::fshl>(m_Value(X), m_Value(), m_Value(Y))) &&
+ match(Op1, m_Shl(m_Specific(X), m_Specific(Y))))
+ return Op0;
+ if (match(Op1,
+ m_Intrinsic<Intrinsic::fshl>(m_Value(X), m_Value(), m_Value(Y))) &&
+ match(Op0, m_Shl(m_Specific(X), m_Specific(Y))))
+ return Op1;
+
+ // (fshr ?, X, Y) | (lshr X, Y) --> fshr ?, X, Y
+ // (lshr X, Y) | (fshr ?, X, Y) --> fshr ?, X, Y
+ if (match(Op0,
+ m_Intrinsic<Intrinsic::fshr>(m_Value(), m_Value(X), m_Value(Y))) &&
+ match(Op1, m_LShr(m_Specific(X), m_Specific(Y))))
+ return Op0;
+ if (match(Op1,
+ m_Intrinsic<Intrinsic::fshr>(m_Value(), m_Value(X), m_Value(Y))) &&
+ match(Op0, m_LShr(m_Specific(X), m_Specific(Y))))
+ return Op1;
+
if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, false))
return V;
define i32 @or_shl_fshl(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_shl_fshl(
-; CHECK-NEXT: [[SHY:%.*]] = shl i32 [[Y:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y]], i32 [[X:%.*]], i32 [[S]])
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[FUN]], [[SHY]]
-; CHECK-NEXT: ret i32 [[OR]]
+; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y:%.*]], i32 [[X:%.*]], i32 [[S:%.*]])
+; CHECK-NEXT: ret i32 [[FUN]]
;
%shy = shl i32 %y, %s
%fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s)
define i32 @or_shl_fshl_commute(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_shl_fshl_commute(
-; CHECK-NEXT: [[SHY:%.*]] = shl i32 [[Y:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y]], i32 [[X:%.*]], i32 [[S]])
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHY]], [[FUN]]
-; CHECK-NEXT: ret i32 [[OR]]
+; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y:%.*]], i32 [[X:%.*]], i32 [[S:%.*]])
+; CHECK-NEXT: ret i32 [[FUN]]
;
%shy = shl i32 %y, %s
%fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s)
ret i32 %or
}
+; negative test - fshl operands are not commutative
+
define i32 @or_shl_fshl_wrong_order(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_shl_fshl_wrong_order(
; CHECK-NEXT: [[SHY:%.*]] = shl i32 [[Y:%.*]], [[S:%.*]]
define i32 @or_lshr_fshr(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_lshr_fshr(
-; CHECK-NEXT: [[SHY:%.*]] = lshr i32 [[Y:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[Y]], i32 [[S]])
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[FUN]], [[SHY]]
-; CHECK-NEXT: ret i32 [[OR]]
+; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[S:%.*]])
+; CHECK-NEXT: ret i32 [[FUN]]
;
%shy = lshr i32 %y, %s
%fun = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %s)
define i32 @or_lshr_fshr_commute(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_lshr_fshr_commute(
-; CHECK-NEXT: [[SHY:%.*]] = lshr i32 [[Y:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[Y]], i32 [[S]])
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHY]], [[FUN]]
-; CHECK-NEXT: ret i32 [[OR]]
+; CHECK-NEXT: [[FUN:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[S:%.*]])
+; CHECK-NEXT: ret i32 [[FUN]]
;
%shy = lshr i32 %y, %s
%fun = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %s)
ret i32 %or
}
+; negative test - fshr operands are not commutative
+
define i32 @or_lshr_fshr_wrong_order(i32 %x, i32 %y, i32 %s) {
; CHECK-LABEL: @or_lshr_fshr_wrong_order(
; CHECK-NEXT: [[SHY:%.*]] = lshr i32 [[Y:%.*]], [[S:%.*]]