File: | build/source/flang/lib/Optimizer/Builder/HLFIRTools.cpp |
Warning: | line 762, column 16 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- HLFIRTools.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 | // Tools to manipulate HLFIR variable and expressions | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #include "flang/Optimizer/Builder/HLFIRTools.h" | |||
14 | #include "flang/Optimizer/Builder/Character.h" | |||
15 | #include "flang/Optimizer/Builder/FIRBuilder.h" | |||
16 | #include "flang/Optimizer/Builder/MutableBox.h" | |||
17 | #include "flang/Optimizer/Builder/Todo.h" | |||
18 | #include "flang/Optimizer/HLFIR/HLFIROps.h" | |||
19 | #include "mlir/IR/IRMapping.h" | |||
20 | #include "mlir/Support/LLVM.h" | |||
21 | #include "llvm/ADT/TypeSwitch.h" | |||
22 | #include <optional> | |||
23 | ||||
24 | // Return explicit extents. If the base is a fir.box, this won't read it to | |||
25 | // return the extents and will instead return an empty vector. | |||
26 | llvm::SmallVector<mlir::Value> | |||
27 | hlfir::getExplicitExtentsFromShape(mlir::Value shape, | |||
28 | fir::FirOpBuilder &builder) { | |||
29 | llvm::SmallVector<mlir::Value> result; | |||
30 | auto *shapeOp = shape.getDefiningOp(); | |||
31 | if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) { | |||
32 | auto e = s.getExtents(); | |||
33 | result.append(e.begin(), e.end()); | |||
34 | } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) { | |||
35 | auto e = s.getExtents(); | |||
36 | result.append(e.begin(), e.end()); | |||
37 | } else if (mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) { | |||
38 | return {}; | |||
39 | } else if (auto s = mlir::dyn_cast_or_null<hlfir::ShapeOfOp>(shapeOp)) { | |||
40 | hlfir::ExprType expr = s.getExpr().getType().cast<hlfir::ExprType>(); | |||
41 | llvm::ArrayRef<int64_t> exprShape = expr.getShape(); | |||
42 | mlir::Type indexTy = builder.getIndexType(); | |||
43 | fir::ShapeType shapeTy = shape.getType().cast<fir::ShapeType>(); | |||
44 | result.reserve(shapeTy.getRank()); | |||
45 | for (unsigned i = 0; i < shapeTy.getRank(); ++i) { | |||
46 | int64_t extent = exprShape[i]; | |||
47 | mlir::Value extentVal; | |||
48 | if (extent == expr.getUnknownExtent()) { | |||
49 | auto op = builder.create<hlfir::GetExtentOp>(shape.getLoc(), shape, i); | |||
50 | extentVal = op.getResult(); | |||
51 | } else { | |||
52 | extentVal = | |||
53 | builder.createIntegerConstant(shape.getLoc(), indexTy, extent); | |||
54 | } | |||
55 | result.emplace_back(extentVal); | |||
56 | } | |||
57 | } else { | |||
58 | TODO(shape.getLoc(), "read fir.shape to get extents")do { fir::emitFatalError(shape.getLoc(), llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "58" ": not yet implemented: ") + llvm::Twine("read fir.shape to get extents" ), false); } while (false); | |||
59 | } | |||
60 | return result; | |||
61 | } | |||
62 | static llvm::SmallVector<mlir::Value> | |||
63 | getExplicitExtents(fir::FortranVariableOpInterface var, | |||
64 | fir::FirOpBuilder &builder) { | |||
65 | if (mlir::Value shape = var.getShape()) | |||
66 | return hlfir::getExplicitExtentsFromShape(var.getShape(), builder); | |||
67 | return {}; | |||
68 | } | |||
69 | ||||
70 | // Return explicit lower bounds. For pointers and allocatables, this will not | |||
71 | // read the lower bounds and instead return an empty vector. | |||
72 | static llvm::SmallVector<mlir::Value> | |||
73 | getExplicitLboundsFromShape(mlir::Value shape) { | |||
74 | llvm::SmallVector<mlir::Value> result; | |||
75 | auto *shapeOp = shape.getDefiningOp(); | |||
76 | if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) { | |||
77 | return {}; | |||
78 | } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) { | |||
79 | auto e = s.getOrigins(); | |||
80 | result.append(e.begin(), e.end()); | |||
81 | } else if (auto s = mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) { | |||
82 | auto e = s.getOrigins(); | |||
83 | result.append(e.begin(), e.end()); | |||
84 | } else { | |||
85 | TODO(shape.getLoc(), "read fir.shape to get lower bounds")do { fir::emitFatalError(shape.getLoc(), llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "85" ": not yet implemented: ") + llvm::Twine("read fir.shape to get lower bounds" ), false); } while (false); | |||
86 | } | |||
87 | return result; | |||
88 | } | |||
89 | static llvm::SmallVector<mlir::Value> | |||
90 | getExplicitLbounds(fir::FortranVariableOpInterface var) { | |||
91 | if (mlir::Value shape = var.getShape()) | |||
92 | return getExplicitLboundsFromShape(shape); | |||
93 | return {}; | |||
94 | } | |||
95 | ||||
96 | static void | |||
97 | genLboundsAndExtentsFromBox(mlir::Location loc, fir::FirOpBuilder &builder, | |||
98 | hlfir::Entity boxEntity, | |||
99 | llvm::SmallVectorImpl<mlir::Value> &lbounds, | |||
100 | llvm::SmallVectorImpl<mlir::Value> *extents) { | |||
101 | assert(boxEntity.getType().isa<fir::BaseBoxType>() && "must be a box")(static_cast <bool> (boxEntity.getType().isa<fir::BaseBoxType >() && "must be a box") ? void (0) : __assert_fail ("boxEntity.getType().isa<fir::BaseBoxType>() && \"must be a box\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 101, __extension__ __PRETTY_FUNCTION__)); | |||
102 | mlir::Type idxTy = builder.getIndexType(); | |||
103 | const int rank = boxEntity.getRank(); | |||
104 | for (int i = 0; i < rank; ++i) { | |||
105 | mlir::Value dim = builder.createIntegerConstant(loc, idxTy, i); | |||
106 | auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, | |||
107 | boxEntity, dim); | |||
108 | lbounds.push_back(dimInfo.getLowerBound()); | |||
109 | if (extents) | |||
110 | extents->push_back(dimInfo.getExtent()); | |||
111 | } | |||
112 | } | |||
113 | ||||
114 | static llvm::SmallVector<mlir::Value> | |||
115 | getNonDefaultLowerBounds(mlir::Location loc, fir::FirOpBuilder &builder, | |||
116 | hlfir::Entity entity) { | |||
117 | if (!entity.hasNonDefaultLowerBounds()) | |||
118 | return {}; | |||
119 | if (auto varIface = entity.getIfVariableInterface()) { | |||
120 | llvm::SmallVector<mlir::Value> lbounds = getExplicitLbounds(varIface); | |||
121 | if (!lbounds.empty()) | |||
122 | return lbounds; | |||
123 | } | |||
124 | if (entity.isMutableBox()) | |||
125 | entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); | |||
126 | llvm::SmallVector<mlir::Value> lowerBounds; | |||
127 | genLboundsAndExtentsFromBox(loc, builder, entity, lowerBounds, | |||
128 | /*extents=*/nullptr); | |||
129 | return lowerBounds; | |||
130 | } | |||
131 | ||||
132 | static llvm::SmallVector<mlir::Value> toSmallVector(mlir::ValueRange range) { | |||
133 | llvm::SmallVector<mlir::Value> res; | |||
134 | res.append(range.begin(), range.end()); | |||
135 | return res; | |||
136 | } | |||
137 | ||||
138 | static llvm::SmallVector<mlir::Value> getExplicitTypeParams(hlfir::Entity var) { | |||
139 | if (auto varIface = var.getMaybeDereferencedVariableInterface()) | |||
140 | return toSmallVector(varIface.getExplicitTypeParams()); | |||
141 | return {}; | |||
142 | } | |||
143 | ||||
144 | static mlir::Value tryGettingNonDeferredCharLen(hlfir::Entity var) { | |||
145 | if (auto varIface = var.getMaybeDereferencedVariableInterface()) | |||
146 | if (!varIface.getExplicitTypeParams().empty()) | |||
147 | return varIface.getExplicitTypeParams()[0]; | |||
148 | return mlir::Value{}; | |||
149 | } | |||
150 | ||||
151 | static mlir::Value genCharacterVariableLength(mlir::Location loc, | |||
152 | fir::FirOpBuilder &builder, | |||
153 | hlfir::Entity var) { | |||
154 | if (mlir::Value len = tryGettingNonDeferredCharLen(var)) | |||
155 | return len; | |||
156 | auto charType = var.getFortranElementType().cast<fir::CharacterType>(); | |||
157 | if (charType.hasConstantLen()) | |||
158 | return builder.createIntegerConstant(loc, builder.getIndexType(), | |||
159 | charType.getLen()); | |||
160 | if (var.isMutableBox()) | |||
161 | var = hlfir::Entity{builder.create<fir::LoadOp>(loc, var)}; | |||
162 | mlir::Value len = fir::factory::CharacterExprHelper{builder, loc}.getLength( | |||
163 | var.getFirBase()); | |||
164 | assert(len && "failed to retrieve length")(static_cast <bool> (len && "failed to retrieve length" ) ? void (0) : __assert_fail ("len && \"failed to retrieve length\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 164, __extension__ __PRETTY_FUNCTION__)); | |||
165 | return len; | |||
166 | } | |||
167 | ||||
168 | static fir::CharBoxValue genUnboxChar(mlir::Location loc, | |||
169 | fir::FirOpBuilder &builder, | |||
170 | mlir::Value boxChar) { | |||
171 | if (auto emboxChar = boxChar.getDefiningOp<fir::EmboxCharOp>()) | |||
172 | return {emboxChar.getMemref(), emboxChar.getLen()}; | |||
173 | mlir::Type refType = fir::ReferenceType::get( | |||
174 | boxChar.getType().cast<fir::BoxCharType>().getEleTy()); | |||
175 | auto unboxed = builder.create<fir::UnboxCharOp>( | |||
176 | loc, refType, builder.getIndexType(), boxChar); | |||
177 | mlir::Value addr = unboxed.getResult(0); | |||
178 | mlir::Value len = unboxed.getResult(1); | |||
179 | if (auto varIface = boxChar.getDefiningOp<fir::FortranVariableOpInterface>()) | |||
180 | if (mlir::Value explicitlen = varIface.getExplicitCharLen()) | |||
181 | len = explicitlen; | |||
182 | return {addr, len}; | |||
183 | } | |||
184 | ||||
185 | mlir::Value hlfir::Entity::getFirBase() const { | |||
186 | if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) { | |||
187 | if (auto declareOp = | |||
188 | mlir::dyn_cast<hlfir::DeclareOp>(variable.getOperation())) | |||
189 | return declareOp.getOriginalBase(); | |||
190 | if (auto associateOp = | |||
191 | mlir::dyn_cast<hlfir::AssociateOp>(variable.getOperation())) | |||
192 | return associateOp.getFirBase(); | |||
193 | } | |||
194 | return getBase(); | |||
195 | } | |||
196 | ||||
197 | fir::FortranVariableOpInterface | |||
198 | hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder, | |||
199 | const fir::ExtendedValue &exv, llvm::StringRef name, | |||
200 | fir::FortranVariableFlagsAttr flags) { | |||
201 | ||||
202 | mlir::Value base = fir::getBase(exv); | |||
203 | assert(fir::conformsWithPassByRef(base.getType()) &&(static_cast <bool> (fir::conformsWithPassByRef(base.getType ()) && "entity being declared must be in memory") ? void (0) : __assert_fail ("fir::conformsWithPassByRef(base.getType()) && \"entity being declared must be in memory\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 204, __extension__ __PRETTY_FUNCTION__)) | |||
204 | "entity being declared must be in memory")(static_cast <bool> (fir::conformsWithPassByRef(base.getType ()) && "entity being declared must be in memory") ? void (0) : __assert_fail ("fir::conformsWithPassByRef(base.getType()) && \"entity being declared must be in memory\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 204, __extension__ __PRETTY_FUNCTION__)); | |||
205 | mlir::Value shapeOrShift; | |||
206 | llvm::SmallVector<mlir::Value> lenParams; | |||
207 | exv.match( | |||
208 | [&](const fir::CharBoxValue &box) { | |||
209 | lenParams.emplace_back(box.getLen()); | |||
210 | }, | |||
211 | [&](const fir::ArrayBoxValue &) { | |||
212 | shapeOrShift = builder.createShape(loc, exv); | |||
213 | }, | |||
214 | [&](const fir::CharArrayBoxValue &box) { | |||
215 | shapeOrShift = builder.createShape(loc, exv); | |||
216 | lenParams.emplace_back(box.getLen()); | |||
217 | }, | |||
218 | [&](const fir::BoxValue &box) { | |||
219 | if (!box.getLBounds().empty()) | |||
220 | shapeOrShift = builder.createShape(loc, exv); | |||
221 | lenParams.append(box.getExplicitParameters().begin(), | |||
222 | box.getExplicitParameters().end()); | |||
223 | }, | |||
224 | [&](const fir::MutableBoxValue &box) { | |||
225 | lenParams.append(box.nonDeferredLenParams().begin(), | |||
226 | box.nonDeferredLenParams().end()); | |||
227 | }, | |||
228 | [](const auto &) {}); | |||
229 | auto declareOp = builder.create<hlfir::DeclareOp>( | |||
230 | loc, base, name, shapeOrShift, lenParams, flags); | |||
231 | return mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation()); | |||
232 | } | |||
233 | ||||
234 | hlfir::AssociateOp hlfir::genAssociateExpr(mlir::Location loc, | |||
235 | fir::FirOpBuilder &builder, | |||
236 | hlfir::Entity value, | |||
237 | mlir::Type variableType, | |||
238 | llvm::StringRef name) { | |||
239 | assert(value.isValue() && "must not be a variable")(static_cast <bool> (value.isValue() && "must not be a variable" ) ? void (0) : __assert_fail ("value.isValue() && \"must not be a variable\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 239, __extension__ __PRETTY_FUNCTION__)); | |||
240 | mlir::Value shape{}; | |||
241 | if (value.isArray()) | |||
242 | shape = genShape(loc, builder, value); | |||
243 | ||||
244 | mlir::Value source = value; | |||
245 | // Lowered scalar expression values for numerical and logical may have a | |||
246 | // different type than what is required for the type in memory (logical | |||
247 | // expressions are typically manipulated as i1, but needs to be stored | |||
248 | // according to the fir.logical<kind> so that the storage size is correct). | |||
249 | // Character length mismatches are ignored (it is ok for one to be dynamic | |||
250 | // and the other static). | |||
251 | mlir::Type varEleTy = getFortranElementType(variableType); | |||
252 | mlir::Type valueEleTy = getFortranElementType(value.getType()); | |||
253 | if (varEleTy != valueEleTy && !(valueEleTy.isa<fir::CharacterType>() && | |||
254 | varEleTy.isa<fir::CharacterType>())) { | |||
255 | assert(value.isScalar() && fir::isa_trivial(value.getType()))(static_cast <bool> (value.isScalar() && fir::isa_trivial (value.getType())) ? void (0) : __assert_fail ("value.isScalar() && fir::isa_trivial(value.getType())" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 255, __extension__ __PRETTY_FUNCTION__)); | |||
256 | source = builder.createConvert(loc, fir::unwrapPassByRefType(variableType), | |||
257 | value); | |||
258 | } | |||
259 | llvm::SmallVector<mlir::Value> lenParams; | |||
260 | genLengthParameters(loc, builder, value, lenParams); | |||
261 | return builder.create<hlfir::AssociateOp>(loc, source, name, shape, lenParams, | |||
262 | fir::FortranVariableFlagsAttr{}); | |||
263 | } | |||
264 | ||||
265 | mlir::Value hlfir::genVariableRawAddress(mlir::Location loc, | |||
266 | fir::FirOpBuilder &builder, | |||
267 | hlfir::Entity var) { | |||
268 | assert(var.isVariable() && "only address of variables can be taken")(static_cast <bool> (var.isVariable() && "only address of variables can be taken" ) ? void (0) : __assert_fail ("var.isVariable() && \"only address of variables can be taken\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 268, __extension__ __PRETTY_FUNCTION__)); | |||
269 | mlir::Value baseAddr = var.getFirBase(); | |||
270 | if (var.isMutableBox()) | |||
271 | baseAddr = builder.create<fir::LoadOp>(loc, baseAddr); | |||
272 | // Get raw address. | |||
273 | if (var.getType().isa<fir::BoxCharType>()) | |||
274 | baseAddr = genUnboxChar(loc, builder, var.getBase()).getAddr(); | |||
275 | if (baseAddr.getType().isa<fir::BaseBoxType>()) | |||
276 | baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr); | |||
277 | return baseAddr; | |||
278 | } | |||
279 | ||||
280 | mlir::Value hlfir::genVariableBoxChar(mlir::Location loc, | |||
281 | fir::FirOpBuilder &builder, | |||
282 | hlfir::Entity var) { | |||
283 | assert(var.isVariable() && "only address of variables can be taken")(static_cast <bool> (var.isVariable() && "only address of variables can be taken" ) ? void (0) : __assert_fail ("var.isVariable() && \"only address of variables can be taken\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 283, __extension__ __PRETTY_FUNCTION__)); | |||
284 | if (var.getType().isa<fir::BoxCharType>()) | |||
285 | return var; | |||
286 | mlir::Value addr = genVariableRawAddress(loc, builder, var); | |||
287 | llvm::SmallVector<mlir::Value> lengths; | |||
288 | genLengthParameters(loc, builder, var, lengths); | |||
289 | assert(lengths.size() == 1)(static_cast <bool> (lengths.size() == 1) ? void (0) : __assert_fail ("lengths.size() == 1", "flang/lib/Optimizer/Builder/HLFIRTools.cpp" , 289, __extension__ __PRETTY_FUNCTION__)); | |||
290 | auto charType = var.getFortranElementType().cast<fir::CharacterType>(); | |||
291 | auto boxCharType = | |||
292 | fir::BoxCharType::get(builder.getContext(), charType.getFKind()); | |||
293 | auto scalarAddr = | |||
294 | builder.createConvert(loc, fir::ReferenceType::get(charType), addr); | |||
295 | return builder.create<fir::EmboxCharOp>(loc, boxCharType, scalarAddr, | |||
296 | lengths[0]); | |||
297 | } | |||
298 | ||||
299 | hlfir::Entity hlfir::genVariableBox(mlir::Location loc, | |||
300 | fir::FirOpBuilder &builder, | |||
301 | hlfir::Entity var) { | |||
302 | assert(var.isVariable() && "must be a variable")(static_cast <bool> (var.isVariable() && "must be a variable" ) ? void (0) : __assert_fail ("var.isVariable() && \"must be a variable\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 302, __extension__ __PRETTY_FUNCTION__)); | |||
303 | var = hlfir::derefPointersAndAllocatables(loc, builder, var); | |||
304 | if (var.getType().isa<fir::BaseBoxType>()) | |||
305 | return var; | |||
306 | // Note: if the var is not a fir.box/fir.class at that point, it has default | |||
307 | // lower bounds and is not polymorphic. | |||
308 | mlir::Value shape = | |||
309 | var.isArray() ? hlfir::genShape(loc, builder, var) : mlir::Value{}; | |||
310 | llvm::SmallVector<mlir::Value> typeParams; | |||
311 | auto maybeCharType = | |||
312 | var.getFortranElementType().dyn_cast<fir::CharacterType>(); | |||
313 | if (!maybeCharType || maybeCharType.hasDynamicLen()) | |||
314 | hlfir::genLengthParameters(loc, builder, var, typeParams); | |||
315 | mlir::Value addr = var.getBase(); | |||
316 | if (var.getType().isa<fir::BoxCharType>()) | |||
317 | addr = genVariableRawAddress(loc, builder, var); | |||
318 | mlir::Type boxType = fir::BoxType::get(var.getElementOrSequenceType()); | |||
319 | auto embox = | |||
320 | builder.create<fir::EmboxOp>(loc, boxType, addr, shape, | |||
321 | /*slice=*/mlir::Value{}, typeParams); | |||
322 | return hlfir::Entity{embox.getResult()}; | |||
323 | } | |||
324 | ||||
325 | hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc, | |||
326 | fir::FirOpBuilder &builder, | |||
327 | Entity entity) { | |||
328 | entity = derefPointersAndAllocatables(loc, builder, entity); | |||
329 | if (entity.isVariable() && entity.isScalar() && | |||
330 | fir::isa_trivial(entity.getFortranElementType())) { | |||
331 | return Entity{builder.create<fir::LoadOp>(loc, entity)}; | |||
332 | } | |||
333 | return entity; | |||
334 | } | |||
335 | ||||
336 | hlfir::Entity hlfir::getElementAt(mlir::Location loc, | |||
337 | fir::FirOpBuilder &builder, Entity entity, | |||
338 | mlir::ValueRange oneBasedIndices) { | |||
339 | if (entity.isScalar()) | |||
340 | return entity; | |||
341 | llvm::SmallVector<mlir::Value> lenParams; | |||
342 | genLengthParameters(loc, builder, entity, lenParams); | |||
343 | if (entity.getType().isa<hlfir::ExprType>()) | |||
344 | return hlfir::Entity{builder.create<hlfir::ApplyOp>( | |||
345 | loc, entity, oneBasedIndices, lenParams)}; | |||
346 | // Build hlfir.designate. The lower bounds may need to be added to | |||
347 | // the oneBasedIndices since hlfir.designate expect indices | |||
348 | // based on the array operand lower bounds. | |||
349 | mlir::Type resultType = hlfir::getVariableElementType(entity); | |||
350 | hlfir::DesignateOp designate; | |||
351 | llvm::SmallVector<mlir::Value> lbounds = | |||
352 | getNonDefaultLowerBounds(loc, builder, entity); | |||
353 | if (!lbounds.empty()) { | |||
354 | llvm::SmallVector<mlir::Value> indices; | |||
355 | mlir::Type idxTy = builder.getIndexType(); | |||
356 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); | |||
357 | for (auto [oneBased, lb] : llvm::zip(oneBasedIndices, lbounds)) { | |||
358 | auto lbIdx = builder.createConvert(loc, idxTy, lb); | |||
359 | auto oneBasedIdx = builder.createConvert(loc, idxTy, oneBased); | |||
360 | auto shift = builder.create<mlir::arith::SubIOp>(loc, lbIdx, one); | |||
361 | mlir::Value index = | |||
362 | builder.create<mlir::arith::AddIOp>(loc, oneBasedIdx, shift); | |||
363 | indices.push_back(index); | |||
364 | } | |||
365 | designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity, | |||
366 | indices, lenParams); | |||
367 | } else { | |||
368 | designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity, | |||
369 | oneBasedIndices, lenParams); | |||
370 | } | |||
371 | return mlir::cast<fir::FortranVariableOpInterface>(designate.getOperation()); | |||
372 | } | |||
373 | ||||
374 | static mlir::Value genUBound(mlir::Location loc, fir::FirOpBuilder &builder, | |||
375 | mlir::Value lb, mlir::Value extent, | |||
376 | mlir::Value one) { | |||
377 | if (auto constantLb = fir::getIntIfConstant(lb)) | |||
378 | if (*constantLb == 1) | |||
379 | return extent; | |||
380 | extent = builder.createConvert(loc, one.getType(), extent); | |||
381 | lb = builder.createConvert(loc, one.getType(), lb); | |||
382 | auto add = builder.create<mlir::arith::AddIOp>(loc, lb, extent); | |||
383 | return builder.create<mlir::arith::SubIOp>(loc, add, one); | |||
384 | } | |||
385 | ||||
386 | llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> | |||
387 | hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder, | |||
388 | Entity entity) { | |||
389 | if (entity.getType().isa<hlfir::ExprType>()) | |||
390 | TODO(loc, "bounds of expressions in hlfir")do { fir::emitFatalError(loc, llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "390" ": not yet implemented: ") + llvm::Twine("bounds of expressions in hlfir" ), false); } while (false); | |||
391 | auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); | |||
392 | assert(!cleanup && "translation of entity should not yield cleanup")(static_cast <bool> (!cleanup && "translation of entity should not yield cleanup" ) ? void (0) : __assert_fail ("!cleanup && \"translation of entity should not yield cleanup\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 392, __extension__ __PRETTY_FUNCTION__)); | |||
393 | if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>()) | |||
394 | exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox); | |||
395 | mlir::Type idxTy = builder.getIndexType(); | |||
396 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); | |||
397 | llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result; | |||
398 | for (unsigned dim = 0; dim < exv.rank(); ++dim) { | |||
399 | mlir::Value extent = fir::factory::readExtent(builder, loc, exv, dim); | |||
400 | mlir::Value lb = fir::factory::readLowerBound(builder, loc, exv, dim, one); | |||
401 | mlir::Value ub = genUBound(loc, builder, lb, extent, one); | |||
402 | result.push_back({lb, ub}); | |||
403 | } | |||
404 | return result; | |||
405 | } | |||
406 | ||||
407 | llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> | |||
408 | hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder, | |||
409 | mlir::Value shape) { | |||
410 | assert((shape.getType().isa<fir::ShapeShiftType>() ||(static_cast <bool> ((shape.getType().isa<fir::ShapeShiftType >() || shape.getType().isa<fir::ShapeType>()) && "shape must contain extents") ? void (0) : __assert_fail ("(shape.getType().isa<fir::ShapeShiftType>() || shape.getType().isa<fir::ShapeType>()) && \"shape must contain extents\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 412, __extension__ __PRETTY_FUNCTION__)) | |||
411 | shape.getType().isa<fir::ShapeType>()) &&(static_cast <bool> ((shape.getType().isa<fir::ShapeShiftType >() || shape.getType().isa<fir::ShapeType>()) && "shape must contain extents") ? void (0) : __assert_fail ("(shape.getType().isa<fir::ShapeShiftType>() || shape.getType().isa<fir::ShapeType>()) && \"shape must contain extents\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 412, __extension__ __PRETTY_FUNCTION__)) | |||
412 | "shape must contain extents")(static_cast <bool> ((shape.getType().isa<fir::ShapeShiftType >() || shape.getType().isa<fir::ShapeType>()) && "shape must contain extents") ? void (0) : __assert_fail ("(shape.getType().isa<fir::ShapeShiftType>() || shape.getType().isa<fir::ShapeType>()) && \"shape must contain extents\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 412, __extension__ __PRETTY_FUNCTION__)); | |||
413 | auto extents = hlfir::getExplicitExtentsFromShape(shape, builder); | |||
414 | auto lowers = getExplicitLboundsFromShape(shape); | |||
415 | assert(lowers.empty() || lowers.size() == extents.size())(static_cast <bool> (lowers.empty() || lowers.size() == extents.size()) ? void (0) : __assert_fail ("lowers.empty() || lowers.size() == extents.size()" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 415, __extension__ __PRETTY_FUNCTION__)); | |||
416 | mlir::Type idxTy = builder.getIndexType(); | |||
417 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); | |||
418 | llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result; | |||
419 | for (auto extent : llvm::enumerate(extents)) { | |||
420 | mlir::Value lb = lowers.empty() ? one : lowers[extent.index()]; | |||
421 | mlir::Value ub = lowers.empty() | |||
422 | ? extent.value() | |||
423 | : genUBound(loc, builder, lb, extent.value(), one); | |||
424 | result.push_back({lb, ub}); | |||
425 | } | |||
426 | return result; | |||
427 | } | |||
428 | ||||
429 | llvm::SmallVector<mlir::Value> hlfir::genLowerbounds(mlir::Location loc, | |||
430 | fir::FirOpBuilder &builder, | |||
431 | mlir::Value shape, | |||
432 | unsigned rank) { | |||
433 | llvm::SmallVector<mlir::Value> lbounds; | |||
434 | if (shape) | |||
435 | lbounds = getExplicitLboundsFromShape(shape); | |||
436 | if (!lbounds.empty()) | |||
437 | return lbounds; | |||
438 | mlir::Value one = | |||
439 | builder.createIntegerConstant(loc, builder.getIndexType(), 1); | |||
440 | return llvm::SmallVector<mlir::Value>(rank, one); | |||
441 | } | |||
442 | ||||
443 | static hlfir::Entity followShapeInducingSource(hlfir::Entity entity) { | |||
444 | while (true) { | |||
445 | if (auto reassoc = entity.getDefiningOp<hlfir::NoReassocOp>()) { | |||
446 | entity = hlfir::Entity{reassoc.getVal()}; | |||
447 | continue; | |||
448 | } | |||
449 | if (auto asExpr = entity.getDefiningOp<hlfir::AsExprOp>()) { | |||
450 | entity = hlfir::Entity{asExpr.getVar()}; | |||
451 | continue; | |||
452 | } | |||
453 | break; | |||
454 | } | |||
455 | return entity; | |||
456 | } | |||
457 | ||||
458 | static mlir::Value computeVariableExtent(mlir::Location loc, | |||
459 | fir::FirOpBuilder &builder, | |||
460 | hlfir::Entity variable, | |||
461 | fir::SequenceType seqTy, | |||
462 | unsigned dim) { | |||
463 | mlir::Type idxTy = builder.getIndexType(); | |||
464 | if (seqTy.getShape().size() > dim) { | |||
465 | fir::SequenceType::Extent typeExtent = seqTy.getShape()[dim]; | |||
466 | if (typeExtent != fir::SequenceType::getUnknownExtent()) | |||
467 | return builder.createIntegerConstant(loc, idxTy, typeExtent); | |||
468 | } | |||
469 | assert(variable.getType().isa<fir::BaseBoxType>() &&(static_cast <bool> (variable.getType().isa<fir::BaseBoxType >() && "array variable with dynamic extent must be boxed" ) ? void (0) : __assert_fail ("variable.getType().isa<fir::BaseBoxType>() && \"array variable with dynamic extent must be boxed\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 470, __extension__ __PRETTY_FUNCTION__)) | |||
470 | "array variable with dynamic extent must be boxed")(static_cast <bool> (variable.getType().isa<fir::BaseBoxType >() && "array variable with dynamic extent must be boxed" ) ? void (0) : __assert_fail ("variable.getType().isa<fir::BaseBoxType>() && \"array variable with dynamic extent must be boxed\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 470, __extension__ __PRETTY_FUNCTION__)); | |||
471 | mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim); | |||
472 | auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, | |||
473 | variable, dimVal); | |||
474 | return dimInfo.getExtent(); | |||
475 | } | |||
476 | llvm::SmallVector<mlir::Value> getVariableExtents(mlir::Location loc, | |||
477 | fir::FirOpBuilder &builder, | |||
478 | hlfir::Entity variable) { | |||
479 | llvm::SmallVector<mlir::Value> extents; | |||
480 | if (fir::FortranVariableOpInterface varIface = | |||
481 | variable.getIfVariableInterface()) { | |||
482 | extents = getExplicitExtents(varIface, builder); | |||
483 | if (!extents.empty()) | |||
484 | return extents; | |||
485 | } | |||
486 | ||||
487 | if (variable.isMutableBox()) | |||
488 | variable = hlfir::derefPointersAndAllocatables(loc, builder, variable); | |||
489 | // Use the type shape information, and/or the fir.box/fir.class shape | |||
490 | // information if any extents are not static. | |||
491 | fir::SequenceType seqTy = | |||
492 | hlfir::getFortranElementOrSequenceType(variable.getType()) | |||
493 | .cast<fir::SequenceType>(); | |||
494 | unsigned rank = seqTy.getShape().size(); | |||
495 | for (unsigned dim = 0; dim < rank; ++dim) | |||
496 | extents.push_back( | |||
497 | computeVariableExtent(loc, builder, variable, seqTy, dim)); | |||
498 | return extents; | |||
499 | } | |||
500 | ||||
501 | static mlir::Value tryRetrievingShapeOrShift(hlfir::Entity entity) { | |||
502 | if (entity.getType().isa<hlfir::ExprType>()) { | |||
503 | if (auto elemental = entity.getDefiningOp<hlfir::ElementalOp>()) | |||
504 | return elemental.getShape(); | |||
505 | return mlir::Value{}; | |||
506 | } | |||
507 | if (auto varIface = entity.getIfVariableInterface()) | |||
508 | return varIface.getShape(); | |||
509 | return {}; | |||
510 | } | |||
511 | ||||
512 | mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder, | |||
513 | hlfir::Entity entity) { | |||
514 | assert(entity.isArray() && "entity must be an array")(static_cast <bool> (entity.isArray() && "entity must be an array" ) ? void (0) : __assert_fail ("entity.isArray() && \"entity must be an array\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 514, __extension__ __PRETTY_FUNCTION__)); | |||
515 | entity = followShapeInducingSource(entity); | |||
516 | assert(entity && "what?")(static_cast <bool> (entity && "what?") ? void ( 0) : __assert_fail ("entity && \"what?\"", "flang/lib/Optimizer/Builder/HLFIRTools.cpp" , 516, __extension__ __PRETTY_FUNCTION__)); | |||
517 | if (auto shape = tryRetrievingShapeOrShift(entity)) { | |||
518 | if (shape.getType().isa<fir::ShapeType>()) | |||
519 | return shape; | |||
520 | if (shape.getType().isa<fir::ShapeShiftType>()) | |||
521 | if (auto s = shape.getDefiningOp<fir::ShapeShiftOp>()) | |||
522 | return builder.create<fir::ShapeOp>(loc, s.getExtents()); | |||
523 | } | |||
524 | if (entity.getType().isa<hlfir::ExprType>()) | |||
525 | return builder.create<hlfir::ShapeOfOp>(loc, entity.getBase()); | |||
526 | // There is no shape lying around for this entity. Retrieve the extents and | |||
527 | // build a new fir.shape. | |||
528 | return builder.create<fir::ShapeOp>(loc, | |||
529 | getVariableExtents(loc, builder, entity)); | |||
530 | } | |||
531 | ||||
532 | llvm::SmallVector<mlir::Value> | |||
533 | hlfir::getIndexExtents(mlir::Location loc, fir::FirOpBuilder &builder, | |||
534 | mlir::Value shape) { | |||
535 | llvm::SmallVector<mlir::Value> extents = | |||
536 | hlfir::getExplicitExtentsFromShape(shape, builder); | |||
537 | mlir::Type indexType = builder.getIndexType(); | |||
538 | for (auto &extent : extents) | |||
539 | extent = builder.createConvert(loc, indexType, extent); | |||
540 | return extents; | |||
541 | } | |||
542 | ||||
543 | mlir::Value hlfir::genExtent(mlir::Location loc, fir::FirOpBuilder &builder, | |||
544 | hlfir::Entity entity, unsigned dim) { | |||
545 | entity = followShapeInducingSource(entity); | |||
546 | if (auto shape = tryRetrievingShapeOrShift(entity)) { | |||
547 | auto extents = hlfir::getExplicitExtentsFromShape(shape, builder); | |||
548 | if (!extents.empty()) { | |||
549 | assert(extents.size() > dim && "bad inquiry")(static_cast <bool> (extents.size() > dim && "bad inquiry") ? void (0) : __assert_fail ("extents.size() > dim && \"bad inquiry\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 549, __extension__ __PRETTY_FUNCTION__)); | |||
550 | return extents[dim]; | |||
551 | } | |||
552 | } | |||
553 | if (entity.isVariable()) { | |||
554 | if (entity.isMutableBox()) | |||
555 | entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); | |||
556 | // Use the type shape information, and/or the fir.box/fir.class shape | |||
557 | // information if any extents are not static. | |||
558 | fir::SequenceType seqTy = | |||
559 | hlfir::getFortranElementOrSequenceType(entity.getType()) | |||
560 | .cast<fir::SequenceType>(); | |||
561 | return computeVariableExtent(loc, builder, entity, seqTy, dim); | |||
562 | } | |||
563 | TODO(loc, "get extent from HLFIR expr without producer holding the shape")do { fir::emitFatalError(loc, llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "563" ": not yet implemented: ") + llvm::Twine("get extent from HLFIR expr without producer holding the shape" ), false); } while (false); | |||
564 | } | |||
565 | ||||
566 | mlir::Value hlfir::genLBound(mlir::Location loc, fir::FirOpBuilder &builder, | |||
567 | hlfir::Entity entity, unsigned dim) { | |||
568 | if (!entity.hasNonDefaultLowerBounds()) | |||
569 | return builder.createIntegerConstant(loc, builder.getIndexType(), 1); | |||
570 | if (auto shape = tryRetrievingShapeOrShift(entity)) { | |||
571 | auto lbounds = getExplicitLboundsFromShape(shape); | |||
572 | if (!lbounds.empty()) { | |||
573 | assert(lbounds.size() > dim && "bad inquiry")(static_cast <bool> (lbounds.size() > dim && "bad inquiry") ? void (0) : __assert_fail ("lbounds.size() > dim && \"bad inquiry\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 573, __extension__ __PRETTY_FUNCTION__)); | |||
574 | return lbounds[dim]; | |||
575 | } | |||
576 | } | |||
577 | if (entity.isMutableBox()) | |||
578 | entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); | |||
579 | assert(entity.getType().isa<fir::BaseBoxType>() && "must be a box")(static_cast <bool> (entity.getType().isa<fir::BaseBoxType >() && "must be a box") ? void (0) : __assert_fail ("entity.getType().isa<fir::BaseBoxType>() && \"must be a box\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 579, __extension__ __PRETTY_FUNCTION__)); | |||
580 | mlir::Type idxTy = builder.getIndexType(); | |||
581 | mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim); | |||
582 | auto dimInfo = | |||
583 | builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, entity, dimVal); | |||
584 | return dimInfo.getLowerBound(); | |||
585 | } | |||
586 | ||||
587 | void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, | |||
588 | Entity entity, | |||
589 | llvm::SmallVectorImpl<mlir::Value> &result) { | |||
590 | if (!entity.hasLengthParameters()) | |||
591 | return; | |||
592 | if (entity.getType().isa<hlfir::ExprType>()) { | |||
593 | mlir::Value expr = entity; | |||
594 | if (auto reassoc = expr.getDefiningOp<hlfir::NoReassocOp>()) | |||
595 | expr = reassoc.getVal(); | |||
596 | // Going through fir::ExtendedValue would create a temp, | |||
597 | // which is not desired for an inquiry. | |||
598 | // TODO: make this an interface when adding further character producing ops. | |||
599 | if (auto concat = expr.getDefiningOp<hlfir::ConcatOp>()) { | |||
600 | result.push_back(concat.getLength()); | |||
601 | return; | |||
602 | } else if (auto concat = expr.getDefiningOp<hlfir::SetLengthOp>()) { | |||
603 | result.push_back(concat.getLength()); | |||
604 | return; | |||
605 | } else if (auto asExpr = expr.getDefiningOp<hlfir::AsExprOp>()) { | |||
606 | hlfir::genLengthParameters(loc, builder, hlfir::Entity{asExpr.getVar()}, | |||
607 | result); | |||
608 | return; | |||
609 | } else if (auto elemental = expr.getDefiningOp<hlfir::ElementalOp>()) { | |||
610 | result.append(elemental.getTypeparams().begin(), | |||
611 | elemental.getTypeparams().end()); | |||
612 | return; | |||
613 | } else if (auto apply = expr.getDefiningOp<hlfir::ApplyOp>()) { | |||
614 | result.append(apply.getTypeparams().begin(), apply.getTypeparams().end()); | |||
615 | } | |||
616 | TODO(loc, "inquire type parameters of hlfir.expr")do { fir::emitFatalError(loc, llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "616" ": not yet implemented: ") + llvm::Twine("inquire type parameters of hlfir.expr" ), false); } while (false); | |||
617 | } | |||
618 | ||||
619 | if (entity.isCharacter()) { | |||
620 | result.push_back(genCharacterVariableLength(loc, builder, entity)); | |||
621 | return; | |||
622 | } | |||
623 | TODO(loc, "inquire PDTs length parameters in HLFIR")do { fir::emitFatalError(loc, llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "623" ": not yet implemented: ") + llvm::Twine("inquire PDTs length parameters in HLFIR" ), false); } while (false); | |||
624 | } | |||
625 | ||||
626 | mlir::Value hlfir::genCharLength(mlir::Location loc, fir::FirOpBuilder &builder, | |||
627 | hlfir::Entity entity) { | |||
628 | llvm::SmallVector<mlir::Value, 1> lenParams; | |||
629 | genLengthParameters(loc, builder, entity, lenParams); | |||
630 | assert(lenParams.size() == 1 && "characters must have one length parameters")(static_cast <bool> (lenParams.size() == 1 && "characters must have one length parameters" ) ? void (0) : __assert_fail ("lenParams.size() == 1 && \"characters must have one length parameters\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 630, __extension__ __PRETTY_FUNCTION__)); | |||
631 | return lenParams[0]; | |||
632 | } | |||
633 | ||||
634 | // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base. | |||
635 | static mlir::Value asEmboxShape(mlir::Location loc, fir::FirOpBuilder &builder, | |||
636 | const fir::ExtendedValue &exv, | |||
637 | mlir::Value shape) { | |||
638 | if (!shape) | |||
639 | return shape; | |||
640 | // fir.rebox does not need and does not accept extents (fir.shape or | |||
641 | // fir.shape_shift) since this information is already in the input fir.box, | |||
642 | // it only accepts fir.shift because local lower bounds may not be reflected | |||
643 | // in the fir.box. | |||
644 | if (fir::getBase(exv).getType().isa<fir::BaseBoxType>() && | |||
645 | !shape.getType().isa<fir::ShiftType>()) | |||
646 | return builder.createShape(loc, exv); | |||
647 | return shape; | |||
648 | } | |||
649 | ||||
650 | std::pair<mlir::Value, mlir::Value> hlfir::genVariableFirBaseShapeAndParams( | |||
651 | mlir::Location loc, fir::FirOpBuilder &builder, Entity entity, | |||
652 | llvm::SmallVectorImpl<mlir::Value> &typeParams) { | |||
653 | auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); | |||
654 | assert(!cleanup && "variable to Exv should not produce cleanup")(static_cast <bool> (!cleanup && "variable to Exv should not produce cleanup" ) ? void (0) : __assert_fail ("!cleanup && \"variable to Exv should not produce cleanup\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 654, __extension__ __PRETTY_FUNCTION__)); | |||
655 | if (entity.hasLengthParameters()) { | |||
656 | auto params = fir::getTypeParams(exv); | |||
657 | typeParams.append(params.begin(), params.end()); | |||
658 | } | |||
659 | if (entity.isScalar()) | |||
660 | return {fir::getBase(exv), mlir::Value{}}; | |||
661 | if (auto variableInterface = entity.getIfVariableInterface()) | |||
662 | return {fir::getBase(exv), | |||
663 | asEmboxShape(loc, builder, exv, variableInterface.getShape())}; | |||
664 | return {fir::getBase(exv), builder.createShape(loc, exv)}; | |||
665 | } | |||
666 | ||||
667 | hlfir::Entity hlfir::derefPointersAndAllocatables(mlir::Location loc, | |||
668 | fir::FirOpBuilder &builder, | |||
669 | Entity entity) { | |||
670 | if (entity.isMutableBox()) { | |||
671 | hlfir::Entity boxLoad{builder.create<fir::LoadOp>(loc, entity)}; | |||
672 | if (entity.isScalar()) { | |||
673 | if (!entity.isPolymorphic() && !entity.hasLengthParameters()) | |||
674 | return hlfir::Entity{builder.create<fir::BoxAddrOp>(loc, boxLoad)}; | |||
675 | mlir::Type elementType = boxLoad.getFortranElementType(); | |||
676 | if (auto charType = elementType.dyn_cast<fir::CharacterType>()) { | |||
677 | mlir::Value base = builder.create<fir::BoxAddrOp>(loc, boxLoad); | |||
678 | if (charType.hasConstantLen()) | |||
679 | return hlfir::Entity{base}; | |||
680 | mlir::Value len = genCharacterVariableLength(loc, builder, entity); | |||
681 | auto boxCharType = | |||
682 | fir::BoxCharType::get(builder.getContext(), charType.getFKind()); | |||
683 | return hlfir::Entity{ | |||
684 | builder.create<fir::EmboxCharOp>(loc, boxCharType, base, len) | |||
685 | .getResult()}; | |||
686 | } | |||
687 | } | |||
688 | // Otherwise, the entity is either an array, a polymorphic entity, or a | |||
689 | // derived type with length parameters. All these entities require a fir.box | |||
690 | // or fir.class to hold bounds, dynamic type or length parameter | |||
691 | // information. Keep them boxed. | |||
692 | return boxLoad; | |||
693 | } | |||
694 | return entity; | |||
695 | } | |||
696 | ||||
697 | mlir::Type hlfir::getVariableElementType(hlfir::Entity variable) { | |||
698 | assert(variable.isVariable() && "entity must be a variable")(static_cast <bool> (variable.isVariable() && "entity must be a variable" ) ? void (0) : __assert_fail ("variable.isVariable() && \"entity must be a variable\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 698, __extension__ __PRETTY_FUNCTION__)); | |||
699 | if (variable.isScalar()) | |||
700 | return variable.getType(); | |||
701 | mlir::Type eleTy = variable.getFortranElementType(); | |||
702 | if (variable.isPolymorphic()) | |||
703 | return fir::ClassType::get(eleTy); | |||
704 | if (auto charType = eleTy.dyn_cast<fir::CharacterType>()) { | |||
705 | if (charType.hasDynamicLen()) | |||
706 | return fir::BoxCharType::get(charType.getContext(), charType.getFKind()); | |||
707 | } else if (fir::isRecordWithTypeParameters(eleTy)) { | |||
708 | return fir::BoxType::get(eleTy); | |||
709 | } | |||
710 | return fir::ReferenceType::get(eleTy); | |||
711 | } | |||
712 | ||||
713 | static hlfir::ExprType getArrayExprType(mlir::Type elementType, | |||
714 | mlir::Value shape, bool isPolymorphic) { | |||
715 | unsigned rank = shape.getType().cast<fir::ShapeType>().getRank(); | |||
716 | hlfir::ExprType::Shape typeShape(rank, hlfir::ExprType::getUnknownExtent()); | |||
717 | if (auto shapeOp = shape.getDefiningOp<fir::ShapeOp>()) | |||
718 | for (auto extent : llvm::enumerate(shapeOp.getExtents())) | |||
719 | if (auto cstExtent = fir::getIntIfConstant(extent.value())) | |||
720 | typeShape[extent.index()] = *cstExtent; | |||
721 | return hlfir::ExprType::get(elementType.getContext(), typeShape, elementType, | |||
722 | isPolymorphic); | |||
723 | } | |||
724 | ||||
725 | hlfir::ElementalOp | |||
726 | hlfir::genElementalOp(mlir::Location loc, fir::FirOpBuilder &builder, | |||
727 | mlir::Type elementType, mlir::Value shape, | |||
728 | mlir::ValueRange typeParams, | |||
729 | const ElementalKernelGenerator &genKernel) { | |||
730 | mlir::Type exprType = getArrayExprType(elementType, shape, false); | |||
731 | auto elementalOp = | |||
732 | builder.create<hlfir::ElementalOp>(loc, exprType, shape, typeParams); | |||
733 | auto insertPt = builder.saveInsertionPoint(); | |||
734 | builder.setInsertionPointToStart(elementalOp.getBody()); | |||
735 | mlir::Value elementResult = genKernel(loc, builder, elementalOp.getIndices()); | |||
736 | // Numerical and logical scalars may be lowered to another type than the | |||
737 | // Fortran expression type (e.g i1 instead of fir.logical). Array expression | |||
738 | // values are typed according to their Fortran type. Insert a cast if needed | |||
739 | // here. | |||
740 | if (fir::isa_trivial(elementResult.getType())) | |||
741 | elementResult = builder.createConvert(loc, elementType, elementResult); | |||
742 | builder.create<hlfir::YieldElementOp>(loc, elementResult); | |||
743 | builder.restoreInsertionPoint(insertPt); | |||
744 | return elementalOp; | |||
745 | } | |||
746 | ||||
747 | // TODO: we do not actually need to clone the YieldElementOp, | |||
748 | // because returning its getElementValue() operand should be enough | |||
749 | // for all callers of this function. | |||
750 | hlfir::YieldElementOp | |||
751 | hlfir::inlineElementalOp(mlir::Location loc, fir::FirOpBuilder &builder, | |||
752 | hlfir::ElementalOp elemental, | |||
753 | mlir::ValueRange oneBasedIndices) { | |||
754 | // hlfir.elemental region is a SizedRegion<1>. | |||
755 | assert(elemental.getRegion().hasOneBlock() &&(static_cast <bool> (elemental.getRegion().hasOneBlock( ) && "expect elemental region to have one block") ? void (0) : __assert_fail ("elemental.getRegion().hasOneBlock() && \"expect elemental region to have one block\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 756, __extension__ __PRETTY_FUNCTION__)) | |||
| ||||
756 | "expect elemental region to have one block")(static_cast <bool> (elemental.getRegion().hasOneBlock( ) && "expect elemental region to have one block") ? void (0) : __assert_fail ("elemental.getRegion().hasOneBlock() && \"expect elemental region to have one block\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 756, __extension__ __PRETTY_FUNCTION__)); | |||
757 | mlir::IRMapping mapper; | |||
758 | mapper.map(elemental.getIndices(), oneBasedIndices); | |||
759 | mlir::Operation *newOp; | |||
760 | for (auto &op : elemental.getRegion().back().getOperations()) | |||
761 | newOp = builder.clone(op, mapper); | |||
762 | auto yield = mlir::dyn_cast_or_null<hlfir::YieldElementOp>(newOp); | |||
| ||||
763 | assert(yield && "last ElementalOp operation must be am hlfir.yield_element")(static_cast <bool> (yield && "last ElementalOp operation must be am hlfir.yield_element" ) ? void (0) : __assert_fail ("yield && \"last ElementalOp operation must be am hlfir.yield_element\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 763, __extension__ __PRETTY_FUNCTION__)); | |||
764 | return yield; | |||
765 | } | |||
766 | ||||
767 | std::pair<fir::DoLoopOp, llvm::SmallVector<mlir::Value>> | |||
768 | hlfir::genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder, | |||
769 | mlir::ValueRange extents) { | |||
770 | assert(!extents.empty() && "must have at least one extent")(static_cast <bool> (!extents.empty() && "must have at least one extent" ) ? void (0) : __assert_fail ("!extents.empty() && \"must have at least one extent\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 770, __extension__ __PRETTY_FUNCTION__)); | |||
771 | auto insPt = builder.saveInsertionPoint(); | |||
772 | llvm::SmallVector<mlir::Value> indices(extents.size()); | |||
773 | // Build loop nest from column to row. | |||
774 | auto one = builder.create<mlir::arith::ConstantIndexOp>(loc, 1); | |||
775 | mlir::Type indexType = builder.getIndexType(); | |||
776 | unsigned dim = extents.size() - 1; | |||
777 | fir::DoLoopOp innerLoop; | |||
778 | for (auto extent : llvm::reverse(extents)) { | |||
779 | auto ub = builder.createConvert(loc, indexType, extent); | |||
780 | innerLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one); | |||
781 | builder.setInsertionPointToStart(innerLoop.getBody()); | |||
782 | // Reverse the indices so they are in column-major order. | |||
783 | indices[dim--] = innerLoop.getInductionVar(); | |||
784 | } | |||
785 | builder.restoreInsertionPoint(insPt); | |||
786 | return {innerLoop, indices}; | |||
787 | } | |||
788 | ||||
789 | static fir::ExtendedValue | |||
790 | translateVariableToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, | |||
791 | hlfir::Entity variable) { | |||
792 | assert(variable.isVariable() && "must be a variable")(static_cast <bool> (variable.isVariable() && "must be a variable" ) ? void (0) : __assert_fail ("variable.isVariable() && \"must be a variable\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 792, __extension__ __PRETTY_FUNCTION__)); | |||
793 | /// When going towards FIR, use the original base value to avoid | |||
794 | /// introducing descriptors at runtime when they are not required. | |||
795 | mlir::Value firBase = variable.getFirBase(); | |||
796 | if (variable.isMutableBox()) | |||
797 | return fir::MutableBoxValue(firBase, getExplicitTypeParams(variable), | |||
798 | fir::MutableProperties{}); | |||
799 | ||||
800 | if (firBase.getType().isa<fir::BaseBoxType>()) { | |||
801 | if (!variable.isSimplyContiguous() || variable.isPolymorphic() || | |||
802 | variable.isDerivedWithLengthParameters() || variable.isOptional()) { | |||
803 | llvm::SmallVector<mlir::Value> nonDefaultLbounds = | |||
804 | getNonDefaultLowerBounds(loc, builder, variable); | |||
805 | return fir::BoxValue(firBase, nonDefaultLbounds, | |||
806 | getExplicitTypeParams(variable)); | |||
807 | } | |||
808 | // Otherwise, the variable can be represented in a fir::ExtendedValue | |||
809 | // without the overhead of a fir.box. | |||
810 | firBase = genVariableRawAddress(loc, builder, variable); | |||
811 | } | |||
812 | ||||
813 | if (variable.isScalar()) { | |||
814 | if (variable.isCharacter()) { | |||
815 | if (firBase.getType().isa<fir::BoxCharType>()) | |||
816 | return genUnboxChar(loc, builder, firBase); | |||
817 | mlir::Value len = genCharacterVariableLength(loc, builder, variable); | |||
818 | return fir::CharBoxValue{firBase, len}; | |||
819 | } | |||
820 | return firBase; | |||
821 | } | |||
822 | llvm::SmallVector<mlir::Value> extents; | |||
823 | llvm::SmallVector<mlir::Value> nonDefaultLbounds; | |||
824 | if (variable.getType().isa<fir::BaseBoxType>() && | |||
825 | !variable.getIfVariableInterface()) { | |||
826 | // This special case avoids generating two generating to sets of identical | |||
827 | // fir.box_dim to get both the lower bounds and extents. | |||
828 | genLboundsAndExtentsFromBox(loc, builder, variable, nonDefaultLbounds, | |||
829 | &extents); | |||
830 | } else { | |||
831 | extents = getVariableExtents(loc, builder, variable); | |||
832 | nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable); | |||
833 | } | |||
834 | if (variable.isCharacter()) | |||
835 | return fir::CharArrayBoxValue{ | |||
836 | firBase, genCharacterVariableLength(loc, builder, variable), extents, | |||
837 | nonDefaultLbounds}; | |||
838 | return fir::ArrayBoxValue{firBase, extents, nonDefaultLbounds}; | |||
839 | } | |||
840 | ||||
841 | fir::ExtendedValue | |||
842 | hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, | |||
843 | fir::FortranVariableOpInterface var) { | |||
844 | return translateVariableToExtendedValue(loc, builder, var); | |||
845 | } | |||
846 | ||||
847 | std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> | |||
848 | hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, | |||
849 | hlfir::Entity entity) { | |||
850 | if (entity.isVariable()) | |||
851 | return {translateVariableToExtendedValue(loc, builder, entity), | |||
852 | std::nullopt}; | |||
853 | ||||
854 | if (entity.isProcedure()) { | |||
855 | if (fir::isCharacterProcedureTuple(entity.getType())) { | |||
856 | auto [boxProc, len] = fir::factory::extractCharacterProcedureTuple( | |||
857 | builder, loc, entity, /*openBoxProc=*/false); | |||
858 | return {fir::CharBoxValue{boxProc, len}, std::nullopt}; | |||
859 | } | |||
860 | return {static_cast<mlir::Value>(entity), std::nullopt}; | |||
861 | } | |||
862 | ||||
863 | if (entity.getType().isa<hlfir::ExprType>()) { | |||
864 | hlfir::AssociateOp associate = hlfir::genAssociateExpr( | |||
865 | loc, builder, entity, entity.getType(), "adapt.valuebyref"); | |||
866 | auto *bldr = &builder; | |||
867 | hlfir::CleanupFunction cleanup = [bldr, loc, associate]() -> void { | |||
868 | bldr->create<hlfir::EndAssociateOp>(loc, associate); | |||
869 | }; | |||
870 | hlfir::Entity temp{associate.getBase()}; | |||
871 | return {translateToExtendedValue(loc, builder, temp).first, cleanup}; | |||
872 | } | |||
873 | return {{static_cast<mlir::Value>(entity)}, {}}; | |||
874 | } | |||
875 | ||||
876 | std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> | |||
877 | hlfir::convertToValue(mlir::Location loc, fir::FirOpBuilder &builder, | |||
878 | const hlfir::Entity &entity) { | |||
879 | auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); | |||
880 | // Load scalar references to integer, logical, real, or complex value | |||
881 | // to an mlir value, dereference allocatable and pointers, and get rid | |||
882 | // of fir.box that are not needed or create a copy into contiguous memory. | |||
883 | exv = exv.match( | |||
884 | [&](const fir::UnboxedValue &box) -> fir::ExtendedValue { | |||
885 | if (mlir::Type elementType = fir::dyn_cast_ptrEleTy(box.getType())) | |||
886 | if (fir::isa_trivial(elementType)) | |||
887 | return builder.create<fir::LoadOp>(loc, box); | |||
888 | return box; | |||
889 | }, | |||
890 | [&](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; }, | |||
891 | [&](const fir::ArrayBoxValue &box) -> fir::ExtendedValue { return box; }, | |||
892 | [&](const fir::CharArrayBoxValue &box) -> fir::ExtendedValue { | |||
893 | return box; | |||
894 | }, | |||
895 | [&](const auto &) -> fir::ExtendedValue { | |||
896 | TODO(loc, "lower descriptor designator to HLFIR value")do { fir::emitFatalError(loc, llvm::Twine("flang/lib/Optimizer/Builder/HLFIRTools.cpp" ":" "896" ": not yet implemented: ") + llvm::Twine("lower descriptor designator to HLFIR value" ), false); } while (false); | |||
897 | }); | |||
898 | return {exv, cleanup}; | |||
899 | } | |||
900 | ||||
901 | static fir::ExtendedValue placeTrivialInMemory(mlir::Location loc, | |||
902 | fir::FirOpBuilder &builder, | |||
903 | mlir::Value val, | |||
904 | mlir::Type targetType) { | |||
905 | auto temp = builder.createTemporary(loc, targetType); | |||
906 | if (targetType != val.getType()) | |||
907 | builder.createStoreWithConvert(loc, val, temp); | |||
908 | else | |||
909 | builder.create<fir::StoreOp>(loc, val, temp); | |||
910 | return temp; | |||
911 | } | |||
912 | ||||
913 | std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> | |||
914 | hlfir::convertToBox(mlir::Location loc, fir::FirOpBuilder &builder, | |||
915 | const hlfir::Entity &entity, mlir::Type targetType) { | |||
916 | auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); | |||
917 | // Procedure entities should not go through createBoxValue that embox | |||
918 | // object entities. Return the fir.boxproc directly. | |||
919 | if (entity.isProcedure()) | |||
920 | return {exv, cleanup}; | |||
921 | mlir::Value base = fir::getBase(exv); | |||
922 | if (fir::isa_trivial(base.getType())) | |||
923 | exv = placeTrivialInMemory(loc, builder, base, targetType); | |||
924 | fir::BoxValue box = fir::factory::createBoxValue(builder, loc, exv); | |||
925 | return {box, cleanup}; | |||
926 | } | |||
927 | ||||
928 | std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> | |||
929 | hlfir::convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder, | |||
930 | const hlfir::Entity &entity, mlir::Type targetType) { | |||
931 | hlfir::Entity derefedEntity = | |||
932 | hlfir::derefPointersAndAllocatables(loc, builder, entity); | |||
933 | auto [exv, cleanup] = | |||
934 | hlfir::translateToExtendedValue(loc, builder, derefedEntity); | |||
935 | mlir::Value base = fir::getBase(exv); | |||
936 | if (fir::isa_trivial(base.getType())) | |||
937 | exv = placeTrivialInMemory(loc, builder, base, targetType); | |||
938 | return {exv, cleanup}; | |||
939 | } | |||
940 | ||||
941 | /// Clone: | |||
942 | /// ``` | |||
943 | /// hlfir.elemental_addr %shape : !fir.shape<1> { | |||
944 | /// ^bb0(%i : index) | |||
945 | /// ..... | |||
946 | /// %hlfir.yield %scalarAddress : fir.ref<T> | |||
947 | /// } | |||
948 | /// ``` | |||
949 | // | |||
950 | /// into | |||
951 | /// | |||
952 | /// ``` | |||
953 | /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> { | |||
954 | /// ^bb0(%i : index) | |||
955 | /// ..... | |||
956 | /// %value = fir.load %scalarAddress : fir.ref<T> | |||
957 | /// %hlfir.yield_element %value : T | |||
958 | /// } | |||
959 | /// ``` | |||
960 | hlfir::ElementalOp | |||
961 | hlfir::cloneToElementalOp(mlir::Location loc, fir::FirOpBuilder &builder, | |||
962 | hlfir::ElementalAddrOp elementalAddrOp) { | |||
963 | hlfir::Entity scalarAddress = | |||
964 | hlfir::Entity{mlir::cast<hlfir::YieldOp>( | |||
965 | elementalAddrOp.getBody().back().getTerminator()) | |||
966 | .getEntity()}; | |||
967 | llvm::SmallVector<mlir::Value, 1> typeParams; | |||
968 | hlfir::genLengthParameters(loc, builder, scalarAddress, typeParams); | |||
969 | ||||
970 | builder.setInsertionPointAfter(elementalAddrOp); | |||
971 | auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b, | |||
972 | mlir::ValueRange oneBasedIndices) -> hlfir::Entity { | |||
973 | mlir::IRMapping mapper; | |||
974 | mapper.map(elementalAddrOp.getIndices(), oneBasedIndices); | |||
975 | mlir::Operation *newOp = nullptr; | |||
976 | for (auto &op : elementalAddrOp.getBody().back().getOperations()) | |||
977 | newOp = b.clone(op, mapper); | |||
978 | auto newYielOp = mlir::dyn_cast_or_null<hlfir::YieldOp>(newOp); | |||
979 | assert(newYielOp && "hlfir.elemental_addr is ill formed")(static_cast <bool> (newYielOp && "hlfir.elemental_addr is ill formed" ) ? void (0) : __assert_fail ("newYielOp && \"hlfir.elemental_addr is ill formed\"" , "flang/lib/Optimizer/Builder/HLFIRTools.cpp", 979, __extension__ __PRETTY_FUNCTION__)); | |||
980 | hlfir::Entity newAddr{newYielOp.getEntity()}; | |||
981 | newYielOp->erase(); | |||
982 | return hlfir::loadTrivialScalar(l, b, newAddr); | |||
983 | }; | |||
984 | mlir::Type elementType = scalarAddress.getFortranElementType(); | |||
985 | return hlfir::genElementalOp(loc, builder, elementType, | |||
986 | elementalAddrOp.getShape(), typeParams, | |||
987 | genKernel); | |||
988 | } |