Skip to content

Commit 01a0d21

Browse files
[flang][acc] Implement MappableType interfaces for fir.box and fir.array (#122495)
The newly introduced MappableType interface in `acc` dialect was primarily intended to allow variables with non-materialized storage to be used in acc data clauses (previously everything was required to be `pointer-like`). One motivator for this was `fir.box` since it is possible to be passed to functions without a wrapping `fir.ref` and also it can be generated directly via operations like `fir.embox` - and unlike other variable representations in FIR, the underlying storage for it does not get materialized until LLVM codegen. The new interface is being attached to both `fir.box` and `fir.array`. Strictly speaking, attaching to the latter is primarily for consistency since the MappableType interface requires implementation of utilities to compute byte size - and it made sense that a `fir.box<fir.array<10xi32>>` and `fir.array<10xi32>` would have a consistently computable size. This decision may be revisited as MappableType interface evolves. The new interface attachments are made in a new library named `FIROpenACCSupport`. The reason for this is to avoid circular dependencies since the implementation of this library is reusing code from lowering of OpenACC. More specifically, the types are defined in `FIRDialect` and `FortranLower` depends on it. Thus we cannot attach these interfaces in `FIRDialect`.
1 parent 9405a81 commit 01a0d21

File tree

17 files changed

+485
-1
lines changed

17 files changed

+485
-1
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===- FIROpenACCTypeInterfaces.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 dialect interfaces for FIR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_
14+
#define FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_
15+
16+
#include "flang/Optimizer/Dialect/FIRType.h"
17+
#include "mlir/Dialect/OpenACC/OpenACC.h"
18+
19+
namespace fir::acc {
20+
21+
template <typename T>
22+
struct OpenACCMappableModel
23+
: public mlir::acc::MappableType::ExternalModel<OpenACCMappableModel<T>,
24+
T> {
25+
mlir::TypedValue<mlir::acc::PointerLikeType> getVarPtr(::mlir::Type type,
26+
mlir::Value var) const;
27+
28+
std::optional<llvm::TypeSize>
29+
getSizeInBytes(mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
30+
const mlir::DataLayout &dataLayout) const;
31+
32+
std::optional<int64_t>
33+
getOffsetInBytes(mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
34+
const mlir::DataLayout &dataLayout) const;
35+
36+
llvm::SmallVector<mlir::Value>
37+
generateAccBounds(mlir::Type type, mlir::Value var,
38+
mlir::OpBuilder &builder) const;
39+
};
40+
41+
} // namespace fir::acc
42+
43+
#endif // FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===- RegisterOpenACCExtensions.h - OpenACC Extension Registration --===--===//
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+
#ifndef FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
10+
#define FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
11+
12+
namespace mlir {
13+
class DialectRegistry;
14+
} // namespace mlir
15+
16+
namespace fir::acc {
17+
18+
void registerOpenACCExtensions(mlir::DialectRegistry &registry);
19+
20+
} // namespace fir::acc
21+
22+
#endif // FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_

flang/include/flang/Optimizer/Support/InitFIR.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "flang/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.h"
1818
#include "flang/Optimizer/Dialect/FIRDialect.h"
1919
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
20+
#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
2021
#include "mlir/Conversion/Passes.h"
2122
#include "mlir/Dialect/Affine/Passes.h"
2223
#include "mlir/Dialect/Complex/IR/Complex.h"
@@ -63,6 +64,7 @@ inline void addFIRExtensions(mlir::DialectRegistry &registry,
6364
addFIRInlinerExtension(registry);
6465
addFIRToLLVMIRExtension(registry);
6566
cuf::registerCUFDialectTranslation(registry);
67+
fir::acc::registerOpenACCExtensions(registry);
6668
}
6769

6870
inline void loadNonCodegenDialects(mlir::MLIRContext &context) {

flang/lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ add_flang_library(flangFrontend
3939
HLFIRDialect
4040
HLFIRTransforms
4141
flangPasses
42+
FIROpenACCSupport
4243
FlangOpenMPTransforms
4344
MLIRTransforms
4445
MLIRBuiltinToLLVMIRTranslation

flang/lib/Optimizer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_subdirectory(Builder)
33
add_subdirectory(CodeGen)
44
add_subdirectory(Dialect)
55
add_subdirectory(HLFIR)
6+
add_subdirectory(OpenACC)
67
add_subdirectory(OpenMP)
78
add_subdirectory(Passes)
89
add_subdirectory(Support)

flang/lib/Optimizer/Dialect/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ add_flang_library(FIRDialect
66
FIRDialect.cpp
77
FIROps.cpp
88
FIRType.cpp
9-
FortranVariableInterface.cpp
109
FirAliasTagOpInterface.cpp
10+
FortranVariableInterface.cpp
1111
Inliner.cpp
1212

1313
DEPENDS
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
2+
3+
add_flang_library(FIROpenACCSupport
4+
FIROpenACCTypeInterfaces.cpp
5+
RegisterOpenACCExtensions.cpp
6+
7+
DEPENDS
8+
FIRBuilder
9+
FIRDialect
10+
FIRDialectSupport
11+
FIRSupport
12+
HLFIRDialect
13+
MLIROpenACCDialect
14+
15+
LINK_LIBS
16+
FIRBuilder
17+
FIRDialect
18+
FIRDialectSupport
19+
FIRSupport
20+
HLFIRDialect
21+
MLIROpenACCDialect
22+
)
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
//===-- FIROpenACCTypeInterfaces.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 dialect interfaces for FIR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h"
14+
#include "flang/Lower/DirectivesCommon.h"
15+
#include "flang/Optimizer/Builder/BoxValue.h"
16+
#include "flang/Optimizer/Builder/FIRBuilder.h"
17+
#include "flang/Optimizer/Builder/HLFIRTools.h"
18+
#include "flang/Optimizer/Dialect/FIROps.h"
19+
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
20+
#include "flang/Optimizer/Dialect/FIRType.h"
21+
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
22+
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
23+
#include "mlir/Dialect/Arith/IR/Arith.h"
24+
#include "mlir/Dialect/OpenACC/OpenACC.h"
25+
#include "mlir/IR/BuiltinOps.h"
26+
#include "mlir/Support/LLVM.h"
27+
28+
namespace fir::acc {
29+
30+
static mlir::TypedValue<mlir::acc::PointerLikeType>
31+
getPtrFromVar(mlir::Value var) {
32+
if (auto ptr =
33+
mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(var))
34+
return ptr;
35+
36+
if (auto load = mlir::dyn_cast_if_present<fir::LoadOp>(var.getDefiningOp())) {
37+
// All FIR reference types implement the PointerLikeType interface.
38+
return mlir::cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(
39+
load.getMemref());
40+
}
41+
42+
return {};
43+
}
44+
45+
template <>
46+
mlir::TypedValue<mlir::acc::PointerLikeType>
47+
OpenACCMappableModel<fir::SequenceType>::getVarPtr(mlir::Type type,
48+
mlir::Value var) const {
49+
return getPtrFromVar(var);
50+
}
51+
52+
template <>
53+
mlir::TypedValue<mlir::acc::PointerLikeType>
54+
OpenACCMappableModel<fir::BaseBoxType>::getVarPtr(mlir::Type type,
55+
mlir::Value var) const {
56+
return getPtrFromVar(var);
57+
}
58+
59+
template <>
60+
std::optional<llvm::TypeSize>
61+
OpenACCMappableModel<fir::SequenceType>::getSizeInBytes(
62+
mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
63+
const mlir::DataLayout &dataLayout) const {
64+
// TODO: Bounds operation affect the total size - add support to take them
65+
// into account.
66+
if (!accBounds.empty())
67+
return {};
68+
69+
// Dynamic extents or unknown ranks generally do not have compile-time
70+
// computable dimensions.
71+
auto seqType = mlir::cast<fir::SequenceType>(type);
72+
if (seqType.hasDynamicExtents() || seqType.hasUnknownShape())
73+
return {};
74+
75+
// Attempt to find an operation that a lookup for KindMapping can be done
76+
// from.
77+
mlir::Operation *kindMapSrcOp = var.getDefiningOp();
78+
if (!kindMapSrcOp) {
79+
kindMapSrcOp = var.getParentRegion()->getParentOp();
80+
if (!kindMapSrcOp)
81+
return {};
82+
}
83+
auto kindMap = fir::getKindMapping(kindMapSrcOp);
84+
85+
auto sizeAndAlignment =
86+
fir::getTypeSizeAndAlignment(var.getLoc(), type, dataLayout, kindMap);
87+
if (!sizeAndAlignment.has_value())
88+
return {};
89+
90+
return {llvm::TypeSize::getFixed(sizeAndAlignment->first)};
91+
}
92+
93+
template <>
94+
std::optional<llvm::TypeSize>
95+
OpenACCMappableModel<fir::BaseBoxType>::getSizeInBytes(
96+
mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
97+
const mlir::DataLayout &dataLayout) const {
98+
// If we have a box value instead of box reference, the intent is to
99+
// get the size of the data not the box itself.
100+
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
101+
if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
102+
fir::unwrapRefType(boxTy.getEleTy()))) {
103+
return mappableTy.getSizeInBytes(var, accBounds, dataLayout);
104+
}
105+
}
106+
// Size for boxes is not computable until it gets materialized.
107+
return {};
108+
}
109+
110+
template <>
111+
std::optional<int64_t>
112+
OpenACCMappableModel<fir::SequenceType>::getOffsetInBytes(
113+
mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
114+
const mlir::DataLayout &dataLayout) const {
115+
// TODO: Bounds operation affect the offset- add support to take them
116+
// into account.
117+
if (!accBounds.empty())
118+
return {};
119+
120+
// Dynamic extents (aka descriptor-based arrays) - may have a offset.
121+
// For example, a negative stride may mean a negative offset to compute the
122+
// start of array.
123+
auto seqType = mlir::cast<fir::SequenceType>(type);
124+
if (seqType.hasDynamicExtents() || seqType.hasUnknownShape())
125+
return {};
126+
127+
// We have non-dynamic extents - but if for some reason the size is not
128+
// computable - assume offset is not either. Otherwise, it is an offset of
129+
// zero.
130+
if (getSizeInBytes(type, var, accBounds, dataLayout).has_value()) {
131+
return {0};
132+
}
133+
return {};
134+
}
135+
136+
template <>
137+
std::optional<int64_t> OpenACCMappableModel<fir::BaseBoxType>::getOffsetInBytes(
138+
mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
139+
const mlir::DataLayout &dataLayout) const {
140+
// If we have a box value instead of box reference, the intent is to
141+
// get the offset of the data not the offset of the box itself.
142+
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
143+
if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
144+
fir::unwrapRefType(boxTy.getEleTy()))) {
145+
return mappableTy.getOffsetInBytes(var, accBounds, dataLayout);
146+
}
147+
}
148+
// Until boxes get materialized, the offset is not evident because it is
149+
// relative to the pointer being held.
150+
return {};
151+
}
152+
153+
template <>
154+
llvm::SmallVector<mlir::Value>
155+
OpenACCMappableModel<fir::SequenceType>::generateAccBounds(
156+
mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const {
157+
assert((mlir::isa<mlir::acc::PointerLikeType>(var.getType()) ||
158+
mlir::isa<mlir::acc::MappableType>(var.getType())) &&
159+
"must be pointer-like or mappable");
160+
161+
fir::FirOpBuilder firBuilder(builder, var.getDefiningOp());
162+
auto seqType = mlir::cast<fir::SequenceType>(type);
163+
mlir::Location loc = var.getLoc();
164+
165+
mlir::Value varPtr =
166+
mlir::isa<mlir::acc::PointerLikeType>(var.getType())
167+
? var
168+
: mlir::cast<mlir::acc::MappableType>(var.getType()).getVarPtr(var);
169+
170+
if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) {
171+
if (auto boxAddr =
172+
mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) {
173+
mlir::Value box = boxAddr.getVal();
174+
auto res =
175+
hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(box));
176+
fir::ExtendedValue exv = res.first;
177+
mlir::Value boxRef = box;
178+
if (auto boxPtr = getPtrFromVar(box)) {
179+
boxRef = boxPtr;
180+
}
181+
// TODO: Handle Fortran optional.
182+
const mlir::Value isPresent;
183+
Fortran::lower::AddrAndBoundsInfo info(box, boxRef, isPresent,
184+
box.getType());
185+
return Fortran::lower::genBoundsOpsFromBox<mlir::acc::DataBoundsOp,
186+
mlir::acc::DataBoundsType>(
187+
firBuilder, loc, exv, info);
188+
}
189+
assert(false && "array with unknown dimension expected to have descriptor");
190+
return {};
191+
}
192+
193+
// TODO: Detect assumed-size case.
194+
const bool isAssumedSize = false;
195+
auto valToCheck = varPtr;
196+
if (auto boxAddr =
197+
mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) {
198+
valToCheck = boxAddr.getVal();
199+
}
200+
auto res = hlfir::translateToExtendedValue(loc, firBuilder,
201+
hlfir::Entity(valToCheck));
202+
fir::ExtendedValue exv = res.first;
203+
return Fortran::lower::genBaseBoundsOps<mlir::acc::DataBoundsOp,
204+
mlir::acc::DataBoundsType>(
205+
firBuilder, loc, exv,
206+
/*isAssumedSize=*/isAssumedSize);
207+
}
208+
209+
template <>
210+
llvm::SmallVector<mlir::Value>
211+
OpenACCMappableModel<fir::BaseBoxType>::generateAccBounds(
212+
mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const {
213+
// If we have a box value instead of box reference, the intent is to
214+
// get the bounds of the data not the bounds of the box itself.
215+
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
216+
if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
217+
fir::unwrapRefType(boxTy.getEleTy()))) {
218+
mlir::Value data = builder.create<fir::BoxAddrOp>(var.getLoc(), var);
219+
return mappableTy.generateAccBounds(data, builder);
220+
}
221+
}
222+
// Box references are not arrays - thus generating acc.bounds does not make
223+
// sense.
224+
return {};
225+
}
226+
227+
} // namespace fir::acc
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- RegisterOpenACCExtensions.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+
// Registration for OpenACC extensions as applied to FIR dialect.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
14+
#include "flang/Optimizer/Dialect/FIRDialect.h"
15+
#include "flang/Optimizer/Dialect/FIRType.h"
16+
#include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h"
17+
18+
namespace fir::acc {
19+
void registerOpenACCExtensions(mlir::DialectRegistry &registry) {
20+
registry.addExtension(+[](mlir::MLIRContext *ctx,
21+
fir::FIROpsDialect *dialect) {
22+
fir::SequenceType::attachInterface<OpenACCMappableModel<fir::SequenceType>>(
23+
*ctx);
24+
fir::BoxType::attachInterface<OpenACCMappableModel<fir::BaseBoxType>>(*ctx);
25+
});
26+
}
27+
28+
} // namespace fir::acc

0 commit comments

Comments
 (0)