Bug Summary

File:build/source/flang/lib/Optimizer/Builder/HLFIRTools.cpp
Warning:line 762, column 16
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name HLFIRTools.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/flang/lib/Optimizer/Builder -I /build/source/flang/lib/Optimizer/Builder -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/flang/lib/Optimizer/Builder/HLFIRTools.cpp
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.
26llvm::SmallVector<mlir::Value>
27hlfir::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}
62static llvm::SmallVector<mlir::Value>
63getExplicitExtents(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.
72static llvm::SmallVector<mlir::Value>
73getExplicitLboundsFromShape(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}
89static llvm::SmallVector<mlir::Value>
90getExplicitLbounds(fir::FortranVariableOpInterface var) {
91 if (mlir::Value shape = var.getShape())
92 return getExplicitLboundsFromShape(shape);
93 return {};
94}
95
96static void
97genLboundsAndExtentsFromBox(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
114static llvm::SmallVector<mlir::Value>
115getNonDefaultLowerBounds(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
132static 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
138static llvm::SmallVector<mlir::Value> getExplicitTypeParams(hlfir::Entity var) {
139 if (auto varIface = var.getMaybeDereferencedVariableInterface())
140 return toSmallVector(varIface.getExplicitTypeParams());
141 return {};
142}
143
144static 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
151static 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
168static 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
185mlir::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
197fir::FortranVariableOpInterface
198hlfir::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
234hlfir::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
265mlir::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
280mlir::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
299hlfir::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
325hlfir::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
336hlfir::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
374static 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
386llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
387hlfir::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
407llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
408hlfir::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
429llvm::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
443static 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
458static 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}
476llvm::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
501static 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
512mlir::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
532llvm::SmallVector<mlir::Value>
533hlfir::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
543mlir::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
566mlir::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
587void 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
626mlir::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.
635static 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
650std::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
667hlfir::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
697mlir::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
713static 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
725hlfir::ElementalOp
726hlfir::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.
750hlfir::YieldElementOp
751hlfir::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__))
1
Assuming the condition is true
2
'?' condition is true
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;
3
'newOp' declared without an initial value
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);
4
1st function call argument is an uninitialized value
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
767std::pair<fir::DoLoopOp, llvm::SmallVector<mlir::Value>>
768hlfir::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
789static fir::ExtendedValue
790translateVariableToExtendedValue(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
841fir::ExtendedValue
842hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
843 fir::FortranVariableOpInterface var) {
844 return translateVariableToExtendedValue(loc, builder, var);
845}
846
847std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
848hlfir::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
876std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
877hlfir::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
901static 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
913std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
914hlfir::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
928std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
929hlfir::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/// ```
960hlfir::ElementalOp
961hlfir::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}