@@ -570,3 +570,107 @@ TEST_F(OpenACCUtilsTest, getRecipeNamePrivateUnrankedMemref) {
570570 getRecipeName (RecipeKind::private_recipe, unrankedMemrefTy);
571571 EXPECT_EQ (recipeName, " privatization_memref_Zxi32_" );
572572}
573+
574+ // ===----------------------------------------------------------------------===//
575+ // getBaseEntity Tests
576+ // ===----------------------------------------------------------------------===//
577+
578+ // Local implementation of PartialEntityAccessOpInterface for memref.subview.
579+ // This is implemented locally in the test rather than officially because memref
580+ // operations already have ViewLikeOpInterface, which serves a similar purpose
581+ // for walking through views to the base entity. This test demonstrates how
582+ // getBaseEntity() would work if the interface were attached to memref.subview.
583+ namespace {
584+ struct SubViewOpPartialEntityAccessOpInterface
585+ : public acc::PartialEntityAccessOpInterface::ExternalModel<
586+ SubViewOpPartialEntityAccessOpInterface, memref::SubViewOp> {
587+ Value getBaseEntity (Operation *op) const {
588+ auto subviewOp = cast<memref::SubViewOp>(op);
589+ return subviewOp.getSource ();
590+ }
591+
592+ bool isCompleteView (Operation *op) const {
593+ // For testing purposes, we'll consider it a partial view (return false).
594+ // The real implementation would need to look at the offsets.
595+ return false ;
596+ }
597+ };
598+ } // namespace
599+
600+ TEST_F (OpenACCUtilsTest, getBaseEntityFromSubview) {
601+ // Register the local interface implementation for memref.subview
602+ memref::SubViewOp::attachInterface<SubViewOpPartialEntityAccessOpInterface>(
603+ context);
604+
605+ // Create a base memref
606+ auto memrefTy = MemRefType::get ({10 , 20 }, b.getF32Type ());
607+ OwningOpRef<memref::AllocaOp> allocOp =
608+ memref::AllocaOp::create (b, loc, memrefTy);
609+ Value baseMemref = allocOp->getResult ();
610+
611+ // Create a subview of the base memref with non-zero offsets
612+ // This creates a 5x10 view starting at [2, 3] in the original 10x20 memref
613+ SmallVector<OpFoldResult> offsets = {b.getIndexAttr (2 ), b.getIndexAttr (3 )};
614+ SmallVector<OpFoldResult> sizes = {b.getIndexAttr (5 ), b.getIndexAttr (10 )};
615+ SmallVector<OpFoldResult> strides = {b.getIndexAttr (1 ), b.getIndexAttr (1 )};
616+
617+ OwningOpRef<memref::SubViewOp> subviewOp =
618+ memref::SubViewOp::create (b, loc, baseMemref, offsets, sizes, strides);
619+ Value subview = subviewOp->getResult ();
620+
621+ // Test that getBaseEntity returns the base memref, not the subview
622+ Value baseEntity = getBaseEntity (subview);
623+ EXPECT_EQ (baseEntity, baseMemref);
624+ }
625+
626+ TEST_F (OpenACCUtilsTest, getBaseEntityNoInterface) {
627+ // Create a memref without the interface
628+ auto memrefTy = MemRefType::get ({10 }, b.getI32Type ());
629+ OwningOpRef<memref::AllocaOp> allocOp =
630+ memref::AllocaOp::create (b, loc, memrefTy);
631+ Value varPtr = allocOp->getResult ();
632+
633+ // Test that getBaseEntity returns the value itself when there's no interface
634+ Value baseEntity = getBaseEntity (varPtr);
635+ EXPECT_EQ (baseEntity, varPtr);
636+ }
637+
638+ TEST_F (OpenACCUtilsTest, getBaseEntityChainedSubviews) {
639+ // Register the local interface implementation for memref.subview
640+ memref::SubViewOp::attachInterface<SubViewOpPartialEntityAccessOpInterface>(
641+ context);
642+
643+ // Create a base memref
644+ auto memrefTy = MemRefType::get ({100 , 200 }, b.getI64Type ());
645+ OwningOpRef<memref::AllocaOp> allocOp =
646+ memref::AllocaOp::create (b, loc, memrefTy);
647+ Value baseMemref = allocOp->getResult ();
648+
649+ // Create first subview
650+ SmallVector<OpFoldResult> offsets1 = {b.getIndexAttr (10 ), b.getIndexAttr (20 )};
651+ SmallVector<OpFoldResult> sizes1 = {b.getIndexAttr (50 ), b.getIndexAttr (80 )};
652+ SmallVector<OpFoldResult> strides1 = {b.getIndexAttr (1 ), b.getIndexAttr (1 )};
653+
654+ OwningOpRef<memref::SubViewOp> subview1Op =
655+ memref::SubViewOp::create (b, loc, baseMemref, offsets1, sizes1, strides1);
656+ Value subview1 = subview1Op->getResult ();
657+
658+ // Create second subview (subview of subview)
659+ SmallVector<OpFoldResult> offsets2 = {b.getIndexAttr (5 ), b.getIndexAttr (10 )};
660+ SmallVector<OpFoldResult> sizes2 = {b.getIndexAttr (20 ), b.getIndexAttr (30 )};
661+ SmallVector<OpFoldResult> strides2 = {b.getIndexAttr (1 ), b.getIndexAttr (1 )};
662+
663+ OwningOpRef<memref::SubViewOp> subview2Op =
664+ memref::SubViewOp::create (b, loc, subview1, offsets2, sizes2, strides2);
665+ Value subview2 = subview2Op->getResult ();
666+
667+ // Test that getBaseEntity on the nested subview returns the first subview
668+ // (since our implementation returns the immediate source, not the ultimate
669+ // base)
670+ Value baseEntity = getBaseEntity (subview2);
671+ EXPECT_EQ (baseEntity, subview1);
672+
673+ // Test that calling getBaseEntity again returns the original base
674+ Value ultimateBase = getBaseEntity (baseEntity);
675+ EXPECT_EQ (ultimateBase, baseMemref);
676+ }
0 commit comments