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