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