Skip to content

Commit bdf4892

Browse files
authored
Merge branch 'main' into V81-new-instructions
2 parents f821fcb + c620d07 commit bdf4892

File tree

10 files changed

+285
-1
lines changed

10 files changed

+285
-1
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
2121
#include "mlir/Interfaces/LoopLikeInterface.h"
2222
#include "mlir/Interfaces/SideEffectInterfaces.h"
23+
#include "mlir/Interfaces/ViewLikeInterface.h"
2324

2425
namespace fir {
2526

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
include "mlir/Dialect/Arith/IR/ArithBase.td"
1818
include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
1919
include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
20+
include "mlir/Interfaces/ViewLikeInterface.td"
2021
include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.td"
2122
include "flang/Optimizer/Dialect/FIRDialect.td"
2223
include "flang/Optimizer/Dialect/FIRTypes.td"
@@ -2828,7 +2829,8 @@ def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [Pure]> {
28282829
let hasFolder = 1;
28292830
}
28302831

2831-
def fir_ConvertOp : fir_SimpleOneResultOp<"convert", [NoMemoryEffect]> {
2832+
def fir_ConvertOp
2833+
: fir_SimpleOneResultOp<"convert", [NoMemoryEffect, ViewLikeOpInterface]> {
28322834
let summary = "encapsulates all Fortran entity type conversions";
28332835

28342836
let description = [{
@@ -2866,6 +2868,7 @@ def fir_ConvertOp : fir_SimpleOneResultOp<"convert", [NoMemoryEffect]> {
28662868
static bool isPointerCompatible(mlir::Type ty);
28672869
static bool canBeConverted(mlir::Type inType, mlir::Type outType);
28682870
static bool areVectorsCompatible(mlir::Type inTy, mlir::Type outTy);
2871+
mlir::Value getViewSource() { return getValue(); }
28692872
}];
28702873
let hasCanonicalizer = 1;
28712874
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===- FIROpenACCOpsInterfaces.h --------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains external operation interfaces for FIR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FLANG_OPTIMIZER_OPENACC_FIROPENACC_OPS_INTERFACES_H_
14+
#define FLANG_OPTIMIZER_OPENACC_FIROPENACC_OPS_INTERFACES_H_
15+
16+
#include "mlir/Dialect/OpenACC/OpenACC.h"
17+
18+
namespace fir {
19+
class DeclareOp;
20+
} // namespace fir
21+
22+
namespace hlfir {
23+
class DeclareOp;
24+
class DesignateOp;
25+
} // namespace hlfir
26+
27+
namespace fir::acc {
28+
29+
template <typename Op>
30+
struct PartialEntityAccessModel
31+
: public mlir::acc::PartialEntityAccessOpInterface::ExternalModel<
32+
PartialEntityAccessModel<Op>, Op> {
33+
mlir::Value getBaseEntity(mlir::Operation *op) const;
34+
35+
// Default implementation - returns false (partial view)
36+
bool isCompleteView(mlir::Operation *op) const { return false; }
37+
};
38+
39+
// Full specializations for declare operations
40+
template <>
41+
struct PartialEntityAccessModel<fir::DeclareOp>
42+
: public mlir::acc::PartialEntityAccessOpInterface::ExternalModel<
43+
PartialEntityAccessModel<fir::DeclareOp>, fir::DeclareOp> {
44+
mlir::Value getBaseEntity(mlir::Operation *op) const;
45+
bool isCompleteView(mlir::Operation *op) const;
46+
};
47+
48+
template <>
49+
struct PartialEntityAccessModel<hlfir::DeclareOp>
50+
: public mlir::acc::PartialEntityAccessOpInterface::ExternalModel<
51+
PartialEntityAccessModel<hlfir::DeclareOp>, hlfir::DeclareOp> {
52+
mlir::Value getBaseEntity(mlir::Operation *op) const;
53+
bool isCompleteView(mlir::Operation *op) const;
54+
};
55+
56+
} // namespace fir::acc
57+
58+
#endif // FLANG_OPTIMIZER_OPENACC_FIROPENACC_OPS_INTERFACES_H_

flang/lib/Optimizer/OpenACC/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
22

33
add_flang_library(FIROpenACCSupport
44
FIROpenACCAttributes.cpp
5+
FIROpenACCOpsInterfaces.cpp
56
FIROpenACCTypeInterfaces.cpp
67
RegisterOpenACCExtensions.cpp
78

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===-- FIROpenACCOpsInterfaces.cpp ---------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Implementation of external operation interfaces for FIR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Optimizer/OpenACC/Support/FIROpenACCOpsInterfaces.h"
14+
15+
#include "flang/Optimizer/Dialect/FIROps.h"
16+
#include "flang/Optimizer/HLFIR/HLFIROps.h"
17+
18+
namespace fir::acc {
19+
20+
template <>
21+
mlir::Value PartialEntityAccessModel<fir::ArrayCoorOp>::getBaseEntity(
22+
mlir::Operation *op) const {
23+
return mlir::cast<fir::ArrayCoorOp>(op).getMemref();
24+
}
25+
26+
template <>
27+
mlir::Value PartialEntityAccessModel<fir::CoordinateOp>::getBaseEntity(
28+
mlir::Operation *op) const {
29+
return mlir::cast<fir::CoordinateOp>(op).getRef();
30+
}
31+
32+
template <>
33+
mlir::Value PartialEntityAccessModel<hlfir::DesignateOp>::getBaseEntity(
34+
mlir::Operation *op) const {
35+
return mlir::cast<hlfir::DesignateOp>(op).getMemref();
36+
}
37+
38+
mlir::Value PartialEntityAccessModel<fir::DeclareOp>::getBaseEntity(
39+
mlir::Operation *op) const {
40+
return mlir::cast<fir::DeclareOp>(op).getStorage();
41+
}
42+
43+
bool PartialEntityAccessModel<fir::DeclareOp>::isCompleteView(
44+
mlir::Operation *op) const {
45+
// Return false (partial view) only if storage is present
46+
// Return true (complete view) if storage is absent
47+
return !getBaseEntity(op);
48+
}
49+
50+
mlir::Value PartialEntityAccessModel<hlfir::DeclareOp>::getBaseEntity(
51+
mlir::Operation *op) const {
52+
return mlir::cast<hlfir::DeclareOp>(op).getStorage();
53+
}
54+
55+
bool PartialEntityAccessModel<hlfir::DeclareOp>::isCompleteView(
56+
mlir::Operation *op) const {
57+
// Return false (partial view) only if storage is present
58+
// Return true (complete view) if storage is absent
59+
return !getBaseEntity(op);
60+
}
61+
62+
} // namespace fir::acc

flang/lib/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "flang/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.h"
14+
1415
#include "flang/Optimizer/Dialect/FIRDialect.h"
16+
#include "flang/Optimizer/Dialect/FIROps.h"
1517
#include "flang/Optimizer/Dialect/FIRType.h"
18+
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
19+
#include "flang/Optimizer/HLFIR/HLFIROps.h"
20+
#include "flang/Optimizer/OpenACC/Support/FIROpenACCOpsInterfaces.h"
1621
#include "flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h"
1722

1823
namespace fir::acc {
@@ -37,7 +42,24 @@ void registerOpenACCExtensions(mlir::DialectRegistry &registry) {
3742

3843
fir::LLVMPointerType::attachInterface<
3944
OpenACCPointerLikeModel<fir::LLVMPointerType>>(*ctx);
45+
46+
fir::ArrayCoorOp::attachInterface<
47+
PartialEntityAccessModel<fir::ArrayCoorOp>>(*ctx);
48+
fir::CoordinateOp::attachInterface<
49+
PartialEntityAccessModel<fir::CoordinateOp>>(*ctx);
50+
fir::DeclareOp::attachInterface<PartialEntityAccessModel<fir::DeclareOp>>(
51+
*ctx);
4052
});
53+
54+
// Register HLFIR operation interfaces
55+
registry.addExtension(
56+
+[](mlir::MLIRContext *ctx, hlfir::hlfirDialect *dialect) {
57+
hlfir::DesignateOp::attachInterface<
58+
PartialEntityAccessModel<hlfir::DesignateOp>>(*ctx);
59+
hlfir::DeclareOp::attachInterface<
60+
PartialEntityAccessModel<hlfir::DeclareOp>>(*ctx);
61+
});
62+
4163
registerAttrsExtensions(registry);
4264
}
4365

mlir/include/mlir/Dialect/OpenACC/OpenACCOpsInterfaces.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,22 @@ def ComputeRegionOpInterface : OpInterface<"ComputeRegionOpInterface"> {
2626
];
2727
}
2828

29+
def PartialEntityAccessOpInterface : OpInterface<"PartialEntityAccessOpInterface"> {
30+
let cppNamespace = "::mlir::acc";
31+
32+
let description = [{
33+
An interface for operations that access a partial entity such as
34+
field or array element access.
35+
}];
36+
37+
let methods = [
38+
InterfaceMethod<"Get the base entity being accessed", "::mlir::Value",
39+
"getBaseEntity", (ins)>,
40+
InterfaceMethod<"Check if this is a complete view of the entity", "bool",
41+
"isCompleteView", (ins), [{
42+
return false;
43+
}]>,
44+
];
45+
}
46+
2947
#endif // OPENACC_OPS_INTERFACES

mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ std::string getVariableName(mlir::Value v);
4747
/// Returns an empty string if not possible to generate a recipe name.
4848
std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type);
4949

50+
// Get the base entity from partial entity access. This is used for getting
51+
// the base `struct` from an operation that only accesses a field or the
52+
// base `array` from an operation that only accesses a subarray.
53+
mlir::Value getBaseEntity(mlir::Value val);
54+
5055
} // namespace acc
5156
} // namespace mlir
5257

mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,13 @@ std::string mlir::acc::getRecipeName(mlir::acc::RecipeKind kind,
145145

146146
return recipeName;
147147
}
148+
149+
mlir::Value mlir::acc::getBaseEntity(mlir::Value val) {
150+
if (auto partialEntityAccessOp =
151+
dyn_cast<PartialEntityAccessOpInterface>(val.getDefiningOp())) {
152+
if (!partialEntityAccessOp.isCompleteView())
153+
return partialEntityAccessOp.getBaseEntity();
154+
}
155+
156+
return val;
157+
}

mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)