FLANG
DirectivesCommon.h
1//===-- DirectivesCommon.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// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
15//===----------------------------------------------------------------------===//
16
17#ifndef FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_
18#define FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_
19
20#include "flang/Optimizer/Builder/BoxValue.h"
21#include "flang/Optimizer/Builder/FIRBuilder.h"
22#include "flang/Optimizer/Builder/Todo.h"
23#include "flang/Optimizer/HLFIR/HLFIROps.h"
24#include "mlir/Dialect/OpenACC/OpenACC.h"
25#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
26
27namespace fir::factory {
28
32 explicit AddrAndBoundsInfo() {}
33 explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput)
34 : addr(addr), rawInput(rawInput) {}
35 explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput,
36 mlir::Value isPresent)
37 : addr(addr), rawInput(rawInput), isPresent(isPresent) {}
38 explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput,
39 mlir::Value isPresent, mlir::Type boxType)
40 : addr(addr), rawInput(rawInput), isPresent(isPresent), boxType(boxType) {
41 }
42 mlir::Value addr = nullptr;
43 mlir::Value rawInput = nullptr;
44 mlir::Value isPresent = nullptr;
45 mlir::Type boxType = nullptr;
46 void dump(llvm::raw_ostream &os) {
47 os << "AddrAndBoundsInfo addr: " << addr << "\n";
48 os << "AddrAndBoundsInfo rawInput: " << rawInput << "\n";
49 os << "AddrAndBoundsInfo isPresent: " << isPresent << "\n";
50 os << "AddrAndBoundsInfo boxType: " << boxType << "\n";
51 }
52};
53
54inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder,
55 mlir::Value symAddr,
56 bool isOptional,
57 mlir::Location loc) {
58 mlir::Value rawInput = symAddr;
59 if (auto declareOp =
60 mlir::dyn_cast_or_null<hlfir::DeclareOp>(symAddr.getDefiningOp())) {
61 symAddr = declareOp.getResults()[0];
62 rawInput = declareOp.getResults()[1];
63 }
64
65 if (!symAddr)
66 llvm::report_fatal_error("could not retrieve symbol address");
67
68 mlir::Value isPresent;
69 if (isOptional)
70 isPresent =
71 builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), rawInput);
72
73 if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(
74 fir::unwrapRefType(symAddr.getType()))) {
75 if (mlir::isa<fir::RecordType>(boxTy.getEleTy()))
76 TODO(loc, "derived type");
77
78 // In case of a box reference, load it here to get the box value.
79 // This is preferrable because then the same box value can then be used for
80 // all address/dimension retrievals. For Fortran optional though, leave
81 // the load generation for later so it can be done in the appropriate
82 // if branches.
83 if (mlir::isa<fir::ReferenceType>(symAddr.getType()) && !isOptional) {
84 mlir::Value addr = builder.create<fir::LoadOp>(loc, symAddr);
85 return AddrAndBoundsInfo(addr, rawInput, isPresent, boxTy);
86 }
87
88 return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy);
89 }
90 return AddrAndBoundsInfo(symAddr, rawInput, isPresent);
91}
92
93template <typename BoundsOp, typename BoundsType>
95gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc,
96 fir::ExtendedValue dataExv, mlir::Value box,
97 bool collectValuesOnly = false) {
98 assert(box && "box must exist");
100 mlir::Value byteStride;
101 mlir::Type idxTy = builder.getIndexType();
102 mlir::Type boundTy = builder.getType<BoundsType>();
103 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
104 for (unsigned dim = 0; dim < dataExv.rank(); ++dim) {
105 mlir::Value d = builder.createIntegerConstant(loc, idxTy, dim);
106 mlir::Value baseLb =
107 fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
108 auto dimInfo =
109 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, d);
110 mlir::Value lb = builder.createIntegerConstant(loc, idxTy, 0);
111 mlir::Value ub =
112 builder.create<mlir::arith::SubIOp>(loc, dimInfo.getExtent(), one);
113 if (dim == 0) // First stride is the element size.
114 byteStride = dimInfo.getByteStride();
115 if (collectValuesOnly) {
116 values.push_back(lb);
117 values.push_back(ub);
118 values.push_back(dimInfo.getExtent());
119 values.push_back(byteStride);
120 values.push_back(baseLb);
121 } else {
122 mlir::Value bound = builder.create<BoundsOp>(
123 loc, boundTy, lb, ub, dimInfo.getExtent(), byteStride, true, baseLb);
124 values.push_back(bound);
125 }
126 // Compute the stride for the next dimension.
127 byteStride = builder.create<mlir::arith::MulIOp>(loc, byteStride,
128 dimInfo.getExtent());
129 }
130 return values;
131}
132
134template <typename BoundsOp, typename BoundsType>
136genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc,
137 fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) {
139 mlir::Type idxTy = builder.getIndexType();
140 mlir::Type boundTy = builder.getType<BoundsType>();
141
142 assert(mlir::isa<fir::BaseBoxType>(info.boxType) &&
143 "expect fir.box or fir.class");
144 assert(fir::unwrapRefType(info.addr.getType()) == info.boxType &&
145 "expected box type consistency");
146
147 if (info.isPresent) {
149 constexpr unsigned nbValuesPerBound = 5;
150 for (unsigned dim = 0; dim < dataExv.rank() * nbValuesPerBound; ++dim)
151 resTypes.push_back(idxTy);
152
153 mlir::Operation::result_range ifRes =
154 builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true)
155 .genThen([&]() {
156 mlir::Value box =
157 !fir::isBoxAddress(info.addr.getType())
158 ? info.addr
159 : builder.create<fir::LoadOp>(loc, info.addr);
161 gatherBoundsOrBoundValues<BoundsOp, BoundsType>(
162 builder, loc, dataExv, box,
163 /*collectValuesOnly=*/true);
164 builder.create<fir::ResultOp>(loc, boundValues);
165 })
166 .genElse([&] {
167 // Box is not present. Populate bound values with default values.
169 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
170 mlir::Value mOne = builder.createMinusOneInteger(loc, idxTy);
171 for (unsigned dim = 0; dim < dataExv.rank(); ++dim) {
172 boundValues.push_back(zero); // lb
173 boundValues.push_back(mOne); // ub
174 boundValues.push_back(zero); // extent
175 boundValues.push_back(zero); // byteStride
176 boundValues.push_back(zero); // baseLb
177 }
178 builder.create<fir::ResultOp>(loc, boundValues);
179 })
180 .getResults();
181 // Create the bound operations outside the if-then-else with the if op
182 // results.
183 for (unsigned i = 0; i < ifRes.size(); i += nbValuesPerBound) {
184 mlir::Value bound = builder.create<BoundsOp>(
185 loc, boundTy, ifRes[i], ifRes[i + 1], ifRes[i + 2], ifRes[i + 3],
186 true, ifRes[i + 4]);
187 bounds.push_back(bound);
188 }
189 } else {
190 mlir::Value box = !fir::isBoxAddress(info.addr.getType())
191 ? info.addr
192 : builder.create<fir::LoadOp>(loc, info.addr);
193 bounds = gatherBoundsOrBoundValues<BoundsOp, BoundsType>(builder, loc,
194 dataExv, box);
195 }
196 return bounds;
197}
198
201template <typename BoundsOp, typename BoundsType>
203genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
204 fir::ExtendedValue dataExv, bool isAssumedSize) {
205 mlir::Type idxTy = builder.getIndexType();
206 mlir::Type boundTy = builder.getType<BoundsType>();
208
209 if (dataExv.rank() == 0)
210 return bounds;
211
212 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
213 const unsigned rank = dataExv.rank();
214 for (unsigned dim = 0; dim < rank; ++dim) {
215 mlir::Value baseLb =
216 fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
217 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
218 mlir::Value ub;
219 mlir::Value lb = zero;
220 mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim);
221 if (isAssumedSize && dim + 1 == rank) {
222 ext = zero;
223 ub = lb;
224 } else {
225 // ub = extent - 1
226 ub = builder.create<mlir::arith::SubIOp>(loc, ext, one);
227 }
228
229 mlir::Value bound =
230 builder.create<BoundsOp>(loc, boundTy, lb, ub, ext, one, false, baseLb);
231 bounds.push_back(bound);
232 }
233 return bounds;
234}
235
236template <typename BoundsOp, typename BoundsType>
238genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info,
239 fir::ExtendedValue dataExv, bool dataExvIsAssumedSize,
240 mlir::Location loc) {
242
243 mlir::Value baseOp = info.rawInput;
244 if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(baseOp.getType())))
245 bounds =
246 genBoundsOpsFromBox<BoundsOp, BoundsType>(builder, loc, dataExv, info);
247 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(baseOp.getType()))) {
248 bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, loc, dataExv,
249 dataExvIsAssumedSize);
250 }
251
252 return bounds;
253}
254
255} // namespace fir::factory
256#endif // FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_
Definition: BoxValue.h:478
Definition: FIRBuilder.h:55
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, mlir::Value cdt, bool withElseRegion)
Definition: FIRBuilder.h:463
mlir::Value createMinusOneInteger(mlir::Location loc, mlir::Type integerType)
Definition: FIRBuilder.h:187
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, std::int64_t i)
Definition: FIRBuilder.cpp:131
Definition: OpenACC.h:20
Definition: BoxValue.h:445
llvm::SmallVector< mlir::Value > genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, AddrAndBoundsInfo &info)
Generate the bounds operation from the descriptor information.
Definition: DirectivesCommon.h:136
mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim, mlir::Value defaultValue)
Definition: FIRBuilder.cpp:905
llvm::SmallVector< mlir::Value > genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, bool isAssumedSize)
Definition: DirectivesCommon.h:203
mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim)
Read or get the extent in dimension dim of the array described by box.
Definition: FIRBuilder.cpp:873
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition: FIRType.h:475
Definition: DirectivesCommon.h:31