@@ -1442,13 +1442,93 @@ void VPlanTransforms::addActiveLaneMask(
14421442 HeaderMask->replaceAllUsesWith (LaneMask);
14431443}
14441444
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+
14451526// / Replace recipes with their EVL variants.
14461527static void transformRecipestoEVLRecipes (VPlan &Plan, VPValue &EVL) {
1447- using namespace llvm ::VPlanPatternMatch;
14481528 Type *CanonicalIVType = Plan.getCanonicalIV ()->getScalarType ();
14491529 VPTypeAnalysis TypeInfo (CanonicalIVType);
14501530 LLVMContext &Ctx = CanonicalIVType->getContext ();
1451- SmallVector< VPValue *> HeaderMasks = collectAllHeaderMasks ( Plan);
1531+ VPValue *AllOneMask = Plan. getOrAddLiveIn ( ConstantInt::getTrue (Ctx) );
14521532
14531533 for (VPUser *U : Plan.getVF ().users ()) {
14541534 if (auto *R = dyn_cast<VPReverseVectorPointerRecipe>(U))
@@ -1460,110 +1540,22 @@ static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
14601540 for (VPValue *HeaderMask : collectAllHeaderMasks (Plan)) {
14611541 for (VPUser *U : collectUsersRecursively (HeaderMask)) {
14621542 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)
15541546 continue ;
15551547
1556- [[maybe_unused]] unsigned NumDefVal = NewRecipe ->getNumDefinedValues ();
1548+ [[maybe_unused]] unsigned NumDefVal = EVLRecipe ->getNumDefinedValues ();
15571549 assert (NumDefVal == CurRecipe->getNumDefinedValues () &&
15581550 " New recipe must define the same number of values as the "
15591551 " original." );
15601552 assert (
15611553 NumDefVal <= 1 &&
15621554 " 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 )) {
15651557 VPValue *CurVPV = CurRecipe->getVPSingleValue ();
1566- CurVPV->replaceAllUsesWith (NewRecipe ->getVPSingleValue ());
1558+ CurVPV->replaceAllUsesWith (EVLRecipe ->getVPSingleValue ());
15671559 }
15681560 // Defer erasing recipes till the end so that we don't invalidate the
15691561 // VPTypeAnalysis cache.
0 commit comments