1 //===-- FIROpenACCTypeInterfaces.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Implementation of external dialect interfaces for FIR.
11 //===----------------------------------------------------------------------===//
13 #include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h"
14 #include "flang/Optimizer/Builder/BoxValue.h"
15 #include "flang/Optimizer/Builder/DirectivesCommon.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"
30 static mlir::TypedValue
<mlir::acc::PointerLikeType
>
31 getPtrFromVar(mlir::Value var
) {
33 mlir::dyn_cast
<mlir::TypedValue
<mlir::acc::PointerLikeType
>>(var
))
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
>>(
46 mlir::TypedValue
<mlir::acc::PointerLikeType
>
47 OpenACCMappableModel
<fir::SequenceType
>::getVarPtr(mlir::Type type
,
48 mlir::Value var
) const {
49 return getPtrFromVar(var
);
53 mlir::TypedValue
<mlir::acc::PointerLikeType
>
54 OpenACCMappableModel
<fir::BaseBoxType
>::getVarPtr(mlir::Type type
,
55 mlir::Value var
) const {
56 return getPtrFromVar(var
);
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
66 if (!accBounds
.empty())
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())
75 // Attempt to find an operation that a lookup for KindMapping can be done
77 mlir::Operation
*kindMapSrcOp
= var
.getDefiningOp();
79 kindMapSrcOp
= var
.getParentRegion()->getParentOp();
83 auto kindMap
= fir::getKindMapping(kindMapSrcOp
);
85 auto sizeAndAlignment
=
86 fir::getTypeSizeAndAlignment(var
.getLoc(), type
, dataLayout
, kindMap
);
87 if (!sizeAndAlignment
.has_value())
90 return {llvm::TypeSize::getFixed(sizeAndAlignment
->first
)};
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
);
106 // Size for boxes is not computable until it gets materialized.
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
117 if (!accBounds
.empty())
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
123 auto seqType
= mlir::cast
<fir::SequenceType
>(type
);
124 if (seqType
.hasDynamicExtents() || seqType
.hasUnknownShape())
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
130 if (getSizeInBytes(type
, var
, accBounds
, dataLayout
).has_value()) {
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
);
148 // Until boxes get materialized, the offset is not evident because it is
149 // relative to the pointer being held.
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");
161 fir::FirOpBuilder
firBuilder(builder
, var
.getDefiningOp());
162 auto seqType
= mlir::cast
<fir::SequenceType
>(type
);
163 mlir::Location loc
= var
.getLoc();
166 mlir::isa
<mlir::acc::PointerLikeType
>(var
.getType())
168 : mlir::cast
<mlir::acc::MappableType
>(var
.getType()).getVarPtr(var
);
170 if (seqType
.hasDynamicExtents() || seqType
.hasUnknownShape()) {
172 mlir::dyn_cast_if_present
<fir::BoxAddrOp
>(varPtr
.getDefiningOp())) {
173 mlir::Value box
= boxAddr
.getVal();
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
)) {
181 // TODO: Handle Fortran optional.
182 const mlir::Value isPresent
;
183 fir::factory::AddrAndBoundsInfo
info(box
, boxRef
, isPresent
,
185 return fir::factory::genBoundsOpsFromBox
<mlir::acc::DataBoundsOp
,
186 mlir::acc::DataBoundsType
>(
187 firBuilder
, loc
, exv
, info
);
189 assert(false && "array with unknown dimension expected to have descriptor");
193 // TODO: Detect assumed-size case.
194 const bool isAssumedSize
= false;
195 auto valToCheck
= varPtr
;
197 mlir::dyn_cast_if_present
<fir::BoxAddrOp
>(varPtr
.getDefiningOp())) {
198 valToCheck
= boxAddr
.getVal();
200 auto res
= hlfir::translateToExtendedValue(loc
, firBuilder
,
201 hlfir::Entity(valToCheck
));
202 fir::ExtendedValue exv
= res
.first
;
203 return fir::factory::genBaseBoundsOps
<mlir::acc::DataBoundsOp
,
204 mlir::acc::DataBoundsType
>(
205 firBuilder
, loc
, exv
,
206 /*isAssumedSize=*/isAssumedSize
);
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
);
222 // Box references are not arrays - thus generating acc.bounds does not make
227 } // namespace fir::acc