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