@@ -555,6 +555,10 @@ namespace {
555
555
SDValue InnerPos, SDValue InnerNeg,
556
556
unsigned PosOpcode, unsigned NegOpcode,
557
557
const SDLoc &DL);
558
+ SDValue MatchFunnelPosNeg(SDValue N0, SDValue N1, SDValue Pos, SDValue Neg,
559
+ SDValue InnerPos, SDValue InnerNeg,
560
+ unsigned PosOpcode, unsigned NegOpcode,
561
+ const SDLoc &DL);
558
562
SDValue MatchRotate(SDValue LHS, SDValue RHS, const SDLoc &DL);
559
563
SDValue MatchLoadCombine(SDNode *N);
560
564
SDValue MatchStoreCombine(StoreSDNode *N);
@@ -6319,6 +6323,33 @@ SDValue DAGCombiner::MatchRotatePosNeg(SDValue Shifted, SDValue Pos,
6319
6323
return SDValue();
6320
6324
}
6321
6325
6326
+ // A subroutine of MatchRotate used once we have found an OR of two opposite
6327
+ // shifts of N0 + N1. If Neg == <operand size> - Pos then the OR reduces
6328
+ // to both (PosOpcode N0, N1, Pos) and (NegOpcode N0, N1, Neg), with the
6329
+ // former being preferred if supported. InnerPos and InnerNeg are Pos and
6330
+ // Neg with outer conversions stripped away.
6331
+ // TODO: Merge with MatchRotatePosNeg.
6332
+ SDValue DAGCombiner::MatchFunnelPosNeg(SDValue N0, SDValue N1, SDValue Pos,
6333
+ SDValue Neg, SDValue InnerPos,
6334
+ SDValue InnerNeg, unsigned PosOpcode,
6335
+ unsigned NegOpcode, const SDLoc &DL) {
6336
+ // fold (or (shl x0, (*ext y)),
6337
+ // (srl x1, (*ext (sub 32, y)))) ->
6338
+ // (fshl x0, x1, y) or (fshr x0, x1, (sub 32, y))
6339
+ //
6340
+ // fold (or (shl x0, (*ext (sub 32, y))),
6341
+ // (srl x1, (*ext y))) ->
6342
+ // (fshr x0, x1, y) or (fshl x0, x1, (sub 32, y))
6343
+ EVT VT = N0.getValueType();
6344
+ if (matchRotateSub(InnerPos, InnerNeg, VT.getScalarSizeInBits(), DAG)) {
6345
+ bool HasPos = TLI.isOperationLegalOrCustom(PosOpcode, VT);
6346
+ return DAG.getNode(HasPos ? PosOpcode : NegOpcode, DL, VT, N0, N1,
6347
+ HasPos ? Pos : Neg);
6348
+ }
6349
+
6350
+ return SDValue();
6351
+ }
6352
+
6322
6353
// MatchRotate - Handle an 'or' of two operands. If this is one of the many
6323
6354
// idioms for rotate, and if the target supports rotation instructions, generate
6324
6355
// a rot[lr]. This also matches funnel shift patterns, similar to rotation but
@@ -6444,10 +6475,6 @@ SDValue DAGCombiner::MatchRotate(SDValue LHS, SDValue RHS, const SDLoc &DL) {
6444
6475
return Res;
6445
6476
}
6446
6477
6447
- // TODO: Handle variable funnel shifts.
6448
- if (!IsRotate)
6449
- return SDValue();
6450
-
6451
6478
// If there is a mask here, and we have a variable shift, we can't be sure
6452
6479
// that we're masking out the right stuff.
6453
6480
if (LHSMask.getNode() || RHSMask.getNode())
@@ -6468,13 +6495,29 @@ SDValue DAGCombiner::MatchRotate(SDValue LHS, SDValue RHS, const SDLoc &DL) {
6468
6495
RExtOp0 = RHSShiftAmt.getOperand(0);
6469
6496
}
6470
6497
6471
- SDValue TryL = MatchRotatePosNeg(LHSShiftArg, LHSShiftAmt, RHSShiftAmt,
6472
- LExtOp0, RExtOp0, ISD::ROTL, ISD::ROTR, DL);
6498
+ if (IsRotate && (HasROTL || HasROTR)) {
6499
+ SDValue TryL =
6500
+ MatchRotatePosNeg(LHSShiftArg, LHSShiftAmt, RHSShiftAmt, LExtOp0,
6501
+ RExtOp0, ISD::ROTL, ISD::ROTR, DL);
6502
+ if (TryL)
6503
+ return TryL;
6504
+
6505
+ SDValue TryR =
6506
+ MatchRotatePosNeg(RHSShiftArg, RHSShiftAmt, LHSShiftAmt, RExtOp0,
6507
+ LExtOp0, ISD::ROTR, ISD::ROTL, DL);
6508
+ if (TryR)
6509
+ return TryR;
6510
+ }
6511
+
6512
+ SDValue TryL =
6513
+ MatchFunnelPosNeg(LHSShiftArg, RHSShiftArg, LHSShiftAmt, RHSShiftAmt,
6514
+ LExtOp0, RExtOp0, ISD::FSHL, ISD::FSHR, DL);
6473
6515
if (TryL)
6474
6516
return TryL;
6475
6517
6476
- SDValue TryR = MatchRotatePosNeg(RHSShiftArg, RHSShiftAmt, LHSShiftAmt,
6477
- RExtOp0, LExtOp0, ISD::ROTR, ISD::ROTL, DL);
6518
+ SDValue TryR =
6519
+ MatchFunnelPosNeg(LHSShiftArg, RHSShiftArg, RHSShiftAmt, LHSShiftAmt,
6520
+ RExtOp0, LExtOp0, ISD::FSHR, ISD::FSHL, DL);
6478
6521
if (TryR)
6479
6522
return TryR;
6480
6523
0 commit comments