@@ -1442,13 +1442,93 @@ void VPlanTransforms::addActiveLaneMask(
1442
1442
HeaderMask->replaceAllUsesWith (LaneMask);
1443
1443
}
1444
1444
1445
+ // Try to convert \p CurRecipe to a corresponding EVL-based recipe. Returns
1446
+ // nullptr if no EVL-based recipe could be created.
1447
+ // \p HeaderMask Header Mask.
1448
+ // \p CurRecipe Recipe to be transform.
1449
+ // \p TypeInfo VPlan-based type analysis.
1450
+ // \p AllOneMask The vector mask parameter of vector-predication intrinsics.
1451
+ // \p EVL The explicit vector length parameter of vector-predication
1452
+ // intrinsics.
1453
+ static VPRecipeBase *createEVLRecipe (VPValue *HeaderMask,
1454
+ VPRecipeBase &CurRecipe,
1455
+ VPTypeAnalysis &TypeInfo,
1456
+ VPValue &AllOneMask, VPValue &EVL) {
1457
+ using namespace llvm ::VPlanPatternMatch;
1458
+ auto GetNewMask = [&](VPValue *OrigMask) -> VPValue * {
1459
+ assert (OrigMask && " Unmasked recipe when folding tail" );
1460
+ return HeaderMask == OrigMask ? nullptr : OrigMask;
1461
+ };
1462
+
1463
+ return TypeSwitch<VPRecipeBase *, VPRecipeBase *>(&CurRecipe)
1464
+ .Case <VPWidenLoadRecipe>([&](VPWidenLoadRecipe *L) {
1465
+ VPValue *NewMask = GetNewMask (L->getMask ());
1466
+ return new VPWidenLoadEVLRecipe (*L, EVL, NewMask);
1467
+ })
1468
+ .Case <VPWidenStoreRecipe>([&](VPWidenStoreRecipe *S) {
1469
+ VPValue *NewMask = GetNewMask (S->getMask ());
1470
+ return new VPWidenStoreEVLRecipe (*S, EVL, NewMask);
1471
+ })
1472
+ .Case <VPWidenRecipe>([&](VPWidenRecipe *W) -> VPRecipeBase * {
1473
+ unsigned Opcode = W->getOpcode ();
1474
+ if (!Instruction::isBinaryOp (Opcode) && !Instruction::isUnaryOp (Opcode))
1475
+ return nullptr ;
1476
+ return new VPWidenEVLRecipe (*W, EVL);
1477
+ })
1478
+ .Case <VPReductionRecipe>([&](VPReductionRecipe *Red) {
1479
+ VPValue *NewMask = GetNewMask (Red->getCondOp ());
1480
+ return new VPReductionEVLRecipe (*Red, EVL, NewMask);
1481
+ })
1482
+ .Case <VPWidenIntrinsicRecipe, VPWidenCastRecipe>(
1483
+ [&](auto *CR) -> VPRecipeBase * {
1484
+ Intrinsic::ID VPID;
1485
+ if (auto *CallR = dyn_cast<VPWidenIntrinsicRecipe>(CR))
1486
+ VPID =
1487
+ VPIntrinsic::getForIntrinsic (CallR->getVectorIntrinsicID ());
1488
+ else if (auto *CastR = dyn_cast<VPWidenCastRecipe>(CR))
1489
+ VPID = VPIntrinsic::getForOpcode (CastR->getOpcode ());
1490
+ assert (VPID != Intrinsic::not_intrinsic && " Expected VP intrinsic" );
1491
+ assert (VPIntrinsic::getMaskParamPos (VPID) &&
1492
+ VPIntrinsic::getVectorLengthParamPos (VPID) &&
1493
+ " Expected VP intrinsic" );
1494
+
1495
+ SmallVector<VPValue *> Ops (CR->operands ());
1496
+ Ops.push_back (&AllOneMask);
1497
+ Ops.push_back (&EVL);
1498
+ return new VPWidenIntrinsicRecipe (
1499
+ VPID, Ops, TypeInfo.inferScalarType (CR), CR->getDebugLoc ());
1500
+ })
1501
+ .Case <VPWidenSelectRecipe>([&](VPWidenSelectRecipe *Sel) {
1502
+ SmallVector<VPValue *> Ops (Sel->operands ());
1503
+ Ops.push_back (&EVL);
1504
+ return new VPWidenIntrinsicRecipe (Intrinsic::vp_select, Ops,
1505
+ TypeInfo.inferScalarType (Sel),
1506
+ Sel->getDebugLoc ());
1507
+ })
1508
+ .Case <VPInstruction>([&](VPInstruction *VPI) -> VPRecipeBase * {
1509
+ VPValue *LHS, *RHS;
1510
+ // Transform select with a header mask condition
1511
+ // select(header_mask, LHS, RHS)
1512
+ // into vector predication merge.
1513
+ // vp.merge(all-true, LHS, RHS, EVL)
1514
+ if (!match (VPI, m_Select (m_Specific (HeaderMask), m_VPValue (LHS),
1515
+ m_VPValue (RHS))))
1516
+ return nullptr ;
1517
+ // Use all true as the condition because this transformation is
1518
+ // limited to selects whose condition is a header mask.
1519
+ return new VPWidenIntrinsicRecipe (
1520
+ Intrinsic::vp_merge, {&AllOneMask, LHS, RHS, &EVL},
1521
+ TypeInfo.inferScalarType (LHS), VPI->getDebugLoc ());
1522
+ })
1523
+ .Default ([&](VPRecipeBase *R) { return nullptr ; });
1524
+ }
1525
+
1445
1526
// / Replace recipes with their EVL variants.
1446
1527
static void transformRecipestoEVLRecipes (VPlan &Plan, VPValue &EVL) {
1447
- using namespace llvm ::VPlanPatternMatch;
1448
1528
Type *CanonicalIVType = Plan.getCanonicalIV ()->getScalarType ();
1449
1529
VPTypeAnalysis TypeInfo (CanonicalIVType);
1450
1530
LLVMContext &Ctx = CanonicalIVType->getContext ();
1451
- SmallVector< VPValue *> HeaderMasks = collectAllHeaderMasks ( Plan);
1531
+ VPValue *AllOneMask = Plan. getOrAddLiveIn ( ConstantInt::getTrue (Ctx) );
1452
1532
1453
1533
for (VPUser *U : Plan.getVF ().users ()) {
1454
1534
if (auto *R = dyn_cast<VPReverseVectorPointerRecipe>(U))
@@ -1460,110 +1540,22 @@ static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
1460
1540
for (VPValue *HeaderMask : collectAllHeaderMasks (Plan)) {
1461
1541
for (VPUser *U : collectUsersRecursively (HeaderMask)) {
1462
1542
auto *CurRecipe = cast<VPRecipeBase>(U);
1463
- auto GetNewMask = [&](VPValue *OrigMask) -> VPValue * {
1464
- assert (OrigMask && " Unmasked recipe when folding tail" );
1465
- return HeaderMask == OrigMask ? nullptr : OrigMask;
1466
- };
1467
-
1468
- VPRecipeBase *NewRecipe =
1469
- TypeSwitch<VPRecipeBase *, VPRecipeBase *>(CurRecipe)
1470
- .Case <VPWidenLoadRecipe>([&](VPWidenLoadRecipe *L) {
1471
- VPValue *NewMask = GetNewMask (L->getMask ());
1472
- return new VPWidenLoadEVLRecipe (*L, EVL, NewMask);
1473
- })
1474
- .Case <VPWidenStoreRecipe>([&](VPWidenStoreRecipe *S) {
1475
- VPValue *NewMask = GetNewMask (S->getMask ());
1476
- return new VPWidenStoreEVLRecipe (*S, EVL, NewMask);
1477
- })
1478
- .Case <VPWidenRecipe>([&](VPWidenRecipe *W) -> VPRecipeBase * {
1479
- unsigned Opcode = W->getOpcode ();
1480
- if (!Instruction::isBinaryOp (Opcode) &&
1481
- !Instruction::isUnaryOp (Opcode))
1482
- return nullptr ;
1483
- return new VPWidenEVLRecipe (*W, EVL);
1484
- })
1485
- .Case <VPReductionRecipe>([&](VPReductionRecipe *Red) {
1486
- VPValue *NewMask = GetNewMask (Red->getCondOp ());
1487
- return new VPReductionEVLRecipe (*Red, EVL, NewMask);
1488
- })
1489
- .Case <VPWidenIntrinsicRecipe>(
1490
- [&](VPWidenIntrinsicRecipe *CallR) -> VPRecipeBase * {
1491
- Intrinsic::ID VPID = VPIntrinsic::getForIntrinsic (
1492
- CallR->getVectorIntrinsicID ());
1493
- assert (VPID != Intrinsic::not_intrinsic &&
1494
- " Expected vp.casts Instrinsic" );
1495
- assert (VPIntrinsic::getMaskParamPos (VPID) &&
1496
- VPIntrinsic::getVectorLengthParamPos (VPID) &&
1497
- " Expected VP intrinsic" );
1498
-
1499
- SmallVector<VPValue *> Ops (CallR->operands ());
1500
- VPValue *Mask =
1501
- Plan.getOrAddLiveIn (ConstantInt::getTrue (Ctx));
1502
- Ops.push_back (Mask);
1503
- Ops.push_back (&EVL);
1504
- return new VPWidenIntrinsicRecipe (
1505
- VPID, Ops, TypeInfo.inferScalarType (CallR),
1506
- CallR->getDebugLoc ());
1507
- })
1508
- .Case <VPWidenCastRecipe>(
1509
- [&](VPWidenCastRecipe *CastR) -> VPRecipeBase * {
1510
- Intrinsic::ID VPID =
1511
- VPIntrinsic::getForOpcode (CastR->getOpcode ());
1512
- assert (VPID != Intrinsic::not_intrinsic &&
1513
- " Expected vp.casts Instrinsic" );
1514
-
1515
- SmallVector<VPValue *> Ops (CastR->operands ());
1516
- assert (VPIntrinsic::getMaskParamPos (VPID) &&
1517
- VPIntrinsic::getVectorLengthParamPos (VPID) &&
1518
- " Expected VP intrinsic" );
1519
- VPValue *Mask =
1520
- Plan.getOrAddLiveIn (ConstantInt::getTrue (Ctx));
1521
- Ops.push_back (Mask);
1522
- Ops.push_back (&EVL);
1523
- return new VPWidenIntrinsicRecipe (
1524
- VPID, Ops, TypeInfo.inferScalarType (CastR),
1525
- CastR->getDebugLoc ());
1526
- })
1527
- .Case <VPWidenSelectRecipe>([&](VPWidenSelectRecipe *Sel) {
1528
- SmallVector<VPValue *> Ops (Sel->operands ());
1529
- Ops.push_back (&EVL);
1530
- return new VPWidenIntrinsicRecipe (Intrinsic::vp_select, Ops,
1531
- TypeInfo.inferScalarType (Sel),
1532
- Sel->getDebugLoc ());
1533
- })
1534
- .Case <VPInstruction>([&](VPInstruction *VPI) -> VPRecipeBase * {
1535
- VPValue *LHS, *RHS;
1536
- // Transform select with a header mask condition
1537
- // select(header_mask, LHS, RHS)
1538
- // into vector predication merge.
1539
- // vp.merge(all-true, LHS, RHS, EVL)
1540
- if (!match (VPI, m_Select (m_Specific (HeaderMask), m_VPValue (LHS),
1541
- m_VPValue (RHS))))
1542
- return nullptr ;
1543
- // Use all true as the condition because this transformation is
1544
- // limited to selects whose condition is a header mask.
1545
- VPValue *AllTrue =
1546
- Plan.getOrAddLiveIn (ConstantInt::getTrue (Ctx));
1547
- return new VPWidenIntrinsicRecipe (
1548
- Intrinsic::vp_merge, {AllTrue, LHS, RHS, &EVL},
1549
- TypeInfo.inferScalarType (LHS), VPI->getDebugLoc ());
1550
- })
1551
- .Default ([&](VPRecipeBase *R) { return nullptr ; });
1552
-
1553
- if (!NewRecipe)
1543
+ VPRecipeBase *EVLRecipe =
1544
+ createEVLRecipe (HeaderMask, *CurRecipe, TypeInfo, *AllOneMask, EVL);
1545
+ if (!EVLRecipe)
1554
1546
continue ;
1555
1547
1556
- [[maybe_unused]] unsigned NumDefVal = NewRecipe ->getNumDefinedValues ();
1548
+ [[maybe_unused]] unsigned NumDefVal = EVLRecipe ->getNumDefinedValues ();
1557
1549
assert (NumDefVal == CurRecipe->getNumDefinedValues () &&
1558
1550
" New recipe must define the same number of values as the "
1559
1551
" original." );
1560
1552
assert (
1561
1553
NumDefVal <= 1 &&
1562
1554
" Only supports recipes with a single definition or without users." );
1563
- NewRecipe ->insertBefore (CurRecipe);
1564
- if (isa<VPSingleDefRecipe, VPWidenLoadEVLRecipe>(NewRecipe )) {
1555
+ EVLRecipe ->insertBefore (CurRecipe);
1556
+ if (isa<VPSingleDefRecipe, VPWidenLoadEVLRecipe>(EVLRecipe )) {
1565
1557
VPValue *CurVPV = CurRecipe->getVPSingleValue ();
1566
- CurVPV->replaceAllUsesWith (NewRecipe ->getVPSingleValue ());
1558
+ CurVPV->replaceAllUsesWith (EVLRecipe ->getVPSingleValue ());
1567
1559
}
1568
1560
// Defer erasing recipes till the end so that we don't invalidate the
1569
1561
// VPTypeAnalysis cache.
0 commit comments