@@ -557,6 +557,7 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPValue {
557
557
case VPRecipeBase::VPPartialReductionSC:
558
558
return true ;
559
559
case VPRecipeBase::VPBranchOnMaskSC:
560
+ case VPRecipeBase::VPInterleaveEVLSC:
560
561
case VPRecipeBase::VPInterleaveSC:
561
562
case VPRecipeBase::VPIRInstructionSC:
562
563
case VPRecipeBase::VPWidenLoadEVLSC:
@@ -2385,11 +2386,14 @@ class LLVM_ABI_FOR_TEST VPBlendRecipe : public VPSingleDefRecipe {
2385
2386
}
2386
2387
};
2387
2388
2388
- // / VPInterleaveRecipe is a recipe for transforming an interleave group of load
2389
- // / or stores into one wide load/store and shuffles. The first operand of a
2390
- // / VPInterleave recipe is the address, followed by the stored values, followed
2391
- // / by an optional mask.
2392
- class LLVM_ABI_FOR_TEST VPInterleaveRecipe : public VPRecipeBase {
2389
+ // / A common base class for interleaved memory operations.
2390
+ // / Interleaved memory operation is a memory access method that combines
2391
+ // / multiple strided loads/stores into a single wide load/store with shuffles.
2392
+ // / The first operand must be the address. The optional operands are, in order,
2393
+ // / the stored values and the mask.
2394
+ // / TODO: Inherit from VPIRMetadata
2395
+ class LLVM_ABI_FOR_TEST VPInterleaveBase : public VPRecipeBase {
2396
+ protected:
2393
2397
const InterleaveGroup<Instruction> *IG;
2394
2398
2395
2399
// / Indicates if the interleave group is in a conditional block and requires a
@@ -2400,14 +2404,13 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe : public VPRecipeBase {
2400
2404
// / unusued gaps can be loaded speculatively.
2401
2405
bool NeedsMaskForGaps = false ;
2402
2406
2403
- public:
2404
- VPInterleaveRecipe (const InterleaveGroup<Instruction> *IG, VPValue *Addr,
2405
- ArrayRef<VPValue *> StoredValues, VPValue *Mask,
2406
- bool NeedsMaskForGaps, DebugLoc DL)
2407
- : VPRecipeBase(VPDef::VPInterleaveSC, {Addr},
2408
- DL),
2409
-
2410
- IG (IG), NeedsMaskForGaps(NeedsMaskForGaps) {
2407
+ VPInterleaveBase (const unsigned char SC,
2408
+ const InterleaveGroup<Instruction> *IG,
2409
+ ArrayRef<VPValue *> Operands,
2410
+ ArrayRef<VPValue *> StoredValues, VPValue *Mask,
2411
+ bool NeedsMaskForGaps, DebugLoc DL)
2412
+ : VPRecipeBase(SC, Operands, DL), IG(IG),
2413
+ NeedsMaskForGaps (NeedsMaskForGaps) {
2411
2414
// TODO: extend the masked interleaved-group support to reversed access.
2412
2415
assert ((!Mask || !IG->isReverse ()) &&
2413
2416
" Reversed masked interleave-group not supported." );
@@ -2420,70 +2423,169 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe : public VPRecipeBase {
2420
2423
2421
2424
for (auto *SV : StoredValues)
2422
2425
addOperand (SV);
2426
+
2423
2427
if (Mask) {
2424
2428
HasMask = true ;
2425
2429
addOperand (Mask);
2426
2430
}
2427
2431
}
2428
- ~VPInterleaveRecipe () override = default ;
2429
2432
2430
- VPInterleaveRecipe * clone () override {
2431
- return new VPInterleaveRecipe (IG, getAddr (), getStoredValues (), getMask (),
2432
- NeedsMaskForGaps, getDebugLoc () );
2433
+ public:
2434
+ VPInterleaveBase * clone () override {
2435
+ llvm_unreachable ( " cloning not supported " );
2433
2436
}
2434
2437
2435
- VP_CLASSOF_IMPL (VPDef::VPInterleaveSC)
2438
+ static inline bool classof (const VPRecipeBase *R) {
2439
+ return R->getVPDefID () == VPRecipeBase::VPInterleaveSC ||
2440
+ R->getVPDefID () == VPRecipeBase::VPInterleaveEVLSC;
2441
+ }
2442
+
2443
+ static inline bool classof (const VPUser *U) {
2444
+ auto *R = dyn_cast<VPRecipeBase>(U);
2445
+ return R && classof (R);
2446
+ }
2436
2447
2437
2448
// / Return the address accessed by this recipe.
2438
2449
VPValue *getAddr () const {
2439
2450
return getOperand (0 ); // Address is the 1st, mandatory operand.
2440
2451
}
2441
2452
2453
+ // / Return true if the access needs a mask because of the gaps.
2454
+ bool needsMaskForGaps () const { return NeedsMaskForGaps; }
2455
+
2442
2456
// / Return the mask used by this recipe. Note that a full mask is represented
2443
2457
// / by a nullptr.
2444
2458
VPValue *getMask () const {
2445
- // Mask is optional and therefore the last, currently 2nd operand.
2459
+ // Mask is optional and the last operand.
2446
2460
return HasMask ? getOperand (getNumOperands () - 1 ) : nullptr ;
2447
2461
}
2448
2462
2463
+ const InterleaveGroup<Instruction> *getInterleaveGroup () { return IG; }
2464
+
2465
+ Instruction *getInsertPos () const { return IG->getInsertPos (); }
2466
+
2467
+ void execute (VPTransformState &State) override {
2468
+ llvm_unreachable (" VPInterleaveBase should not be instantiated." );
2469
+ }
2470
+
2471
+ // / Return the cost of this VPInterleaveRecipe.
2472
+ InstructionCost computeCost (ElementCount VF,
2473
+ VPCostContext &Ctx) const override ;
2474
+
2475
+ // / Returns true if the recipe only uses the first lane of operand \p Op.
2476
+ virtual bool onlyFirstLaneUsed (const VPValue *Op) const = 0;
2477
+
2478
+ // / Returns the number of stored operands of this interleave group. Returns 0
2479
+ // / for load interleave groups.
2480
+ virtual unsigned getNumStoreOperands () const = 0;
2481
+
2449
2482
// / Return the VPValues stored by this interleave group. If it is a load
2450
2483
// / interleave group, return an empty ArrayRef.
2451
- ArrayRef<VPValue *> getStoredValues () const {
2452
- // The first operand is the address, followed by the stored values, followed
2453
- // by an optional mask.
2454
- return ArrayRef<VPValue *>(op_begin (), getNumOperands ())
2455
- .slice (1 , getNumStoreOperands ());
2484
+ virtual ArrayRef<VPValue *> getStoredValues () const = 0;
2485
+ };
2486
+
2487
+ // / VPInterleaveRecipe is a recipe for transforming an interleave group of load
2488
+ // / or stores into one wide load/store and shuffles. The first operand of a
2489
+ // / VPInterleave recipe is the address, followed by the stored values, followed
2490
+ // / by an optional mask.
2491
+ class LLVM_ABI_FOR_TEST VPInterleaveRecipe final : public VPInterleaveBase {
2492
+ public:
2493
+ VPInterleaveRecipe (const InterleaveGroup<Instruction> *IG, VPValue *Addr,
2494
+ ArrayRef<VPValue *> StoredValues, VPValue *Mask,
2495
+ bool NeedsMaskForGaps, DebugLoc DL)
2496
+ : VPInterleaveBase(VPDef::VPInterleaveSC, IG, ArrayRef<VPValue *>({Addr}),
2497
+ StoredValues, Mask, NeedsMaskForGaps, DL) {}
2498
+
2499
+ ~VPInterleaveRecipe () override = default ;
2500
+
2501
+ VPInterleaveRecipe *clone () override {
2502
+ return new VPInterleaveRecipe (IG, getAddr (), getStoredValues (), getMask (),
2503
+ NeedsMaskForGaps, getDebugLoc ());
2456
2504
}
2457
2505
2506
+ VP_CLASSOF_IMPL (VPDef::VPInterleaveSC)
2507
+
2458
2508
// / Generate the wide load or store, and shuffles.
2459
2509
void execute (VPTransformState &State) override ;
2460
2510
2461
- // / Return the cost of this VPInterleaveRecipe.
2462
- InstructionCost computeCost (ElementCount VF,
2463
- VPCostContext &Ctx) const override ;
2464
-
2465
2511
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2466
2512
// / Print the recipe.
2467
2513
void print (raw_ostream &O, const Twine &Indent,
2468
2514
VPSlotTracker &SlotTracker) const override ;
2469
2515
#endif
2470
2516
2471
- const InterleaveGroup<Instruction> *getInterleaveGroup () { return IG; }
2517
+ bool onlyFirstLaneUsed (const VPValue *Op) const override {
2518
+ assert (is_contained (operands (), Op) &&
2519
+ " Op must be an operand of the recipe" );
2520
+ return Op == getAddr () && !llvm::is_contained (getStoredValues (), Op);
2521
+ }
2472
2522
2473
- // / Returns the number of stored operands of this interleave group. Returns 0
2474
- // / for load interleave groups.
2475
- unsigned getNumStoreOperands () const {
2523
+ unsigned getNumStoreOperands () const override {
2476
2524
return getNumOperands () - (HasMask ? 2 : 1 );
2477
2525
}
2478
2526
2479
- // / The recipe only uses the first lane of the address.
2527
+ ArrayRef<VPValue *> getStoredValues () const override {
2528
+ // The first operand is the address, followed by the stored values, followed
2529
+ // by an optional mask.
2530
+ return ArrayRef<VPValue *>(op_begin (), getNumOperands ())
2531
+ .slice (1 , getNumStoreOperands ());
2532
+ }
2533
+ };
2534
+
2535
+ // / A recipe for interleaved access operations with vector-predication
2536
+ // / intrinsics. The first operand is the address, the second operand is the
2537
+ // / explicit vector length . Stored values and mask are optional operands.
2538
+ class LLVM_ABI_FOR_TEST VPInterleaveEVLRecipe final : public VPInterleaveBase {
2539
+ public:
2540
+ VPInterleaveEVLRecipe (VPInterleaveRecipe &R, VPValue &EVL, VPValue *Mask)
2541
+ : VPInterleaveBase(VPDef::VPInterleaveEVLSC, R.getInterleaveGroup(),
2542
+ ArrayRef<VPValue *>({R.getAddr (), &EVL}),
2543
+ R.getStoredValues(), Mask, R.needsMaskForGaps(),
2544
+ R.getDebugLoc()) {
2545
+ assert (!IG->isReverse () &&
2546
+ " Reversed interleave-group with tail folding is not supported." );
2547
+ assert (!needsMaskForGaps () && " Interleaved access with gap mask is not "
2548
+ " supported for scalable vector." );
2549
+ }
2550
+
2551
+ ~VPInterleaveEVLRecipe () override = default ;
2552
+
2553
+ VPInterleaveEVLRecipe *clone () override {
2554
+ llvm_unreachable (" cloning not implemented yet" );
2555
+ }
2556
+
2557
+ VP_CLASSOF_IMPL (VPDef::VPInterleaveEVLSC)
2558
+
2559
+ // / The VPValue of the explicit vector length.
2560
+ VPValue *getEVL () const { return getOperand (1 ); }
2561
+
2562
+ // / Generate the wide load or store, and shuffles.
2563
+ void execute (VPTransformState &State) override ;
2564
+
2565
+ #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2566
+ // / Print the recipe.
2567
+ void print (raw_ostream &O, const Twine &Indent,
2568
+ VPSlotTracker &SlotTracker) const override ;
2569
+ #endif
2570
+
2571
+ // / The recipe only uses the first lane of the address, and EVL operand.
2480
2572
bool onlyFirstLaneUsed (const VPValue *Op) const override {
2481
2573
assert (is_contained (operands (), Op) &&
2482
2574
" Op must be an operand of the recipe" );
2483
- return Op == getAddr () && !llvm::is_contained (getStoredValues (), Op);
2575
+ return (Op == getAddr () && !llvm::is_contained (getStoredValues (), Op)) ||
2576
+ Op == getEVL ();
2484
2577
}
2485
2578
2486
- Instruction *getInsertPos () const { return IG->getInsertPos (); }
2579
+ unsigned getNumStoreOperands () const override {
2580
+ return getNumOperands () - (HasMask ? 3 : 2 );
2581
+ }
2582
+
2583
+ ArrayRef<VPValue *> getStoredValues () const override {
2584
+ // The first operand is the address, and the second operand is EVL, followed
2585
+ // by the stored values, followe by an optional mask.
2586
+ return ArrayRef<VPValue *>(op_begin (), getNumOperands ())
2587
+ .slice (2 , getNumStoreOperands ());
2588
+ }
2487
2589
};
2488
2590
2489
2591
// / A recipe to represent inloop reduction operations, performing a reduction on
0 commit comments