@@ -1438,13 +1438,100 @@ void VPlanTransforms::addActiveLaneMask(
14381438 HeaderMask->replaceAllUsesWith (LaneMask);
14391439}
14401440
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+
14411529// / Replace recipes with their EVL variants.
14421530static void transformRecipestoEVLRecipes (VPlan &Plan, VPValue &EVL) {
1443- using namespace llvm ::VPlanPatternMatch;
14441531 Type *CanonicalIVType = Plan.getCanonicalIV ()->getScalarType ();
14451532 VPTypeAnalysis TypeInfo (CanonicalIVType);
14461533 LLVMContext &Ctx = CanonicalIVType->getContext ();
1447- SmallVector< VPValue *> HeaderMasks = collectAllHeaderMasks ( Plan);
1534+ VPValue *AllOneMask = Plan. getOrAddLiveIn ( ConstantInt::getTrue (Ctx) );
14481535
14491536 for (VPUser *U : Plan.getVF ().users ()) {
14501537 if (auto *R = dyn_cast<VPReverseVectorPointerRecipe>(U))
@@ -1454,112 +1541,22 @@ static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
14541541 for (VPValue *HeaderMask : collectAllHeaderMasks (Plan)) {
14551542 for (VPUser *U : collectUsersRecursively (HeaderMask)) {
14561543 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)
15501547 continue ;
15511548
1552- [[maybe_unused]] unsigned NumDefVal = NewRecipe ->getNumDefinedValues ();
1549+ [[maybe_unused]] unsigned NumDefVal = EVLRecipe ->getNumDefinedValues ();
15531550 assert (NumDefVal == CurRecipe->getNumDefinedValues () &&
15541551 " New recipe must define the same number of values as the "
15551552 " original." );
15561553 assert (
15571554 NumDefVal <= 1 &&
15581555 " 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 )) {
15611558 VPValue *CurVPV = CurRecipe->getVPSingleValue ();
1562- CurVPV->replaceAllUsesWith (NewRecipe ->getVPSingleValue ());
1559+ CurVPV->replaceAllUsesWith (EVLRecipe ->getVPSingleValue ());
15631560 }
15641561 CurRecipe->eraseFromParent ();
15651562 }
0 commit comments