blob: b4d1197822a43d89c3aaa494874b46f82cc4ee43 [file] [log] [blame]
Valentin Clemente1a12762022-01-28 22:39:44 +01001//===-- Bridge.cpp -- bridge to lower to MLIR -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#include "flang/Lower/Bridge.h"
Kareem Ergawye5322412024-12-18 09:19:45 +010014
Valentin Clementc5cf1b92022-03-07 21:22:28 +010015#include "flang/Lower/Allocatable.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010016#include "flang/Lower/CallInterface.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010017#include "flang/Lower/Coarray.h"
Jean Periere78e4a12022-12-01 11:09:35 +010018#include "flang/Lower/ConvertCall.h"
Valentin Clementdc6a3442022-02-03 10:40:19 +010019#include "flang/Lower/ConvertExpr.h"
Jean Perierc14ef2d2022-10-24 15:35:19 +020020#include "flang/Lower/ConvertExprToHLFIR.h"
Valentin Clementdc6a3442022-02-03 10:40:19 +010021#include "flang/Lower/ConvertType.h"
Valentin Clement2c2e5a52022-02-07 09:12:17 +010022#include "flang/Lower/ConvertVariable.h"
Valentin Clement (バレンタイン クレメン)d4c519e2024-08-29 22:37:20 -070023#include "flang/Lower/Cuda.h"
Kareem Ergawye5322412024-12-18 09:19:45 +010024#include "flang/Lower/DirectivesCommon.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010025#include "flang/Lower/HostAssociations.h"
Valentin Clement8c22cb82022-03-01 21:47:40 +010026#include "flang/Lower/IO.h"
Valentin Clementf9704f02022-02-24 21:09:40 +010027#include "flang/Lower/IterationSpace.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010028#include "flang/Lower/Mangler.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010029#include "flang/Lower/OpenACC.h"
Shraiysh Vaishaye0f549a2022-03-10 22:40:23 +053030#include "flang/Lower/OpenMP.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010031#include "flang/Lower/PFTBuilder.h"
Valentin Clementaab42632022-02-01 20:53:00 +010032#include "flang/Lower/Runtime.h"
Valentin Clementd0b70a02022-02-23 19:48:07 +010033#include "flang/Lower/StatementContext.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010034#include "flang/Lower/Support/Utils.h"
Valentin Clement2a59ead2022-02-24 18:11:41 +010035#include "flang/Optimizer/Builder/BoxValue.h"
Valentin Clement (バレンタイン クレメン)91658482025-01-03 14:37:14 -080036#include "flang/Optimizer/Builder/CUFCommon.h"
Valentin Clement37e84d92022-02-25 18:21:44 +010037#include "flang/Optimizer/Builder/Character.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010038#include "flang/Optimizer/Builder/FIRBuilder.h"
Valentin Clementf8ea3492022-12-02 15:51:01 +010039#include "flang/Optimizer/Builder/Runtime/Assign.h"
Valentin Clement308fc3f2022-03-18 15:39:57 +010040#include "flang/Optimizer/Builder/Runtime/Character.h"
Valentin Clement90e9fcb2022-10-31 11:02:50 +010041#include "flang/Optimizer/Builder/Runtime/Derived.h"
Jonathon Penix0ec3ac92022-07-19 11:47:25 -070042#include "flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h"
vdonaldson6003be72024-12-04 16:21:11 -050043#include "flang/Optimizer/Builder/Runtime/Exceptions.h"
David Truby8d538662024-04-29 14:16:25 +010044#include "flang/Optimizer/Builder/Runtime/Main.h"
Valentin Clement88ae0d62022-03-10 19:43:11 +010045#include "flang/Optimizer/Builder/Runtime/Ragged.h"
V Donaldsonfd922e62023-04-05 11:13:36 -070046#include "flang/Optimizer/Builder/Runtime/Stop.h"
Valentin Clement5b66cc12022-06-10 08:50:40 +020047#include "flang/Optimizer/Builder/Todo.h"
Valentin Clement (バレンタイン クレメン)45daa4f2024-05-17 09:37:53 -070048#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
49#include "flang/Optimizer/Dialect/CUF/CUFOps.h"
Valentin Clement78a127a2022-03-08 20:17:48 +010050#include "flang/Optimizer/Dialect/FIRAttr.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010051#include "flang/Optimizer/Dialect/FIRDialect.h"
52#include "flang/Optimizer/Dialect/FIROps.h"
Renaud-Kb07ef9e2023-03-08 18:39:40 -080053#include "flang/Optimizer/Dialect/Support/FIRContext.h"
Jean Perierdd73bfa2022-11-15 12:01:21 +010054#include "flang/Optimizer/HLFIR/HLFIROps.h"
jeanPeriere59e8482023-12-06 14:20:06 +010055#include "flang/Optimizer/Support/DataLayout.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010056#include "flang/Optimizer/Support/FatalError.h"
Valentin Clement17d71342022-03-02 18:26:13 +010057#include "flang/Optimizer/Support/InternalNames.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010058#include "flang/Optimizer/Transforms/Passes.h"
59#include "flang/Parser/parse-tree.h"
Michael Krusec91ba042024-12-06 15:29:00 +010060#include "flang/Runtime/iostat-consts.h"
Valentin Clement6393d2e2022-11-17 10:53:13 +010061#include "flang/Semantics/runtime-type-info.h"
Sergio Afonso29aa7492023-03-29 18:13:48 +010062#include "flang/Semantics/symbol.h"
Valentin Clemente641c292022-02-17 18:23:22 +010063#include "flang/Semantics/tools.h"
Michael Kruseb815a392025-02-06 15:29:10 +010064#include "flang/Support/Version.h"
Kiran Chandramohanae37bb92022-02-08 23:01:39 +000065#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
Asher Mancinelli6b52fb22025-02-10 08:21:22 -080066#include "mlir/IR/BuiltinAttributes.h"
Valentin Clement (バレンタイン クレメン)0bc710f2024-05-21 12:42:30 -070067#include "mlir/IR/Matchers.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010068#include "mlir/IR/PatternMatch.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010069#include "mlir/Parser/Parser.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010070#include "mlir/Transforms/RegionUtils.h"
Valentin Clementdda01632023-02-07 09:15:54 +010071#include "llvm/ADT/SmallVector.h"
Valentin Clement6393d2e2022-11-17 10:53:13 +010072#include "llvm/ADT/StringSet.h"
Valentin Clemente1a12762022-01-28 22:39:44 +010073#include "llvm/Support/CommandLine.h"
74#include "llvm/Support/Debug.h"
Valentin Clementfe252f82022-03-22 15:40:32 +010075#include "llvm/Support/ErrorHandling.h"
Kiran Chandramohaneef02102023-01-19 16:49:26 +000076#include "llvm/Support/FileSystem.h"
77#include "llvm/Support/Path.h"
Sergio Afonso837bff12024-01-30 13:45:56 +000078#include "llvm/Target/TargetMachine.h"
Kazu Hirata4d4d4782023-01-07 20:55:47 -080079#include <optional>
Valentin Clemente1a12762022-01-28 22:39:44 +010080
81#define DEBUG_TYPE "flang-lower-bridge"
82
83static llvm::cl::opt<bool> dumpBeforeFir(
84 "fdebug-dump-pre-fir", llvm::cl::init(false),
85 llvm::cl::desc("dump the Pre-FIR tree prior to FIR generation"));
86
Valentin Clementfe252f82022-03-22 15:40:32 +010087static llvm::cl::opt<bool> forceLoopToExecuteOnce(
88 "always-execute-loop-body", llvm::cl::init(false),
89 llvm::cl::desc("force the body of a loop to execute at least once"));
90
Valentin Clement9aeb7f02022-03-16 17:10:31 +010091namespace {
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +000092/// Information for generating a structured or unstructured increment loop.
93struct IncrementLoopInfo {
94 template <typename T>
95 explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower,
96 const T &upper, const std::optional<T> &step,
Kareem Ergawy30990c02025-04-16 14:20:27 +020097 bool isUnordered = false)
Krzysztof Parzyszekdd376f82023-12-04 08:27:57 -060098 : loopVariableSym{&sym}, lowerExpr{Fortran::semantics::GetExpr(lower)},
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +000099 upperExpr{Fortran::semantics::GetExpr(upper)},
Kareem Ergawy30990c02025-04-16 14:20:27 +0200100 stepExpr{Fortran::semantics::GetExpr(step)}, isUnordered{isUnordered} {}
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000101
102 IncrementLoopInfo(IncrementLoopInfo &&) = default;
Krzysztof Parzyszekdd376f82023-12-04 08:27:57 -0600103 IncrementLoopInfo &operator=(IncrementLoopInfo &&x) = default;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000104
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +0000105 bool isStructured() const { return !headerBlock; }
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000106
107 mlir::Type getLoopVariableType() const {
108 assert(loopVariable && "must be set");
109 return fir::unwrapRefType(loopVariable.getType());
110 }
111
V Donaldson335b3992023-08-07 13:29:17 -0700112 bool hasLocalitySpecs() const {
113 return !localSymList.empty() || !localInitSymList.empty() ||
khaki3f11e08f2024-06-10 08:41:05 -0700114 !reduceSymList.empty() || !sharedSymList.empty();
V Donaldson335b3992023-08-07 13:29:17 -0700115 }
116
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000117 // Data members common to both structured and unstructured loops.
Krzysztof Parzyszekdd376f82023-12-04 08:27:57 -0600118 const Fortran::semantics::Symbol *loopVariableSym;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000119 const Fortran::lower::SomeExpr *lowerExpr;
120 const Fortran::lower::SomeExpr *upperExpr;
121 const Fortran::lower::SomeExpr *stepExpr;
Mats Petersson84b9ae62022-06-07 14:00:08 +0100122 const Fortran::lower::SomeExpr *maskExpr = nullptr;
Kareem Ergawy30990c02025-04-16 14:20:27 +0200123 bool isUnordered; // do concurrent, forall
V Donaldson335b3992023-08-07 13:29:17 -0700124 llvm::SmallVector<const Fortran::semantics::Symbol *> localSymList;
Mats Petersson84b9ae62022-06-07 14:00:08 +0100125 llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
khaki3f11e08f2024-06-10 08:41:05 -0700126 llvm::SmallVector<
127 std::pair<fir::ReduceOperationEnum, const Fortran::semantics::Symbol *>>
128 reduceSymList;
Mats Petersson84b9ae62022-06-07 14:00:08 +0100129 llvm::SmallVector<const Fortran::semantics::Symbol *> sharedSymList;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000130 mlir::Value loopVariable = nullptr;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000131
132 // Data members for structured loops.
Kareem Ergawy30990c02025-04-16 14:20:27 +0200133 fir::DoLoopOp doLoop = nullptr;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000134
135 // Data members for unstructured loops.
Diana Picusa1591282022-05-31 10:55:56 +0000136 bool hasRealControl = false;
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +0000137 mlir::Value tripVariable = nullptr;
Leandro Lupori3dbb0552023-09-21 15:59:35 +0200138 mlir::Value stepVariable = nullptr;
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +0000139 mlir::Block *headerBlock = nullptr; // loop entry and test block
Mats Petersson84b9ae62022-06-07 14:00:08 +0100140 mlir::Block *maskBlock = nullptr; // concurrent loop mask block
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +0000141 mlir::Block *bodyBlock = nullptr; // first loop body block
142 mlir::Block *exitBlock = nullptr; // loop exit target block
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +0000143};
144
V Donaldson2c143342023-02-27 14:05:53 -0800145/// Information to support stack management, object deallocation, and
146/// object finalization at early and normal construct exits.
147struct ConstructContext {
148 explicit ConstructContext(Fortran::lower::pft::Evaluation &eval,
149 Fortran::lower::StatementContext &stmtCtx)
150 : eval{eval}, stmtCtx{stmtCtx} {}
151
152 Fortran::lower::pft::Evaluation &eval; // construct eval
153 Fortran::lower::StatementContext &stmtCtx; // construct exit code
jeanPerierd1aa9ba2024-06-03 17:20:07 +0200154 std::optional<hlfir::Entity> selector; // construct selector, if any.
155 bool pushedScope = false; // was a scoped pushed for this construct?
V Donaldson2c143342023-02-27 14:05:53 -0800156};
157
jeanPerier66d5ca22024-07-02 15:19:49 +0200158/// Helper to gather the lower bounds of array components with non deferred
159/// shape when they are not all ones. Return an empty array attribute otherwise.
160static mlir::DenseI64ArrayAttr
161gatherComponentNonDefaultLowerBounds(mlir::Location loc,
162 mlir::MLIRContext *mlirContext,
163 const Fortran::semantics::Symbol &sym) {
164 if (Fortran::semantics::IsAllocatableOrObjectPointer(&sym))
165 return {};
166 mlir::DenseI64ArrayAttr lbs_attr;
167 if (const auto *objDetails =
168 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
169 llvm::SmallVector<std::int64_t> lbs;
170 bool hasNonDefaultLbs = false;
171 for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape())
172 if (auto lb = bounds.lbound().GetExplicit()) {
173 if (auto constant = Fortran::evaluate::ToInt64(*lb)) {
174 hasNonDefaultLbs |= (*constant != 1);
175 lbs.push_back(*constant);
176 } else {
177 TODO(loc, "generate fir.dt_component for length parametrized derived "
178 "types");
179 }
180 }
181 if (hasNonDefaultLbs) {
182 assert(static_cast<int>(lbs.size()) == sym.Rank() &&
183 "expected component bounds to be constant or deferred");
184 lbs_attr = mlir::DenseI64ArrayAttr::get(mlirContext, lbs);
185 }
186 }
187 return lbs_attr;
188}
189
190// Helper class to generate name of fir.global containing component explicit
191// default value for objects, and initial procedure target for procedure pointer
192// components.
193static mlir::FlatSymbolRefAttr gatherComponentInit(
194 mlir::Location loc, Fortran::lower::AbstractConverter &converter,
195 const Fortran::semantics::Symbol &sym, fir::RecordType derivedType) {
196 mlir::MLIRContext *mlirContext = &converter.getMLIRContext();
197 // Return procedure target mangled name for procedure pointer components.
198 if (const auto *procPtr =
199 sym.detailsIf<Fortran::semantics::ProcEntityDetails>()) {
200 if (std::optional<const Fortran::semantics::Symbol *> maybeInitSym =
201 procPtr->init()) {
202 // So far, do not make distinction between p => NULL() and p without init,
203 // f18 always initialize pointers to NULL anyway.
204 if (!*maybeInitSym)
205 return {};
206 return mlir::FlatSymbolRefAttr::get(mlirContext,
207 converter.mangleName(**maybeInitSym));
208 }
209 }
210
211 const auto *objDetails =
212 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
213 if (!objDetails || !objDetails->init().has_value())
214 return {};
215 // Object component initial value. Semantic package component object default
216 // value into compiler generated symbols that are lowered as read-only
217 // fir.global. Get the name of this global.
218 std::string name = fir::NameUniquer::getComponentInitName(
219 derivedType.getName(), toStringRef(sym.name()));
220 return mlir::FlatSymbolRefAttr::get(mlirContext, name);
221}
222
jeanPerier4ccd57d2023-10-06 09:29:57 +0200223/// Helper class to generate the runtime type info global data and the
224/// fir.type_info operations that contain the dipatch tables (if any).
225/// The type info global data is required to describe the derived type to the
226/// runtime so that it can operate over it.
227/// It must be ensured these operations will be generated for every derived type
228/// lowered in the current translated unit. However, these operations
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100229/// cannot be generated before FuncOp have been created for functions since the
230/// initializers may take their address (e.g for type bound procedures). This
jeanPerier4ccd57d2023-10-06 09:29:57 +0200231/// class allows registering all the required type info while it is not
232/// possible to create GlobalOp/TypeInfoOp, and to generate this data afte
233/// function lowering.
234class TypeInfoConverter {
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100235 /// Store the location and symbols of derived type info to be generated.
236 /// The location of the derived type instantiation is also stored because
jeanPerier4ccd57d2023-10-06 09:29:57 +0200237 /// runtime type descriptor symbols are compiler generated and cannot be
238 /// mapped to user code on their own.
239 struct TypeInfo {
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100240 Fortran::semantics::SymbolRef symbol;
jeanPerier4ccd57d2023-10-06 09:29:57 +0200241 const Fortran::semantics::DerivedTypeSpec &typeSpec;
242 fir::RecordType type;
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100243 mlir::Location loc;
244 };
245
246public:
jeanPerier4ccd57d2023-10-06 09:29:57 +0200247 void registerTypeInfo(Fortran::lower::AbstractConverter &converter,
248 mlir::Location loc,
249 Fortran::semantics::SymbolRef typeInfoSym,
250 const Fortran::semantics::DerivedTypeSpec &typeSpec,
251 fir::RecordType type) {
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100252 if (seen.contains(typeInfoSym))
253 return;
254 seen.insert(typeInfoSym);
jeanPerierc373f582023-12-19 17:17:09 +0100255 currentTypeInfoStack->emplace_back(
256 TypeInfo{typeInfoSym, typeSpec, type, loc});
257 return;
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100258 }
259
jeanPerier4ccd57d2023-10-06 09:29:57 +0200260 void createTypeInfo(Fortran::lower::AbstractConverter &converter) {
jeanPerierc373f582023-12-19 17:17:09 +0100261 while (!registeredTypeInfoA.empty()) {
262 currentTypeInfoStack = &registeredTypeInfoB;
263 for (const TypeInfo &info : registeredTypeInfoA)
264 createTypeInfoOpAndGlobal(converter, info);
265 registeredTypeInfoA.clear();
266 currentTypeInfoStack = &registeredTypeInfoA;
267 for (const TypeInfo &info : registeredTypeInfoB)
268 createTypeInfoOpAndGlobal(converter, info);
269 registeredTypeInfoB.clear();
270 }
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100271 }
272
273private:
jeanPerier4ccd57d2023-10-06 09:29:57 +0200274 void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter,
275 const TypeInfo &info) {
vdonaldson3aba9262023-12-04 09:55:54 -0800276 Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
jeanPerier4ccd57d2023-10-06 09:29:57 +0200277 createTypeInfoOp(converter, info);
Valentin Clement6393d2e2022-11-17 10:53:13 +0100278 }
279
jeanPerier4ccd57d2023-10-06 09:29:57 +0200280 void createTypeInfoOp(Fortran::lower::AbstractConverter &converter,
281 const TypeInfo &info) {
282 fir::RecordType parentType{};
283 if (const Fortran::semantics::DerivedTypeSpec *parent =
284 Fortran::evaluate::GetParentTypeSpec(info.typeSpec))
285 parentType = mlir::cast<fir::RecordType>(converter.genType(*parent));
Valentin Clement6393d2e2022-11-17 10:53:13 +0100286
jeanPerier4ccd57d2023-10-06 09:29:57 +0200287 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
jeanPerier66d5ca22024-07-02 15:19:49 +0200288 fir::TypeInfoOp dt;
289 mlir::OpBuilder::InsertPoint insertPointIfCreated;
290 std::tie(dt, insertPointIfCreated) =
291 builder.createTypeInfoOp(info.loc, info.type, parentType);
292 if (!insertPointIfCreated.isSet())
293 return; // fir.type_info was already built in a previous call.
Valentin Clement6393d2e2022-11-17 10:53:13 +0100294
jeanPerier66d5ca22024-07-02 15:19:49 +0200295 // Set init, destroy, and nofinal attributes.
jeanPerier4ccd57d2023-10-06 09:29:57 +0200296 if (!info.typeSpec.HasDefaultInitialization(/*ignoreAllocatable=*/false,
297 /*ignorePointer=*/false))
298 dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr());
299 if (!info.typeSpec.HasDestruction())
300 dt->setAttr(dt.getNoDestroyAttrName(), builder.getUnitAttr());
301 if (!Fortran::semantics::MayRequireFinalization(info.typeSpec))
302 dt->setAttr(dt.getNoFinalAttrName(), builder.getUnitAttr());
303
jeanPerier66d5ca22024-07-02 15:19:49 +0200304 const Fortran::semantics::Scope &derivedScope =
305 DEREF(info.typeSpec.GetScope());
jeanPerier4ccd57d2023-10-06 09:29:57 +0200306
jeanPerier66d5ca22024-07-02 15:19:49 +0200307 // Fill binding table region if the derived type has bindings.
jeanPerier4ccd57d2023-10-06 09:29:57 +0200308 Fortran::semantics::SymbolVector bindings =
jeanPerier66d5ca22024-07-02 15:19:49 +0200309 Fortran::semantics::CollectBindings(derivedScope);
jeanPerier4ccd57d2023-10-06 09:29:57 +0200310 if (!bindings.empty()) {
311 builder.createBlock(&dt.getDispatchTable());
Valentin Clementd38735e2022-11-22 15:13:18 +0100312 for (const Fortran::semantics::SymbolRef &binding : bindings) {
Peter Klausler7f7bbc72023-05-16 12:33:29 -0700313 const auto &details =
314 binding.get().get<Fortran::semantics::ProcBindingDetails>();
315 std::string tbpName = binding.get().name().ToString();
316 if (details.numPrivatesNotOverridden() > 0)
317 tbpName += "."s + std::to_string(details.numPrivatesNotOverridden());
318 std::string bindingName = converter.mangleName(details.symbol());
Valentin Clement6393d2e2022-11-17 10:53:13 +0100319 builder.create<fir::DTEntryOp>(
Peter Klausler7f7bbc72023-05-16 12:33:29 -0700320 info.loc, mlir::StringAttr::get(builder.getContext(), tbpName),
Valentin Clement6393d2e2022-11-17 10:53:13 +0100321 mlir::SymbolRefAttr::get(builder.getContext(), bindingName));
322 }
jeanPerier4ccd57d2023-10-06 09:29:57 +0200323 builder.create<fir::FirEndOp>(info.loc);
Valentin Clement6393d2e2022-11-17 10:53:13 +0100324 }
jeanPerier66d5ca22024-07-02 15:19:49 +0200325 // Gather info about components that is not reflected in fir.type and may be
326 // needed later: component initial values and array component non default
327 // lower bounds.
328 mlir::Block *componentInfo = nullptr;
329 for (const auto &componentName :
330 info.typeSpec.typeSymbol()
331 .get<Fortran::semantics::DerivedTypeDetails>()
332 .componentNames()) {
333 auto scopeIter = derivedScope.find(componentName);
334 assert(scopeIter != derivedScope.cend() &&
335 "failed to find derived type component symbol");
336 const Fortran::semantics::Symbol &component = scopeIter->second.get();
337 mlir::FlatSymbolRefAttr init_val =
338 gatherComponentInit(info.loc, converter, component, info.type);
339 mlir::DenseI64ArrayAttr lbs = gatherComponentNonDefaultLowerBounds(
340 info.loc, builder.getContext(), component);
341 if (init_val || lbs) {
342 if (!componentInfo)
343 componentInfo = builder.createBlock(&dt.getComponentInfo());
344 auto compName = mlir::StringAttr::get(builder.getContext(),
345 toStringRef(component.name()));
346 builder.create<fir::DTComponentOp>(info.loc, compName, lbs, init_val);
347 }
348 }
349 if (componentInfo)
350 builder.create<fir::FirEndOp>(info.loc);
351 builder.restoreInsertionPoint(insertPointIfCreated);
Valentin Clement6393d2e2022-11-17 10:53:13 +0100352 }
353
jeanPerier4ccd57d2023-10-06 09:29:57 +0200354 /// Store the front-end data that will be required to generate the type info
jeanPerierc373f582023-12-19 17:17:09 +0100355 /// for the derived types that have been converted to fir.type<>. There are
356 /// two stacks since the type info may visit new types, so the new types must
357 /// be added to a new stack.
358 llvm::SmallVector<TypeInfo> registeredTypeInfoA;
359 llvm::SmallVector<TypeInfo> registeredTypeInfoB;
360 llvm::SmallVector<TypeInfo> *currentTypeInfoStack = &registeredTypeInfoA;
jeanPerier4ccd57d2023-10-06 09:29:57 +0200361 /// Track symbols symbols processed during and after the registration
362 /// to avoid infinite loops between type conversions and global variable
363 /// creation.
364 llvm::SmallSetVector<Fortran::semantics::SymbolRef, 32> seen;
Valentin Clement6393d2e2022-11-17 10:53:13 +0100365};
366
Slava Zakharinaf7edf12022-08-18 14:06:19 -0700367using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo, 8>;
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100368} // namespace
369
Valentin Clemente1a12762022-01-28 22:39:44 +0100370//===----------------------------------------------------------------------===//
371// FirConverter
372//===----------------------------------------------------------------------===//
373
374namespace {
375
376/// Traverse the pre-FIR tree (PFT) to generate the FIR dialect of MLIR.
377class FirConverter : public Fortran::lower::AbstractConverter {
378public:
379 explicit FirConverter(Fortran::lower::LoweringBridge &bridge)
Slava Zakharinf1eb9452022-07-19 20:39:58 -0700380 : Fortran::lower::AbstractConverter(bridge.getLoweringOptions()),
jeanPeriera4798bb2024-04-02 14:29:29 +0200381 bridge{bridge}, foldingContext{bridge.createFoldingContext()},
382 mlirSymbolTable{bridge.getModule()} {}
Valentin Clemente1a12762022-01-28 22:39:44 +0100383 virtual ~FirConverter() = default;
384
385 /// Convert the PFT to FIR.
386 void run(Fortran::lower::pft::Program &pft) {
Valentin Clementa1425012022-03-15 21:57:30 +0100387 // Preliminary translation pass.
Jean Perier2c8cb9a2022-04-29 14:52:27 +0200388
vdonaldson3aba9262023-12-04 09:55:54 -0800389 // Lower common blocks, taking into account initialization and the largest
390 // size of all instances of each common block. This is done before lowering
391 // since the global definition may differ from any one local definition.
Jean Perier2c8cb9a2022-04-29 14:52:27 +0200392 lowerCommonBlocks(pft.getCommonBlocks());
393
vdonaldson3aba9262023-12-04 09:55:54 -0800394 // - Declare all functions that have definitions so that definition
395 // signatures prevail over call site signatures.
396 // - Define module variables and OpenMP/OpenACC declarative constructs so
397 // they are available before lowering any function that may use them.
Jonathon Penix0ec3ac92022-07-19 11:47:25 -0700398 bool hasMainProgram = false;
Sergio Afonso29aa7492023-03-29 18:13:48 +0100399 const Fortran::semantics::Symbol *globalOmpRequiresSymbol = nullptr;
Valentin Clement17d71342022-03-02 18:26:13 +0100400 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -0700401 Fortran::common::visit(
vdonaldson87374a82024-06-12 09:35:14 -0400402 Fortran::common::visitors{
403 [&](Fortran::lower::pft::FunctionLikeUnit &f) {
404 if (f.isMainProgram())
405 hasMainProgram = true;
406 declareFunction(f);
407 if (!globalOmpRequiresSymbol)
408 globalOmpRequiresSymbol = f.getScope().symbol();
409 },
410 [&](Fortran::lower::pft::ModuleLikeUnit &m) {
411 lowerModuleDeclScope(m);
412 for (Fortran::lower::pft::ContainedUnit &unit :
413 m.containedUnitList)
414 if (auto *f =
415 std::get_if<Fortran::lower::pft::FunctionLikeUnit>(
416 &unit))
417 declareFunction(*f);
418 },
419 [&](Fortran::lower::pft::BlockDataUnit &b) {
420 if (!globalOmpRequiresSymbol)
421 globalOmpRequiresSymbol = b.symTab.symbol();
422 },
423 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
424 [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
425 },
426 u);
Valentin Clement17d71342022-03-02 18:26:13 +0100427 }
428
vdonaldson3aba9262023-12-04 09:55:54 -0800429 // Create definitions of intrinsic module constants.
430 createGlobalOutsideOfFunctionLowering(
431 [&]() { createIntrinsicModuleDefinitions(pft); });
432
Valentin Clement17d71342022-03-02 18:26:13 +0100433 // Primary translation pass.
Valentin Clemente1a12762022-01-28 22:39:44 +0100434 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -0700435 Fortran::common::visit(
Valentin Clemente1a12762022-01-28 22:39:44 +0100436 Fortran::common::visitors{
437 [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); },
Valentin Clement17d71342022-03-02 18:26:13 +0100438 [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); },
Valentin Clemente1a12762022-01-28 22:39:44 +0100439 [&](Fortran::lower::pft::BlockDataUnit &b) {},
V Donaldsonaf781972023-04-12 15:37:19 -0700440 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
Valentin Clement (バレンタイン クレメン)82867432023-10-24 09:17:48 -0700441 [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {
jeanPeriera4798bb2024-04-02 14:29:29 +0200442 builder = new fir::FirOpBuilder(
443 bridge.getModule(), bridge.getKindMap(), &mlirSymbolTable);
Valentin Clement (バレンタイン クレメン)82867432023-10-24 09:17:48 -0700444 Fortran::lower::genOpenACCRoutineConstruct(
445 *this, bridge.getSemanticsContext(), bridge.getModule(),
446 d.routine, accRoutineInfos);
447 builder = nullptr;
448 },
Valentin Clemente1a12762022-01-28 22:39:44 +0100449 },
450 u);
451 }
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100452
vdonaldson3aba9262023-12-04 09:55:54 -0800453 // Once all the code has been translated, create global runtime type info
454 // data structures for the derived types that have been processed, as well
455 // as fir.type_info operations for the dispatch tables.
Valentin Clement9aeb7f02022-03-16 17:10:31 +0100456 createGlobalOutsideOfFunctionLowering(
jeanPerier4ccd57d2023-10-06 09:29:57 +0200457 [&]() { typeInfoConverter.createTypeInfo(*this); });
Valentin Clement6393d2e2022-11-17 10:53:13 +0100458
David Trubyecec1312024-04-30 22:38:36 +0100459 // Generate the `main` entry point if necessary
Jonathon Penix0ec3ac92022-07-19 11:47:25 -0700460 if (hasMainProgram)
461 createGlobalOutsideOfFunctionLowering([&]() {
David Trubyecec1312024-04-30 22:38:36 +0100462 fir::runtime::genMain(*builder, toLocation(),
Valentin Clement (バレンタイン クレメン)654b7632025-01-28 20:57:33 -0800463 bridge.getEnvironmentDefaults(),
464 getFoldingContext().languageFeatures().IsEnabled(
465 Fortran::common::LanguageFeature::CUDA));
Jonathon Penix0ec3ac92022-07-19 11:47:25 -0700466 });
Valentin Clement69a6bd52023-08-17 14:25:05 -0700467
468 finalizeOpenACCLowering();
Sergio Afonso29aa7492023-03-29 18:13:48 +0100469 finalizeOpenMPLowering(globalOmpRequiresSymbol);
Valentin Clemente1a12762022-01-28 22:39:44 +0100470 }
471
Valentin Clement17d71342022-03-02 18:26:13 +0100472 /// Declare a function.
473 void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
474 setCurrentPosition(funit.getStartingSourceLoc());
475 for (int entryIndex = 0, last = funit.entryPointList.size();
476 entryIndex < last; ++entryIndex) {
477 funit.setActiveEntry(entryIndex);
River Riddle58ceae92022-04-18 11:53:47 -0700478 // Calling CalleeInterface ctor will build a declaration
479 // mlir::func::FuncOp with no other side effects.
Valentin Clement17d71342022-03-02 18:26:13 +0100480 // TODO: when doing some compiler profiling on real apps, it may be worth
481 // to check it's better to save the CalleeInterface instead of recomputing
482 // it later when lowering the body. CalleeInterface ctor should be linear
483 // with the number of arguments, so it is not awful to do it that way for
484 // now, but the linear coefficient might be non negligible. Until
485 // measured, stick to the solution that impacts the code less.
486 Fortran::lower::CalleeInterface{funit, *this};
487 }
488 funit.setActiveEntry(0);
489
Valentin Clement764f95a2022-03-07 19:55:48 +0100490 // Compute the set of host associated entities from the nested functions.
491 llvm::SetVector<const Fortran::semantics::Symbol *> escapeHost;
vdonaldson87374a82024-06-12 09:35:14 -0400492 for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
493 if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
494 collectHostAssociatedVariables(*f, escapeHost);
Valentin Clement764f95a2022-03-07 19:55:48 +0100495 funit.setHostAssociatedSymbols(escapeHost);
496
Valentin Clement17d71342022-03-02 18:26:13 +0100497 // Declare internal procedures
vdonaldson87374a82024-06-12 09:35:14 -0400498 for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
499 if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
500 declareFunction(*f);
Valentin Clement17d71342022-03-02 18:26:13 +0100501 }
502
jeanPerierd26c78b2023-09-06 09:07:45 +0200503 /// Get the scope that is defining or using \p sym. The returned scope is not
504 /// the ultimate scope, since this helper does not traverse use association.
505 /// This allows capturing module variables that are referenced in an internal
506 /// procedure but whose use statement is inside the host program.
507 const Fortran::semantics::Scope &
508 getSymbolHostScope(const Fortran::semantics::Symbol &sym) {
509 const Fortran::semantics::Symbol *hostSymbol = &sym;
510 while (const auto *details =
511 hostSymbol->detailsIf<Fortran::semantics::HostAssocDetails>())
512 hostSymbol = &details->symbol();
513 return hostSymbol->owner();
514 }
515
Valentin Clement764f95a2022-03-07 19:55:48 +0100516 /// Collects the canonical list of all host associated symbols. These bindings
517 /// must be aggregated into a tuple which can then be added to each of the
518 /// internal procedure declarations and passed at each call site.
519 void collectHostAssociatedVariables(
520 Fortran::lower::pft::FunctionLikeUnit &funit,
521 llvm::SetVector<const Fortran::semantics::Symbol *> &escapees) {
522 const Fortran::semantics::Scope *internalScope =
523 funit.getSubprogramSymbol().scope();
524 assert(internalScope && "internal procedures symbol must create a scope");
525 auto addToListIfEscapee = [&](const Fortran::semantics::Symbol &sym) {
526 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
527 const auto *namelistDetails =
528 ultimate.detailsIf<Fortran::semantics::NamelistDetails>();
529 if (ultimate.has<Fortran::semantics::ObjectEntityDetails>() ||
530 Fortran::semantics::IsProcedurePointer(ultimate) ||
531 Fortran::semantics::IsDummy(sym) || namelistDetails) {
jeanPerierd26c78b2023-09-06 09:07:45 +0200532 const Fortran::semantics::Scope &symbolScope = getSymbolHostScope(sym);
533 if (symbolScope.kind() ==
Valentin Clement764f95a2022-03-07 19:55:48 +0100534 Fortran::semantics::Scope::Kind::MainProgram ||
jeanPerierd26c78b2023-09-06 09:07:45 +0200535 symbolScope.kind() == Fortran::semantics::Scope::Kind::Subprogram)
536 if (symbolScope != *internalScope &&
537 symbolScope.Contains(*internalScope)) {
Valentin Clement764f95a2022-03-07 19:55:48 +0100538 if (namelistDetails) {
539 // So far, namelist symbols are processed on the fly in IO and
540 // the related namelist data structure is not added to the symbol
541 // map, so it cannot be passed to the internal procedures.
542 // Instead, all the symbols of the host namelist used in the
543 // internal procedure must be considered as host associated so
544 // that IO lowering can find them when needed.
545 for (const auto &namelistObject : namelistDetails->objects())
546 escapees.insert(&*namelistObject);
547 } else {
548 escapees.insert(&ultimate);
549 }
550 }
551 }
552 };
553 Fortran::lower::pft::visitAllSymbols(funit, addToListIfEscapee);
554 }
555
Valentin Clemente1a12762022-01-28 22:39:44 +0100556 //===--------------------------------------------------------------------===//
557 // AbstractConverter overrides
558 //===--------------------------------------------------------------------===//
559
560 mlir::Value getSymbolAddress(Fortran::lower::SymbolRef sym) override final {
561 return lookupSymbol(sym).getAddr();
562 }
563
Leandro Lupori1fcb6a92024-12-19 17:26:50 -0300564 fir::ExtendedValue symBoxToExtendedValue(
565 const Fortran::lower::SymbolBox &symBox) override final {
Jean Perierab9c4e92023-02-07 09:22:47 +0100566 return symBox.match(
567 [](const Fortran::lower::SymbolBox::Intrinsic &box)
568 -> fir::ExtendedValue { return box.getAddr(); },
569 [](const Fortran::lower::SymbolBox::None &) -> fir::ExtendedValue {
570 llvm::report_fatal_error("symbol not mapped");
571 },
572 [&](const fir::FortranVariableOpInterface &x) -> fir::ExtendedValue {
573 return hlfir::translateToExtendedValue(getCurrentLocation(),
574 getFirOpBuilder(), x);
575 },
576 [](const auto &box) -> fir::ExtendedValue { return box; });
577 }
578
579 fir::ExtendedValue
580 getSymbolExtendedValue(const Fortran::semantics::Symbol &sym,
581 Fortran::lower::SymMap *symMap) override final {
582 Fortran::lower::SymbolBox sb = lookupSymbol(sym, symMap);
583 if (!sb) {
584 LLVM_DEBUG(llvm::dbgs() << "unknown symbol: " << sym << "\nmap: "
585 << (symMap ? *symMap : localSymbols) << '\n');
586 fir::emitFatalError(getCurrentLocation(),
587 "symbol is not mapped to any IR value");
588 }
589 return symBoxToExtendedValue(sb);
Peixin-Qiao411bd2d2022-06-07 15:08:17 +0800590 }
591
Valentin Clementb3eb0e12022-03-08 18:47:28 +0100592 mlir::Value impliedDoBinding(llvm::StringRef name) override final {
593 mlir::Value val = localSymbols.lookupImpliedDo(name);
594 if (!val)
595 fir::emitFatalError(toLocation(), "ac-do-variable has no binding");
596 return val;
597 }
598
Valentin Clementa1425012022-03-15 21:57:30 +0100599 void copySymbolBinding(Fortran::lower::SymbolRef src,
600 Fortran::lower::SymbolRef target) override final {
Jean Perierab9c4e92023-02-07 09:22:47 +0100601 localSymbols.copySymbolBinding(src, target);
Valentin Clementa1425012022-03-15 21:57:30 +0100602 }
603
604 /// Add the symbol binding to the inner-most level of the symbol map and
605 /// return true if it is not already present. Otherwise, return false.
606 bool bindIfNewSymbol(Fortran::lower::SymbolRef sym,
607 const fir::ExtendedValue &exval) {
608 if (shallowLookupSymbol(sym))
609 return false;
610 bindSymbol(sym, exval);
611 return true;
612 }
613
614 void bindSymbol(Fortran::lower::SymbolRef sym,
615 const fir::ExtendedValue &exval) override final {
Jean Perierab9c4e92023-02-07 09:22:47 +0100616 addSymbol(sym, exval, /*forced=*/true);
Valentin Clementa1425012022-03-15 21:57:30 +0100617 }
618
jeanPerierb6b07562023-10-25 09:22:23 +0200619 void
620 overrideExprValues(const Fortran::lower::ExprToValueMap *map) override final {
621 exprValueOverrides = map;
622 }
623
624 const Fortran::lower::ExprToValueMap *getExprOverrides() override final {
625 return exprValueOverrides;
626 }
627
Valentin Clement8c22cb82022-03-01 21:47:40 +0100628 bool lookupLabelSet(Fortran::lower::SymbolRef sym,
629 Fortran::lower::pft::LabelSet &labelSet) override final {
630 Fortran::lower::pft::FunctionLikeUnit &owningProc =
631 *getEval().getOwningProcedure();
632 auto iter = owningProc.assignSymbolLabelMap.find(sym);
633 if (iter == owningProc.assignSymbolLabelMap.end())
634 return false;
635 labelSet = iter->second;
636 return true;
637 }
638
639 Fortran::lower::pft::Evaluation *
640 lookupLabel(Fortran::lower::pft::Label label) override final {
641 Fortran::lower::pft::FunctionLikeUnit &owningProc =
642 *getEval().getOwningProcedure();
Kazu Hirataa678ed42023-08-27 08:26:48 -0700643 return owningProc.labelEvaluationMap.lookup(label);
Valentin Clement8c22cb82022-03-01 21:47:40 +0100644 }
645
Jean Perier45463972022-10-17 09:57:16 +0200646 fir::ExtendedValue
647 genExprAddr(const Fortran::lower::SomeExpr &expr,
648 Fortran::lower::StatementContext &context,
649 mlir::Location *locPtr = nullptr) override final {
650 mlir::Location loc = locPtr ? *locPtr : toLocation();
Jean Perier7531c872023-01-20 14:05:42 +0100651 if (lowerToHighLevelFIR())
Jean Perier4e78f882023-01-10 09:28:08 +0100652 return Fortran::lower::convertExprToAddress(loc, *this, expr,
653 localSymbols, context);
Jean Perier45463972022-10-17 09:57:16 +0200654 return Fortran::lower::createSomeExtendedAddress(loc, *this, expr,
655 localSymbols, context);
Valentin Clemente1a12762022-01-28 22:39:44 +0100656 }
Jean Perierc14ef2d2022-10-24 15:35:19 +0200657
Valentin Clement41526742022-02-02 18:44:09 +0100658 fir::ExtendedValue
659 genExprValue(const Fortran::lower::SomeExpr &expr,
Valentin Clementd0b70a02022-02-23 19:48:07 +0100660 Fortran::lower::StatementContext &context,
Jean Perier45463972022-10-17 09:57:16 +0200661 mlir::Location *locPtr = nullptr) override final {
662 mlir::Location loc = locPtr ? *locPtr : toLocation();
Jean Perier7531c872023-01-20 14:05:42 +0100663 if (lowerToHighLevelFIR())
Jean Perier199e4972023-01-13 09:15:52 +0100664 return Fortran::lower::convertExprToValue(loc, *this, expr, localSymbols,
665 context);
Jean Perier45463972022-10-17 09:57:16 +0200666 return Fortran::lower::createSomeExtendedExpression(loc, *this, expr,
667 localSymbols, context);
Valentin Clemente1a12762022-01-28 22:39:44 +0100668 }
Eric Schweitz1bffc752022-04-22 13:59:17 -0700669
670 fir::ExtendedValue
671 genExprBox(mlir::Location loc, const Fortran::lower::SomeExpr &expr,
672 Fortran::lower::StatementContext &stmtCtx) override final {
Jean Perier7531c872023-01-20 14:05:42 +0100673 if (lowerToHighLevelFIR())
Jean Perier4e78f882023-01-10 09:28:08 +0100674 return Fortran::lower::convertExprToBox(loc, *this, expr, localSymbols,
675 stmtCtx);
Valentin Clement94a11062022-03-15 22:18:45 +0100676 return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols,
Eric Schweitz1bffc752022-04-22 13:59:17 -0700677 stmtCtx);
Valentin Clement8c22cb82022-03-01 21:47:40 +0100678 }
Valentin Clemente1a12762022-01-28 22:39:44 +0100679
680 Fortran::evaluate::FoldingContext &getFoldingContext() override final {
681 return foldingContext;
682 }
683
Valentin Clemente641c292022-02-17 18:23:22 +0100684 mlir::Type genType(const Fortran::lower::SomeExpr &expr) override final {
685 return Fortran::lower::translateSomeExprToFIRType(*this, expr);
Valentin Clemente1a12762022-01-28 22:39:44 +0100686 }
Valentin Clementfe252f82022-03-22 15:40:32 +0100687 mlir::Type genType(const Fortran::lower::pft::Variable &var) override final {
688 return Fortran::lower::translateVariableToFIRType(*this, var);
689 }
Valentin Clementad40cc12022-02-14 21:31:46 +0100690 mlir::Type genType(Fortran::lower::SymbolRef sym) override final {
691 return Fortran::lower::translateSymbolToFIRType(*this, sym);
Valentin Clemente1a12762022-01-28 22:39:44 +0100692 }
Valentin Clement8c22cb82022-03-01 21:47:40 +0100693 mlir::Type
694 genType(Fortran::common::TypeCategory tc, int kind,
695 llvm::ArrayRef<std::int64_t> lenParameters) override final {
696 return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind,
697 lenParameters);
Valentin Clemente1a12762022-01-28 22:39:44 +0100698 }
Valentin Clement589d51e2022-03-10 18:06:20 +0100699 mlir::Type
700 genType(const Fortran::semantics::DerivedTypeSpec &tySpec) override final {
701 return Fortran::lower::translateDerivedTypeToFIRType(*this, tySpec);
702 }
703 mlir::Type genType(Fortran::common::TypeCategory tc) override final {
Valentin Clementfe252f82022-03-22 15:40:32 +0100704 return Fortran::lower::getFIRType(
705 &getMLIRContext(), tc, bridge.getDefaultKinds().GetDefaultKind(tc),
Kazu Hirata9a417392022-12-03 12:14:21 -0800706 std::nullopt);
Kiran Chandramohanae37bb92022-02-08 23:01:39 +0000707 }
Valentin Clemente1a12762022-01-28 22:39:44 +0100708
jeanPerierc373f582023-12-19 17:17:09 +0100709 Fortran::lower::TypeConstructionStack &
710 getTypeConstructionStack() override final {
711 return typeConstructionStack;
712 }
713
Kareem Ergawy6af41182024-05-27 14:26:52 +0200714 bool
715 isPresentShallowLookup(const Fortran::semantics::Symbol &sym) override final {
NimishMishra91f92e62023-11-10 00:17:47 -0800716 return bool(shallowLookupSymbol(sym));
717 }
718
jeanPerierff78cd52024-12-05 14:09:48 +0100719 bool createHostAssociateVarClone(const Fortran::semantics::Symbol &sym,
720 bool skipDefaultInit) override final {
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000721 mlir::Location loc = genLocation(sym.name());
722 mlir::Type symType = genType(sym);
723 const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
724 assert(details && "No host-association found");
725 const Fortran::semantics::Symbol &hsym = details->symbol();
Leandro Lupori29cdc8f2024-07-01 14:10:35 -0300726 mlir::Type hSymType = genType(hsym.GetUltimate());
Kareem Ergawy3b305592024-03-11 10:38:28 +0100727 Fortran::lower::SymbolBox hsb =
728 lookupSymbol(hsym, /*symMap=*/nullptr, /*forceHlfirBase=*/true);
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000729
730 auto allocate = [&](llvm::ArrayRef<mlir::Value> shape,
731 llvm::ArrayRef<mlir::Value> typeParams) -> mlir::Value {
732 mlir::Value allocVal = builder->allocateLocal(
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000733 loc,
Peter Klausler031b4e52023-08-21 12:21:49 -0700734 Fortran::semantics::IsAllocatableOrObjectPointer(&hsym.GetUltimate())
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000735 ? hSymType
736 : symType,
737 mangleName(sym), toStringRef(sym.GetUltimate().name()),
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000738 /*pinned=*/true, shape, typeParams,
739 sym.GetUltimate().attrs().test(Fortran::semantics::Attr::TARGET));
740 return allocVal;
741 };
742
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000743 fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000744 fir::ExtendedValue exv = hexv.match(
745 [&](const fir::BoxValue &box) -> fir::ExtendedValue {
746 const Fortran::semantics::DeclTypeSpec *type = sym.GetType();
747 if (type && type->IsPolymorphic())
748 TODO(loc, "create polymorphic host associated copy");
749 // Create a contiguous temp with the same shape and length as
750 // the original variable described by a fir.box.
751 llvm::SmallVector<mlir::Value> extents =
Eric Schweitz1bffc752022-04-22 13:59:17 -0700752 fir::factory::getExtents(loc, *builder, hexv);
753 if (box.isDerivedWithLenParameters())
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000754 TODO(loc, "get length parameters from derived type BoxValue");
755 if (box.isCharacter()) {
756 mlir::Value len = fir::factory::readCharLen(*builder, loc, box);
757 mlir::Value temp = allocate(extents, {len});
758 return fir::CharArrayBoxValue{temp, len, extents};
759 }
760 return fir::ArrayBoxValue{allocate(extents, {}), extents};
761 },
762 [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
763 // Allocate storage for a pointer/allocatble descriptor.
764 // No shape/lengths to be passed to the alloca.
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000765 return fir::MutableBoxValue(allocate({}, {}), {}, {});
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000766 },
767 [&](const auto &) -> fir::ExtendedValue {
768 mlir::Value temp =
Eric Schweitz1bffc752022-04-22 13:59:17 -0700769 allocate(fir::factory::getExtents(loc, *builder, hexv),
Valentin Clement53804e42022-07-07 09:37:12 +0200770 fir::factory::getTypeParams(loc, *builder, hexv));
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000771 return fir::substBase(hexv, temp);
772 });
773
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000774 // Initialise cloned allocatable
775 hexv.match(
776 [&](const fir::MutableBoxValue &box) -> void {
jeanPerierff78cd52024-12-05 14:09:48 +0100777 const auto new_box = exv.getBoxOf<fir::MutableBoxValue>();
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000778 if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
jeanPerierff78cd52024-12-05 14:09:48 +0100779 // Establish the pointer descriptors. The rank and type code/size
780 // at least must be set properly for later inquiry of the pointer
781 // to work, and new pointers are always given disassociated status
782 // by flang for safety, even if this is not required by the
783 // language.
784 auto empty = fir::factory::createUnallocatedBox(
785 *builder, loc, new_box->getBoxTy(), box.nonDeferredLenParams(),
786 {});
787 builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000788 return;
789 }
jeanPerierff78cd52024-12-05 14:09:48 +0100790 // Copy allocation status of Allocatables, creating new storage if
791 // needed.
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000792
793 // allocate if allocated
794 mlir::Value isAllocated =
795 fir::factory::genIsAllocatedOrAssociatedTest(*builder, loc, box);
796 auto if_builder = builder->genIfThenElse(loc, isAllocated);
797 if_builder.genThen([&]() {
798 std::string name = mangleName(sym) + ".alloc";
Kiran Chandramohan57d0d3b2024-05-01 12:58:50 +0100799 fir::ExtendedValue read = fir::factory::genMutableBoxRead(
800 *builder, loc, box, /*mayBePolymorphic=*/false);
801 if (auto read_arr_box = read.getBoxOf<fir::ArrayBoxValue>()) {
802 fir::factory::genInlinedAllocation(
803 *builder, loc, *new_box, read_arr_box->getLBounds(),
804 read_arr_box->getExtents(),
805 /*lenParams=*/std::nullopt, name,
806 /*mustBeHeap=*/true);
807 } else if (auto read_char_arr_box =
808 read.getBoxOf<fir::CharArrayBoxValue>()) {
809 fir::factory::genInlinedAllocation(
810 *builder, loc, *new_box, read_char_arr_box->getLBounds(),
811 read_char_arr_box->getExtents(), read_char_arr_box->getLen(),
812 name,
813 /*mustBeHeap=*/true);
814 } else if (auto read_char_box =
815 read.getBoxOf<fir::CharBoxValue>()) {
816 fir::factory::genInlinedAllocation(*builder, loc, *new_box,
817 /*lbounds=*/std::nullopt,
818 /*extents=*/std::nullopt,
819 read_char_box->getLen(), name,
820 /*mustBeHeap=*/true);
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000821 } else {
822 fir::factory::genInlinedAllocation(
Kiran Chandramohand0ef94b2023-11-07 11:53:30 +0000823 *builder, loc, *new_box, box.getMutableProperties().lbounds,
824 box.getMutableProperties().extents,
825 box.nonDeferredLenParams(), name,
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000826 /*mustBeHeap=*/true);
827 }
828 });
829 if_builder.genElse([&]() {
830 // nullify box
831 auto empty = fir::factory::createUnallocatedBox(
832 *builder, loc, new_box->getBoxTy(),
833 new_box->nonDeferredLenParams(), {});
834 builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
835 });
836 if_builder.end();
837 },
838 [&](const auto &) -> void {
jeanPerierd82d53b2025-01-07 10:04:27 +0100839 // Always initialize allocatable component descriptor, even when the
840 // value is later copied from the host (e.g. firstprivate) because the
841 // assignment from the host to the copy will fail if the component
842 // descriptors are not initialized.
843 if (skipDefaultInit && !hlfir::mayHaveAllocatableComponent(hSymType))
jeanPerierff78cd52024-12-05 14:09:48 +0100844 return;
845 // Initialize local/private derived types with default
846 // initialization (Fortran 2023 section 11.1.7.5 and OpenMP 5.2
847 // section 5.3). Pointer and allocatable components, when allowed,
848 // also need to be established so that flang runtime can later work
849 // with them.
850 if (const Fortran::semantics::DeclTypeSpec *declTypeSpec =
851 sym.GetType())
852 if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
853 declTypeSpec->AsDerived())
854 if (derivedTypeSpec->HasDefaultInitialization(
855 /*ignoreAllocatable=*/false, /*ignorePointer=*/false)) {
856 mlir::Value box = builder->createBox(loc, exv);
857 fir::runtime::genDerivedTypeInitialize(*builder, loc, box);
858 }
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000859 });
860
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000861 return bindIfNewSymbol(sym, exv);
862 }
863
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000864 void createHostAssociateVarCloneDealloc(
865 const Fortran::semantics::Symbol &sym) override final {
866 mlir::Location loc = genLocation(sym.name());
Kareem Ergawy3b305592024-03-11 10:38:28 +0100867 Fortran::lower::SymbolBox hsb =
868 lookupSymbol(sym, /*symMap=*/nullptr, /*forceHlfirBase=*/true);
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000869
870 fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
871 hexv.match(
872 [&](const fir::MutableBoxValue &new_box) -> void {
873 // Do not process pointers
874 if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
875 return;
876 }
877 // deallocate allocated in createHostAssociateVarClone value
jeanPerier2cb31fe2023-09-21 18:38:23 +0200878 Fortran::lower::genDeallocateIfAllocated(*this, new_box, loc);
Dmitriy Smirnovbc4586d2023-07-03 16:31:20 +0000879 },
880 [&](const auto &) -> void {
881 // Do nothing
882 });
883 }
884
Leandro Lupori952bdaa2024-06-25 09:25:41 -0300885 void copyVar(mlir::Location loc, mlir::Value dst, mlir::Value src,
886 fir::FortranVariableFlagsEnum attrs) override final {
887 bool isAllocatable =
888 bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::allocatable);
889 bool isPointer =
890 bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::pointer);
891
Kareem Ergawy87cee712024-03-18 10:44:44 +0100892 copyVarHLFIR(loc, Fortran::lower::SymbolBox::Intrinsic{dst},
Leandro Lupori952bdaa2024-06-25 09:25:41 -0300893 Fortran::lower::SymbolBox::Intrinsic{src}, isAllocatable,
Leandro Lupori797f0112024-09-05 14:55:01 -0300894 isPointer, Fortran::semantics::Symbol::Flags());
Leandro Luporie50a2312024-02-21 14:51:37 -0300895 }
896
Kareem Ergawya0406ce2025-01-16 19:10:12 +0100897 void
898 copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
899 mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr,
900 bool hostIsSource = true) override final {
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000901 // 1) Fetch the original copy of the variable.
902 assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
903 "No host-association found");
904 const Fortran::semantics::Symbol &hsym = sym.GetUltimate();
Peixin-Qiao27afb362022-06-24 15:33:09 +0800905 Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym);
906 assert(hsb && "Host symbol box not found");
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000907
Peixin-Qiao27afb362022-06-24 15:33:09 +0800908 // 2) Fetch the copied one that will mask the original.
909 Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym);
910 assert(sb && "Host-associated symbol box not found");
911 assert(hsb.getAddr() != sb.getAddr() &&
912 "Host and associated symbol boxes are the same");
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000913
914 // 3) Perform the assignment.
Kareem Ergawya0406ce2025-01-16 19:10:12 +0100915 mlir::OpBuilder::InsertionGuard guard(*builder);
Peixin Qiaof4accbf2022-10-05 20:22:33 +0800916 if (copyAssignIP && copyAssignIP->isSet())
917 builder->restoreInsertionPoint(*copyAssignIP);
Arnamoy Bhattacharyya17d9bdf2022-07-25 20:31:23 -0400918 else
jeanPerier2ef370b2023-10-20 11:11:52 +0200919 builder->setInsertionPointAfter(sb.getAddr().getDefiningOp());
Arnamoy Bhattacharyya17d9bdf2022-07-25 20:31:23 -0400920
jeanPerier2ef370b2023-10-20 11:11:52 +0200921 Fortran::lower::SymbolBox *lhs_sb, *rhs_sb;
Kareem Ergawya0406ce2025-01-16 19:10:12 +0100922 if (!hostIsSource) {
jeanPerier2ef370b2023-10-20 11:11:52 +0200923 lhs_sb = &hsb;
924 rhs_sb = &sb;
Arnamoy Bhattacharyya17d9bdf2022-07-25 20:31:23 -0400925 } else {
jeanPerier2ef370b2023-10-20 11:11:52 +0200926 lhs_sb = &sb;
927 rhs_sb = &hsb;
Arnamoy Bhattacharyya17d9bdf2022-07-25 20:31:23 -0400928 }
929
Leandro Lupori797f0112024-09-05 14:55:01 -0300930 copyVar(sym, *lhs_sb, *rhs_sb, sym.flags());
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000931 }
932
Valentin Clement (バレンタイン クレメン)fedc54b2023-12-14 09:25:27 -0800933 void genEval(Fortran::lower::pft::Evaluation &eval,
934 bool unstructuredContext) override final {
935 genFIR(eval, unstructuredContext);
936 }
937
Kiran Chandramohan07e16a22022-04-11 09:05:00 +0000938 //===--------------------------------------------------------------------===//
939 // Utility methods
940 //===--------------------------------------------------------------------===//
941
Peixin-Qiao411bd2d2022-06-07 15:08:17 +0800942 void collectSymbolSet(
943 Fortran::lower::pft::Evaluation &eval,
944 llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet,
Nimish Mishra435feef2022-08-12 16:46:26 +0530945 Fortran::semantics::Symbol::Flag flag, bool collectSymbols,
946 bool checkHostAssociatedSymbols) override final {
Peixin-Qiao411bd2d2022-06-07 15:08:17 +0800947 auto addToList = [&](const Fortran::semantics::Symbol &sym) {
Nimish Mishra435feef2022-08-12 16:46:26 +0530948 std::function<void(const Fortran::semantics::Symbol &, bool)>
949 insertSymbols = [&](const Fortran::semantics::Symbol &oriSymbol,
950 bool collectSymbol) {
Thirumalai Shaktivel091dcb82025-04-01 11:35:44 +0530951 if (collectSymbol && oriSymbol.test(flag)) {
Nimish Mishra435feef2022-08-12 16:46:26 +0530952 symbolSet.insert(&oriSymbol);
Thirumalai Shaktivel091dcb82025-04-01 11:35:44 +0530953 } else if (const auto *commonDetails =
954 oriSymbol.detailsIf<
955 Fortran::semantics::CommonBlockDetails>()) {
956 for (const auto &mem : commonDetails->objects())
957 if (collectSymbol && mem->test(flag))
958 symbolSet.insert(&(*mem).GetUltimate());
959 } else if (checkHostAssociatedSymbols) {
Nimish Mishra435feef2022-08-12 16:46:26 +0530960 if (const auto *details{
961 oriSymbol
962 .detailsIf<Fortran::semantics::HostAssocDetails>()})
963 insertSymbols(details->symbol(), true);
Thirumalai Shaktivel091dcb82025-04-01 11:35:44 +0530964 }
Nimish Mishra435feef2022-08-12 16:46:26 +0530965 };
966 insertSymbols(sym, collectSymbols);
Peixin-Qiao411bd2d2022-06-07 15:08:17 +0800967 };
968 Fortran::lower::pft::visitAllSymbols(eval, addToList);
969 }
970
Valentin Clemente1a12762022-01-28 22:39:44 +0100971 mlir::Location getCurrentLocation() override final { return toLocation(); }
972
973 /// Generate a dummy location.
974 mlir::Location genUnknownLocation() override final {
975 // Note: builder may not be instantiated yet
976 return mlir::UnknownLoc::get(&getMLIRContext());
977 }
978
Valentin Clement (バレンタイン クレメン)0ee0eeb2024-07-23 09:49:17 -0700979 static mlir::Location genLocation(Fortran::parser::SourcePosition pos,
980 mlir::MLIRContext &ctx) {
981 llvm::SmallString<256> path(*pos.path);
982 llvm::sys::fs::make_absolute(path);
983 llvm::sys::path::remove_dots(path);
984 return mlir::FileLineColLoc::get(&ctx, path.str(), pos.line, pos.column);
985 }
986
Valentin Clemente1a12762022-01-28 22:39:44 +0100987 /// Generate a `Location` from the `CharBlock`.
988 mlir::Location
989 genLocation(const Fortran::parser::CharBlock &block) override final {
Valentin Clement (バレンタイン クレメン)0ee0eeb2024-07-23 09:49:17 -0700990 mlir::Location mainLocation = genUnknownLocation();
Valentin Clemente1a12762022-01-28 22:39:44 +0100991 if (const Fortran::parser::AllCookedSources *cooked =
992 bridge.getCookedSource()) {
jeanPerier43d2ef22023-09-26 20:33:01 +0200993 if (std::optional<Fortran::parser::ProvenanceRange> provenance =
994 cooked->GetProvenanceRange(block)) {
995 if (std::optional<Fortran::parser::SourcePosition> filePos =
Valentin Clement (バレンタイン クレメン)0ee0eeb2024-07-23 09:49:17 -0700996 cooked->allSources().GetSourcePosition(provenance->start()))
997 mainLocation = genLocation(*filePos, getMLIRContext());
998
999 llvm::SmallVector<mlir::Location> locs;
1000 locs.push_back(mainLocation);
1001
1002 llvm::SmallVector<fir::LocationKindAttr> locAttrs;
1003 locAttrs.push_back(fir::LocationKindAttr::get(&getMLIRContext(),
1004 fir::LocationKind::Base));
1005
1006 // Gather include location information if any.
1007 Fortran::parser::ProvenanceRange *prov = &*provenance;
1008 while (prov) {
1009 if (std::optional<Fortran::parser::ProvenanceRange> include =
1010 cooked->allSources().GetInclusionInfo(*prov)) {
1011 if (std::optional<Fortran::parser::SourcePosition> incPos =
1012 cooked->allSources().GetSourcePosition(include->start())) {
1013 locs.push_back(genLocation(*incPos, getMLIRContext()));
1014 locAttrs.push_back(fir::LocationKindAttr::get(
1015 &getMLIRContext(), fir::LocationKind::Inclusion));
1016 }
1017 prov = &*include;
1018 } else {
1019 prov = nullptr;
1020 }
1021 }
1022 if (locs.size() > 1) {
1023 assert(locs.size() == locAttrs.size() &&
1024 "expect as many attributes as locations");
1025 return mlir::FusedLocWith<fir::LocationKindArrayAttr>::get(
1026 &getMLIRContext(), locs,
1027 fir::LocationKindArrayAttr::get(&getMLIRContext(), locAttrs));
jeanPerier43d2ef22023-09-26 20:33:01 +02001028 }
Valentin Clemente1a12762022-01-28 22:39:44 +01001029 }
1030 }
Valentin Clement (バレンタイン クレメン)0ee0eeb2024-07-23 09:49:17 -07001031 return mainLocation;
Valentin Clemente1a12762022-01-28 22:39:44 +01001032 }
1033
V Donaldson6f7a3b02023-05-16 13:34:57 -07001034 const Fortran::semantics::Scope &getCurrentScope() override final {
1035 return bridge.getSemanticsContext().FindScope(currentPosition);
1036 }
1037
Valentin Clemente1a12762022-01-28 22:39:44 +01001038 fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; }
1039
Matthias Springerc8706322024-12-25 09:42:03 +01001040 mlir::ModuleOp getModuleOp() override final { return bridge.getModule(); }
Valentin Clemente1a12762022-01-28 22:39:44 +01001041
1042 mlir::MLIRContext &getMLIRContext() override final {
1043 return bridge.getMLIRContext();
1044 }
1045 std::string
1046 mangleName(const Fortran::semantics::Symbol &symbol) override final {
jeanPerier6ffea742023-09-08 10:43:55 +02001047 return Fortran::lower::mangle::mangleName(
1048 symbol, scopeBlockIdMap, /*keepExternalInScope=*/false,
1049 getLoweringOptions().getUnderscoring());
V Donaldson2c143342023-02-27 14:05:53 -08001050 }
1051 std::string mangleName(
1052 const Fortran::semantics::DerivedTypeSpec &derivedType) override final {
1053 return Fortran::lower::mangle::mangleName(derivedType, scopeBlockIdMap);
Valentin Clemente1a12762022-01-28 22:39:44 +01001054 }
V Donaldson6f7a3b02023-05-16 13:34:57 -07001055 std::string mangleName(std::string &name) override final {
1056 return Fortran::lower::mangle::mangleName(name, getCurrentScope(),
1057 scopeBlockIdMap);
1058 }
Akash Banerjee99057282025-02-18 16:36:01 +00001059 std::string
1060 mangleName(std::string &name,
1061 const Fortran::semantics::Scope &myScope) override final {
1062 return Fortran::lower::mangle::mangleName(name, myScope, scopeBlockIdMap);
1063 }
jeanPerier99a54b82023-09-18 14:59:56 +02001064 std::string getRecordTypeFieldName(
1065 const Fortran::semantics::Symbol &component) override final {
1066 return Fortran::lower::mangle::getRecordTypeFieldName(component,
1067 scopeBlockIdMap);
1068 }
Valentin Clemente1a12762022-01-28 22:39:44 +01001069 const fir::KindMapping &getKindMap() override final {
1070 return bridge.getKindMap();
1071 }
1072
V Donaldson2c143342023-02-27 14:05:53 -08001073 /// Return the current function context, which may be a nested BLOCK context
1074 /// or a full subprogram context.
Valentin Clement97492fd1a2023-01-31 13:46:12 +01001075 Fortran::lower::StatementContext &getFctCtx() override final {
V Donaldson2c143342023-02-27 14:05:53 -08001076 if (!activeConstructStack.empty() &&
1077 activeConstructStack.back().eval.isA<Fortran::parser::BlockConstruct>())
1078 return activeConstructStack.back().stmtCtx;
Valentin Clement97492fd1a2023-01-31 13:46:12 +01001079 return bridge.fctCtx();
1080 }
1081
Valentin Clementd0b70a02022-02-23 19:48:07 +01001082 mlir::Value hostAssocTupleValue() override final { return hostAssocTuple; }
1083
Valentin Clement764f95a2022-03-07 19:55:48 +01001084 /// Record a binding for the ssa-value of the tuple for this function.
1085 void bindHostAssocTuple(mlir::Value val) override final {
1086 assert(!hostAssocTuple && val);
1087 hostAssocTuple = val;
1088 }
1089
Slava Zakharin1710c8c2024-05-08 16:48:14 -07001090 mlir::Value dummyArgsScopeValue() const override final {
1091 return dummyArgsScope;
1092 }
1093
1094 bool isRegisteredDummySymbol(
1095 Fortran::semantics::SymbolRef symRef) const override final {
1096 auto *sym = &*symRef;
1097 return registeredDummySymbols.contains(sym);
1098 }
1099
jeanPerierbb8bf852024-11-26 09:21:13 +01001100 const Fortran::lower::pft::FunctionLikeUnit *
1101 getCurrentFunctionUnit() const override final {
1102 return currentFunctionUnit;
1103 }
1104
jeanPerier4ccd57d2023-10-06 09:29:57 +02001105 void registerTypeInfo(mlir::Location loc,
1106 Fortran::lower::SymbolRef typeInfoSym,
1107 const Fortran::semantics::DerivedTypeSpec &typeSpec,
1108 fir::RecordType type) override final {
1109 typeInfoConverter.registerTypeInfo(*this, loc, typeInfoSym, typeSpec, type);
Valentin Clement6393d2e2022-11-17 10:53:13 +01001110 }
1111
Slava Zakharinbe5747e2023-05-09 19:50:48 -07001112 llvm::StringRef
1113 getUniqueLitName(mlir::Location loc,
1114 std::unique_ptr<Fortran::lower::SomeExpr> expr,
1115 mlir::Type eleTy) override final {
1116 std::string namePrefix =
1117 getConstantExprManglePrefix(loc, *expr.get(), eleTy);
1118 auto [it, inserted] = literalNamesMap.try_emplace(
1119 expr.get(), namePrefix + std::to_string(uniqueLitId));
1120 const auto &name = it->second;
1121 if (inserted) {
1122 // Keep ownership of the expr key.
1123 literalExprsStorage.push_back(std::move(expr));
1124
1125 // If we've just added a new name, we have to make sure
1126 // there is no global object with the same name in the module.
1127 fir::GlobalOp global = builder->getNamedGlobal(name);
1128 if (global)
1129 fir::emitFatalError(loc, llvm::Twine("global object with name '") +
1130 llvm::Twine(name) +
1131 llvm::Twine("' already exists"));
1132 ++uniqueLitId;
1133 return name;
1134 }
1135
1136 // The name already exists. Verify that the prefix is the same.
1137 if (!llvm::StringRef(name).starts_with(namePrefix))
1138 fir::emitFatalError(loc, llvm::Twine("conflicting prefixes: '") +
1139 llvm::Twine(name) +
1140 llvm::Twine("' does not start with '") +
1141 llvm::Twine(namePrefix) + llvm::Twine("'"));
1142
1143 return name;
1144 }
1145
Valentin Clemente1a12762022-01-28 22:39:44 +01001146private:
1147 FirConverter() = delete;
1148 FirConverter(const FirConverter &) = delete;
1149 FirConverter &operator=(const FirConverter &) = delete;
1150
1151 //===--------------------------------------------------------------------===//
1152 // Helper member functions
1153 //===--------------------------------------------------------------------===//
1154
Valentin Clement764f95a2022-03-07 19:55:48 +01001155 mlir::Value createFIRExpr(mlir::Location loc,
1156 const Fortran::lower::SomeExpr *expr,
1157 Fortran::lower::StatementContext &stmtCtx) {
1158 return fir::getBase(genExprValue(*expr, stmtCtx, &loc));
1159 }
1160
Valentin Clemente1a12762022-01-28 22:39:44 +01001161 /// Find the symbol in the local map or return null.
1162 Fortran::lower::SymbolBox
Jean Perierab9c4e92023-02-07 09:22:47 +01001163 lookupSymbol(const Fortran::semantics::Symbol &sym,
Kareem Ergawy3b305592024-03-11 10:38:28 +01001164 Fortran::lower::SymMap *symMap = nullptr,
1165 bool forceHlfirBase = false) {
Jean Perierab9c4e92023-02-07 09:22:47 +01001166 symMap = symMap ? symMap : &localSymbols;
Jean Perier7531c872023-01-20 14:05:42 +01001167 if (lowerToHighLevelFIR()) {
Kazu Hiratac0921582023-01-07 22:26:48 -08001168 if (std::optional<fir::FortranVariableOpInterface> var =
Jean Perierab9c4e92023-02-07 09:22:47 +01001169 symMap->lookupVariableDefinition(sym)) {
Kareem Ergawy3b305592024-03-11 10:38:28 +01001170 auto exv = hlfir::translateToExtendedValue(toLocation(), *builder, *var,
1171 forceHlfirBase);
Jean Perier19811162022-12-05 09:05:37 +01001172 return exv.match(
1173 [](mlir::Value x) -> Fortran::lower::SymbolBox {
1174 return Fortran::lower::SymbolBox::Intrinsic{x};
1175 },
1176 [](auto x) -> Fortran::lower::SymbolBox { return x; });
1177 }
Slava Zakharin4eab3032023-05-16 20:05:22 -07001178
1179 // Entry character result represented as an argument pair
1180 // needs to be represented in the symbol table even before
1181 // we can create DeclareOp for it. The temporary mapping
1182 // is EmboxCharOp that conveys the address and length information.
1183 // After mapSymbolAttributes is done, the mapping is replaced
1184 // with the new DeclareOp, and the following table lookups
1185 // do not reach here.
1186 if (sym.IsFuncResult())
1187 if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
1188 if (declTy->category() ==
1189 Fortran::semantics::DeclTypeSpec::Category::Character)
1190 return symMap->lookupSymbol(sym);
1191
Jean Periercedfd272023-02-09 09:02:43 +01001192 // Procedure dummies are not mapped with an hlfir.declare because
1193 // they are not "variable" (cannot be assigned to), and it would
1194 // make hlfir.declare more complex than it needs to to allow this.
1195 // Do a regular lookup.
1196 if (Fortran::semantics::IsProcedure(sym))
1197 return symMap->lookupSymbol(sym);
Kiran Chandramohan8b834ca2023-08-23 11:37:00 +00001198
1199 // Commonblock names are not variables, but in some lowerings (like
1200 // OpenMP) it is useful to maintain the address of the commonblock in an
1201 // MLIR value and query it. hlfir.declare need not be created for these.
1202 if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>())
1203 return symMap->lookupSymbol(sym);
1204
Kareem Ergawy26b8be22024-02-28 10:15:57 +01001205 // For symbols to be privatized in OMP, the symbol is mapped to an
1206 // instance of `SymbolBox::Intrinsic` (i.e. a direct mapping to an MLIR
1207 // SSA value). This MLIR SSA value is the block argument to the
1208 // `omp.private`'s `alloc` block. If this is the case, we return this
1209 // `SymbolBox::Intrinsic` value.
1210 if (Fortran::lower::SymbolBox v = symMap->lookupSymbol(sym))
Kareem Ergawy87cee712024-03-18 10:44:44 +01001211 return v;
Kareem Ergawy26b8be22024-02-28 10:15:57 +01001212
Jean Perier19811162022-12-05 09:05:37 +01001213 return {};
1214 }
Jean Perierab9c4e92023-02-07 09:22:47 +01001215 if (Fortran::lower::SymbolBox v = symMap->lookupSymbol(sym))
Valentin Clemente1a12762022-01-28 22:39:44 +01001216 return v;
1217 return {};
1218 }
1219
Valentin Clementa1425012022-03-15 21:57:30 +01001220 /// Find the symbol in the inner-most level of the local map or return null.
1221 Fortran::lower::SymbolBox
1222 shallowLookupSymbol(const Fortran::semantics::Symbol &sym) {
1223 if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
1224 return v;
1225 return {};
1226 }
1227
Peixin-Qiao27afb362022-06-24 15:33:09 +08001228 /// Find the symbol in one level up of symbol map such as for host-association
1229 /// in OpenMP code or return null.
1230 Fortran::lower::SymbolBox
Kareem Ergawy26b8be22024-02-28 10:15:57 +01001231 lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) override {
Peixin-Qiao27afb362022-06-24 15:33:09 +08001232 if (Fortran::lower::SymbolBox v = localSymbols.lookupOneLevelUpSymbol(sym))
1233 return v;
1234 return {};
1235 }
1236
jeanPeriera4798bb2024-04-02 14:29:29 +02001237 mlir::SymbolTable *getMLIRSymbolTable() override { return &mlirSymbolTable; }
1238
Valentin Clementda7c77b2022-02-16 20:27:23 +01001239 /// Add the symbol to the local map and return `true`. If the symbol is
1240 /// already in the map and \p forced is `false`, the map is not updated.
1241 /// Instead the value `false` is returned.
Jean Perierab9c4e92023-02-07 09:22:47 +01001242 bool addSymbol(const Fortran::semantics::SymbolRef sym,
1243 fir::ExtendedValue val, bool forced = false) {
1244 if (!forced && lookupSymbol(sym))
1245 return false;
1246 if (lowerToHighLevelFIR()) {
Slava Zakharin47025af2023-09-18 09:59:06 -07001247 Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val,
1248 fir::FortranVariableFlagsEnum::None,
1249 forced);
Jean Perierab9c4e92023-02-07 09:22:47 +01001250 } else {
1251 localSymbols.addSymbol(sym, val, forced);
1252 }
1253 return true;
1254 }
1255
Leandro Luporie50a2312024-02-21 14:51:37 -03001256 void copyVar(const Fortran::semantics::Symbol &sym,
1257 const Fortran::lower::SymbolBox &lhs_sb,
Leandro Lupori797f0112024-09-05 14:55:01 -03001258 const Fortran::lower::SymbolBox &rhs_sb,
1259 Fortran::semantics::Symbol::Flags flags) {
Leandro Luporie50a2312024-02-21 14:51:37 -03001260 mlir::Location loc = genLocation(sym.name());
1261 if (lowerToHighLevelFIR())
Leandro Lupori797f0112024-09-05 14:55:01 -03001262 copyVarHLFIR(loc, lhs_sb, rhs_sb, flags);
Leandro Luporie50a2312024-02-21 14:51:37 -03001263 else
1264 copyVarFIR(loc, sym, lhs_sb, rhs_sb);
1265 }
1266
Kareem Ergawy87cee712024-03-18 10:44:44 +01001267 void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst,
Leandro Lupori797f0112024-09-05 14:55:01 -03001268 Fortran::lower::SymbolBox src,
1269 Fortran::semantics::Symbol::Flags flags) {
Leandro Luporie50a2312024-02-21 14:51:37 -03001270 assert(lowerToHighLevelFIR());
Leandro Lupori952bdaa2024-06-25 09:25:41 -03001271
1272 bool isBoxAllocatable = dst.match(
1273 [](const fir::MutableBoxValue &box) { return box.isAllocatable(); },
1274 [](const fir::FortranVariableOpInterface &box) {
1275 return fir::FortranVariableOpInterface(box).isAllocatable();
1276 },
1277 [](const auto &box) { return false; });
1278
1279 bool isBoxPointer = dst.match(
1280 [](const fir::MutableBoxValue &box) { return box.isPointer(); },
1281 [](const fir::FortranVariableOpInterface &box) {
1282 return fir::FortranVariableOpInterface(box).isPointer();
1283 },
Leandro Lupori29f5d5b2025-03-11 09:38:40 -03001284 [](const fir::AbstractBox &box) {
1285 return fir::isBoxProcAddressType(box.getAddr().getType());
1286 },
Leandro Lupori952bdaa2024-06-25 09:25:41 -03001287 [](const auto &box) { return false; });
1288
Leandro Lupori797f0112024-09-05 14:55:01 -03001289 copyVarHLFIR(loc, dst, src, isBoxAllocatable, isBoxPointer, flags);
Leandro Lupori952bdaa2024-06-25 09:25:41 -03001290 }
1291
1292 void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst,
1293 Fortran::lower::SymbolBox src, bool isAllocatable,
Leandro Lupori797f0112024-09-05 14:55:01 -03001294 bool isPointer, Fortran::semantics::Symbol::Flags flags) {
Leandro Lupori952bdaa2024-06-25 09:25:41 -03001295 assert(lowerToHighLevelFIR());
Kareem Ergawy87cee712024-03-18 10:44:44 +01001296 hlfir::Entity lhs{dst.getAddr()};
1297 hlfir::Entity rhs{src.getAddr()};
Leandro Lupori797f0112024-09-05 14:55:01 -03001298
Leandro Luporie50a2312024-02-21 14:51:37 -03001299 auto copyData = [&](hlfir::Entity l, hlfir::Entity r) {
1300 // Dereference RHS and load it if trivial scalar.
1301 r = hlfir::loadTrivialScalar(loc, *builder, r);
Leandro Lupori797f0112024-09-05 14:55:01 -03001302 builder->create<hlfir::AssignOp>(loc, r, l, isAllocatable);
Leandro Luporie50a2312024-02-21 14:51:37 -03001303 };
Kareem Ergawy87cee712024-03-18 10:44:44 +01001304
Leandro Lupori797f0112024-09-05 14:55:01 -03001305 if (isPointer) {
Leandro Luporie50a2312024-02-21 14:51:37 -03001306 // Set LHS target to the target of RHS (do not copy the RHS
1307 // target data into the LHS target storage).
1308 auto loadVal = builder->create<fir::LoadOp>(loc, rhs);
1309 builder->create<fir::StoreOp>(loc, loadVal, lhs);
Leandro Lupori797f0112024-09-05 14:55:01 -03001310 } else if (isAllocatable &&
Kaviya Rajendirandaa18202025-01-23 11:14:00 +05301311 flags.test(Fortran::semantics::Symbol::Flag::OmpCopyIn)) {
1312 // For copyin allocatable variables, RHS must be copied to lhs
1313 // only when rhs is allocated.
1314 hlfir::Entity temp =
1315 hlfir::derefPointersAndAllocatables(loc, *builder, rhs);
1316 mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, temp);
1317 mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
1318 builder->genIfThenElse(loc, isAllocated)
1319 .genThen([&]() { copyData(lhs, rhs); })
1320 .genElse([&]() {
1321 fir::ExtendedValue hexv = symBoxToExtendedValue(dst);
1322 hexv.match(
1323 [&](const fir::MutableBoxValue &new_box) -> void {
1324 // if the allocation status of original list item is
1325 // unallocated, unallocate the copy if it is allocated, else
1326 // do nothing.
1327 Fortran::lower::genDeallocateIfAllocated(*this, new_box, loc);
1328 },
1329 [&](const auto &) -> void {});
1330 })
1331 .end();
1332 } else if (isAllocatable &&
1333 flags.test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) {
1334 // For firstprivate allocatable variables, RHS must be copied
David Truby53b59022024-09-10 14:59:21 +01001335 // only when LHS is allocated.
Leandro Lupori797f0112024-09-05 14:55:01 -03001336 hlfir::Entity temp =
1337 hlfir::derefPointersAndAllocatables(loc, *builder, lhs);
1338 mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, temp);
1339 mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
1340 builder->genIfThen(loc, isAllocated)
1341 .genThen([&]() { copyData(lhs, rhs); })
1342 .end();
Leandro Luporie50a2312024-02-21 14:51:37 -03001343 } else {
Leandro Luporie50a2312024-02-21 14:51:37 -03001344 copyData(lhs, rhs);
1345 }
1346 }
1347
1348 void copyVarFIR(mlir::Location loc, const Fortran::semantics::Symbol &sym,
1349 const Fortran::lower::SymbolBox &lhs_sb,
1350 const Fortran::lower::SymbolBox &rhs_sb) {
1351 assert(!lowerToHighLevelFIR());
1352 fir::ExtendedValue lhs = symBoxToExtendedValue(lhs_sb);
1353 fir::ExtendedValue rhs = symBoxToExtendedValue(rhs_sb);
1354 mlir::Type symType = genType(sym);
Christian Siggfac349a2024-04-28 22:01:42 +02001355 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(symType)) {
Leandro Luporie50a2312024-02-21 14:51:37 -03001356 Fortran::lower::StatementContext stmtCtx;
1357 Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
1358 stmtCtx);
1359 stmtCtx.finalizeAndReset();
1360 } else if (lhs.getBoxOf<fir::CharBoxValue>()) {
1361 fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
1362 } else {
1363 auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
1364 builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
1365 }
1366 }
1367
Jean Perierab9c4e92023-02-07 09:22:47 +01001368 /// Map a block argument to a result or dummy symbol. This is not the
1369 /// definitive mapping. The specification expression have not been lowered
1370 /// yet. The final mapping will be done using this pre-mapping in
1371 /// Fortran::lower::mapSymbolAttributes.
1372 bool mapBlockArgToDummyOrResult(const Fortran::semantics::SymbolRef sym,
Slava Zakharin1710c8c2024-05-08 16:48:14 -07001373 mlir::Value val, bool isResult) {
1374 localSymbols.addSymbol(sym, val);
1375 if (!isResult)
1376 registerDummySymbol(sym);
1377
Valentin Clementda7c77b2022-02-16 20:27:23 +01001378 return true;
1379 }
1380
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00001381 /// Generate the address of loop variable \p sym.
Mats Petersson84b9ae62022-06-07 14:00:08 +01001382 /// If \p sym is not mapped yet, allocate local storage for it.
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00001383 mlir::Value genLoopVariableAddress(mlir::Location loc,
Mats Petersson84b9ae62022-06-07 14:00:08 +01001384 const Fortran::semantics::Symbol &sym,
1385 bool isUnordered) {
1386 if (isUnordered || sym.has<Fortran::semantics::HostAssocDetails>() ||
1387 sym.has<Fortran::semantics::UseDetails>()) {
Mats Petersson8e10a3f2024-09-13 12:57:11 +01001388 if (!shallowLookupSymbol(sym) &&
1389 !sym.test(Fortran::semantics::Symbol::Flag::OmpShared)) {
Mats Petersson84b9ae62022-06-07 14:00:08 +01001390 // Do concurrent loop variables are not mapped yet since they are local
1391 // to the Do concurrent scope (same for OpenMP loops).
Kiran Chandramohan90f58eb2023-09-01 10:44:35 +00001392 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
1393 builder->setInsertionPointToStart(builder->getAllocaBlock());
1394 mlir::Type tempTy = genType(sym);
1395 mlir::Value temp =
1396 builder->createTemporaryAlloc(loc, tempTy, toStringRef(sym.name()));
1397 bindIfNewSymbol(sym, temp);
1398 builder->restoreInsertionPoint(insPt);
Mats Petersson84b9ae62022-06-07 14:00:08 +01001399 }
1400 }
1401 auto entry = lookupSymbol(sym);
1402 (void)entry;
1403 assert(entry && "loop control variable must already be in map");
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00001404 Fortran::lower::StatementContext stmtCtx;
1405 return fir::getBase(
1406 genExprAddr(Fortran::evaluate::AsGenericExpr(sym).value(), stmtCtx));
1407 }
1408
Valentin Clementfe252f82022-03-22 15:40:32 +01001409 static bool isNumericScalarCategory(Fortran::common::TypeCategory cat) {
Valentin Clemente641c292022-02-17 18:23:22 +01001410 return cat == Fortran::common::TypeCategory::Integer ||
1411 cat == Fortran::common::TypeCategory::Real ||
1412 cat == Fortran::common::TypeCategory::Complex ||
1413 cat == Fortran::common::TypeCategory::Logical;
1414 }
Valentin Clement308fc3f2022-03-18 15:39:57 +01001415 static bool isLogicalCategory(Fortran::common::TypeCategory cat) {
1416 return cat == Fortran::common::TypeCategory::Logical;
1417 }
Valentin Clementfe252f82022-03-22 15:40:32 +01001418 static bool isCharacterCategory(Fortran::common::TypeCategory cat) {
Valentin Clemente641c292022-02-17 18:23:22 +01001419 return cat == Fortran::common::TypeCategory::Character;
1420 }
Valentin Clementfe252f82022-03-22 15:40:32 +01001421 static bool isDerivedCategory(Fortran::common::TypeCategory cat) {
Valentin Clemente641c292022-02-17 18:23:22 +01001422 return cat == Fortran::common::TypeCategory::Derived;
1423 }
1424
V Donaldson2c143342023-02-27 14:05:53 -08001425 /// Insert a new block before \p block. Leave the insertion point unchanged.
Valentin Clement308fc3f2022-03-18 15:39:57 +01001426 mlir::Block *insertBlock(mlir::Block *block) {
1427 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1428 mlir::Block *newBlock = builder->createBlock(block);
1429 builder->restoreInsertionPoint(insertPt);
1430 return newBlock;
1431 }
1432
V Donaldson2c143342023-02-27 14:05:53 -08001433 Fortran::lower::pft::Evaluation &evalOfLabel(Fortran::parser::Label label) {
Valentin Clement8c22cb82022-03-01 21:47:40 +01001434 const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap =
V Donaldson2c143342023-02-27 14:05:53 -08001435 getEval().getOwningProcedure()->labelEvaluationMap;
Valentin Clement8c22cb82022-03-01 21:47:40 +01001436 const auto iter = labelEvaluationMap.find(label);
1437 assert(iter != labelEvaluationMap.end() && "label missing from map");
V Donaldson2c143342023-02-27 14:05:53 -08001438 return *iter->second;
Valentin Clement8c22cb82022-03-01 21:47:40 +01001439 }
1440
V Donaldson2c143342023-02-27 14:05:53 -08001441 void genBranch(mlir::Block *targetBlock) {
Kiran Chandramohanae37bb92022-02-08 23:01:39 +00001442 assert(targetBlock && "missing unconditional target block");
Valentin Clementfe252f82022-03-22 15:40:32 +01001443 builder->create<mlir::cf::BranchOp>(toLocation(), targetBlock);
Kiran Chandramohanae37bb92022-02-08 23:01:39 +00001444 }
1445
V Donaldson2c143342023-02-27 14:05:53 -08001446 void genConditionalBranch(mlir::Value cond, mlir::Block *trueTarget,
1447 mlir::Block *falseTarget) {
Valentin Clement764f95a2022-03-07 19:55:48 +01001448 assert(trueTarget && "missing conditional branch true block");
1449 assert(falseTarget && "missing conditional branch false block");
1450 mlir::Location loc = toLocation();
1451 mlir::Value bcc = builder->createConvert(loc, builder->getI1Type(), cond);
Kazu Hirata9a417392022-12-03 12:14:21 -08001452 builder->create<mlir::cf::CondBranchOp>(loc, bcc, trueTarget, std::nullopt,
1453 falseTarget, std::nullopt);
Valentin Clement764f95a2022-03-07 19:55:48 +01001454 }
V Donaldson2c143342023-02-27 14:05:53 -08001455 void genConditionalBranch(mlir::Value cond,
1456 Fortran::lower::pft::Evaluation *trueTarget,
1457 Fortran::lower::pft::Evaluation *falseTarget) {
1458 genConditionalBranch(cond, trueTarget->block, falseTarget->block);
Valentin Clement764f95a2022-03-07 19:55:48 +01001459 }
V Donaldson2c143342023-02-27 14:05:53 -08001460 void genConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
1461 mlir::Block *trueTarget, mlir::Block *falseTarget) {
Valentin Clement764f95a2022-03-07 19:55:48 +01001462 Fortran::lower::StatementContext stmtCtx;
1463 mlir::Value cond =
1464 createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08001465 stmtCtx.finalizeAndReset();
1466 genConditionalBranch(cond, trueTarget, falseTarget);
Valentin Clement764f95a2022-03-07 19:55:48 +01001467 }
V Donaldson2c143342023-02-27 14:05:53 -08001468 void genConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
1469 Fortran::lower::pft::Evaluation *trueTarget,
1470 Fortran::lower::pft::Evaluation *falseTarget) {
Valentin Clement764f95a2022-03-07 19:55:48 +01001471 Fortran::lower::StatementContext stmtCtx;
1472 mlir::Value cond =
1473 createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08001474 stmtCtx.finalizeAndReset();
1475 genConditionalBranch(cond, trueTarget->block, falseTarget->block);
1476 }
1477
1478 /// Return the nearest active ancestor construct of \p eval, or nullptr.
1479 Fortran::lower::pft::Evaluation *
1480 getActiveAncestor(const Fortran::lower::pft::Evaluation &eval) {
1481 Fortran::lower::pft::Evaluation *ancestor = eval.parentConstruct;
1482 for (; ancestor; ancestor = ancestor->parentConstruct)
1483 if (ancestor->activeConstruct)
1484 break;
1485 return ancestor;
1486 }
1487
1488 /// Return the predicate: "a branch to \p targetEval has exit code".
1489 bool hasExitCode(const Fortran::lower::pft::Evaluation &targetEval) {
1490 Fortran::lower::pft::Evaluation *activeAncestor =
1491 getActiveAncestor(targetEval);
1492 for (auto it = activeConstructStack.rbegin(),
1493 rend = activeConstructStack.rend();
1494 it != rend; ++it) {
1495 if (&it->eval == activeAncestor)
1496 break;
1497 if (it->stmtCtx.hasCode())
1498 return true;
1499 }
1500 return false;
1501 }
1502
1503 /// Generate a branch to \p targetEval after generating on-exit code for
1504 /// any enclosing construct scopes that are exited by taking the branch.
1505 void
1506 genConstructExitBranch(const Fortran::lower::pft::Evaluation &targetEval) {
1507 Fortran::lower::pft::Evaluation *activeAncestor =
1508 getActiveAncestor(targetEval);
1509 for (auto it = activeConstructStack.rbegin(),
1510 rend = activeConstructStack.rend();
1511 it != rend; ++it) {
1512 if (&it->eval == activeAncestor)
1513 break;
1514 it->stmtCtx.finalizeAndKeep();
1515 }
1516 genBranch(targetEval.block);
1517 }
1518
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05001519 /// A construct contains nested evaluations. Some of these evaluations
1520 /// may start a new basic block, others will add code to an existing
1521 /// block.
1522 /// Collect the list of nested evaluations that are last in their block,
1523 /// organize them into two sets:
1524 /// 1. Exiting evaluations: they may need a branch exiting from their
1525 /// parent construct,
1526 /// 2. Fall-through evaluations: they will continue to the following
1527 /// evaluation. They may still need a branch, but they do not exit
1528 /// the construct. They appear in cases where the following evaluation
1529 /// is a target of some branch.
1530 void collectFinalEvaluations(
1531 Fortran::lower::pft::Evaluation &construct,
1532 llvm::SmallVector<Fortran::lower::pft::Evaluation *> &exits,
1533 llvm::SmallVector<Fortran::lower::pft::Evaluation *> &fallThroughs) {
1534 Fortran::lower::pft::EvaluationList &nested =
1535 construct.getNestedEvaluations();
1536 if (nested.empty())
1537 return;
1538
1539 Fortran::lower::pft::Evaluation *exit = construct.constructExit;
1540 Fortran::lower::pft::Evaluation *previous = &nested.front();
1541
1542 for (auto it = ++nested.begin(), end = nested.end(); it != end;
1543 previous = &*it++) {
1544 if (it->block == nullptr)
1545 continue;
1546 // "*it" starts a new block, check what to do with "previous"
1547 if (it->isIntermediateConstructStmt() && previous != exit)
1548 exits.push_back(previous);
1549 else if (previous->lexicalSuccessor && previous->lexicalSuccessor->block)
1550 fallThroughs.push_back(previous);
1551 }
1552 if (previous != exit)
1553 exits.push_back(previous);
1554 }
1555
V Donaldson2c143342023-02-27 14:05:53 -08001556 /// Generate a SelectOp or branch sequence that compares \p selector against
1557 /// values in \p valueList and targets corresponding labels in \p labelList.
1558 /// If no value matches the selector, branch to \p defaultEval.
1559 ///
V Donaldsonfd922e62023-04-05 11:13:36 -07001560 /// Three cases require special processing.
V Donaldson5e521582023-03-31 09:36:16 -07001561 ///
1562 /// An empty \p valueList indicates an ArithmeticIfStmt context that requires
1563 /// two comparisons against 0 or 0.0. The selector may have either INTEGER
1564 /// or REAL type.
1565 ///
1566 /// A nonpositive \p valuelist value indicates an IO statement context
1567 /// (0 for ERR, -1 for END, -2 for EOR). An ERR branch must be taken for
1568 /// any positive (IOSTAT) value. A missing (zero) label requires a branch
1569 /// to \p defaultEval for that value.
V Donaldson2c143342023-02-27 14:05:53 -08001570 ///
V Donaldsonfd922e62023-04-05 11:13:36 -07001571 /// A non-null \p errorBlock indicates an AssignedGotoStmt context that
1572 /// must always branch to an explicit target. There is no valid defaultEval
1573 /// in this case. Generate a branch to \p errorBlock for an AssignedGotoStmt
1574 /// that violates this program requirement.
1575 ///
V Donaldson2c143342023-02-27 14:05:53 -08001576 /// If this is not an ArithmeticIfStmt and no targets have exit code,
1577 /// generate a SelectOp. Otherwise, for each target, if it has exit code,
1578 /// branch to a new block, insert exit code, and then branch to the target.
1579 /// Otherwise, branch directly to the target.
1580 void genMultiwayBranch(mlir::Value selector,
1581 llvm::SmallVector<int64_t> valueList,
1582 llvm::SmallVector<Fortran::parser::Label> labelList,
V Donaldsonfd922e62023-04-05 11:13:36 -07001583 const Fortran::lower::pft::Evaluation &defaultEval,
1584 mlir::Block *errorBlock = nullptr) {
V Donaldson2c143342023-02-27 14:05:53 -08001585 bool inArithmeticIfContext = valueList.empty();
1586 assert(((inArithmeticIfContext && labelList.size() == 2) ||
1587 (valueList.size() && labelList.size() == valueList.size())) &&
1588 "mismatched multiway branch targets");
V Donaldsonfd922e62023-04-05 11:13:36 -07001589 mlir::Block *defaultBlock = errorBlock ? errorBlock : defaultEval.block;
1590 bool defaultHasExitCode = !errorBlock && hasExitCode(defaultEval);
V Donaldson2c143342023-02-27 14:05:53 -08001591 bool hasAnyExitCode = defaultHasExitCode;
1592 if (!hasAnyExitCode)
1593 for (auto label : labelList)
V Donaldson5e521582023-03-31 09:36:16 -07001594 if (label && hasExitCode(evalOfLabel(label))) {
V Donaldson2c143342023-02-27 14:05:53 -08001595 hasAnyExitCode = true;
1596 break;
1597 }
1598 mlir::Location loc = toLocation();
1599 size_t branchCount = labelList.size();
1600 if (!inArithmeticIfContext && !hasAnyExitCode &&
1601 !getEval().forceAsUnstructured()) { // from -no-structured-fir option
1602 // Generate a SelectOp.
1603 llvm::SmallVector<mlir::Block *> blockList;
V Donaldson5e521582023-03-31 09:36:16 -07001604 for (auto label : labelList) {
1605 mlir::Block *block =
1606 label ? evalOfLabel(label).block : defaultEval.block;
1607 assert(block && "missing multiway branch block");
1608 blockList.push_back(block);
V Donaldson2c143342023-02-27 14:05:53 -08001609 }
V Donaldsonfd922e62023-04-05 11:13:36 -07001610 blockList.push_back(defaultBlock);
V Donaldson5e521582023-03-31 09:36:16 -07001611 if (valueList[branchCount - 1] == 0) // Swap IO ERR and default blocks.
1612 std::swap(blockList[branchCount - 1], blockList[branchCount]);
V Donaldson2c143342023-02-27 14:05:53 -08001613 builder->create<fir::SelectOp>(loc, selector, valueList, blockList);
1614 return;
1615 }
1616 mlir::Type selectorType = selector.getType();
Christian Siggfac349a2024-04-28 22:01:42 +02001617 bool realSelector = mlir::isa<mlir::FloatType>(selectorType);
V Donaldson2c143342023-02-27 14:05:53 -08001618 assert((inArithmeticIfContext || !realSelector) && "invalid selector type");
1619 mlir::Value zero;
1620 if (inArithmeticIfContext)
1621 zero =
1622 realSelector
1623 ? builder->create<mlir::arith::ConstantOp>(
1624 loc, selectorType, builder->getFloatAttr(selectorType, 0.0))
1625 : builder->createIntegerConstant(loc, selectorType, 0);
1626 for (auto label : llvm::enumerate(labelList)) {
1627 mlir::Value cond;
1628 if (realSelector) // inArithmeticIfContext
1629 cond = builder->create<mlir::arith::CmpFOp>(
1630 loc,
1631 label.index() == 0 ? mlir::arith::CmpFPredicate::OLT
1632 : mlir::arith::CmpFPredicate::OGT,
1633 selector, zero);
V Donaldson5e521582023-03-31 09:36:16 -07001634 else if (inArithmeticIfContext) // INTEGER selector
V Donaldson2c143342023-02-27 14:05:53 -08001635 cond = builder->create<mlir::arith::CmpIOp>(
1636 loc,
1637 label.index() == 0 ? mlir::arith::CmpIPredicate::slt
1638 : mlir::arith::CmpIPredicate::sgt,
1639 selector, zero);
V Donaldson5e521582023-03-31 09:36:16 -07001640 else // A value of 0 is an IO ERR branch: invert comparison.
V Donaldson2c143342023-02-27 14:05:53 -08001641 cond = builder->create<mlir::arith::CmpIOp>(
1642 loc,
V Donaldson5e521582023-03-31 09:36:16 -07001643 valueList[label.index()] == 0 ? mlir::arith::CmpIPredicate::ne
1644 : mlir::arith::CmpIPredicate::eq,
V Donaldson2c143342023-02-27 14:05:53 -08001645 selector,
1646 builder->createIntegerConstant(loc, selectorType,
1647 valueList[label.index()]));
1648 // Branch to a new block with exit code and then to the target, or branch
V Donaldsonfd922e62023-04-05 11:13:36 -07001649 // directly to the target. defaultBlock is the "else" target.
V Donaldson2c143342023-02-27 14:05:53 -08001650 bool lastBranch = label.index() == branchCount - 1;
1651 mlir::Block *nextBlock =
1652 lastBranch && !defaultHasExitCode
V Donaldsonfd922e62023-04-05 11:13:36 -07001653 ? defaultBlock
V Donaldson2c143342023-02-27 14:05:53 -08001654 : builder->getBlock()->splitBlock(builder->getInsertionPoint());
V Donaldson5e521582023-03-31 09:36:16 -07001655 const Fortran::lower::pft::Evaluation &targetEval =
1656 label.value() ? evalOfLabel(label.value()) : defaultEval;
1657 if (hasExitCode(targetEval)) {
V Donaldson2c143342023-02-27 14:05:53 -08001658 mlir::Block *jumpBlock =
1659 builder->getBlock()->splitBlock(builder->getInsertionPoint());
1660 genConditionalBranch(cond, jumpBlock, nextBlock);
1661 startBlock(jumpBlock);
V Donaldson5e521582023-03-31 09:36:16 -07001662 genConstructExitBranch(targetEval);
V Donaldson2c143342023-02-27 14:05:53 -08001663 } else {
V Donaldson5e521582023-03-31 09:36:16 -07001664 genConditionalBranch(cond, targetEval.block, nextBlock);
V Donaldson2c143342023-02-27 14:05:53 -08001665 }
1666 if (!lastBranch) {
1667 startBlock(nextBlock);
1668 } else if (defaultHasExitCode) {
1669 startBlock(nextBlock);
1670 genConstructExitBranch(defaultEval);
1671 }
1672 }
1673 }
1674
1675 void pushActiveConstruct(Fortran::lower::pft::Evaluation &eval,
1676 Fortran::lower::StatementContext &stmtCtx) {
1677 activeConstructStack.push_back(ConstructContext{eval, stmtCtx});
1678 eval.activeConstruct = true;
1679 }
1680 void popActiveConstruct() {
1681 assert(!activeConstructStack.empty() && "invalid active construct stack");
1682 activeConstructStack.back().eval.activeConstruct = false;
jeanPerierd1aa9ba2024-06-03 17:20:07 +02001683 if (activeConstructStack.back().pushedScope)
1684 localSymbols.popScope();
V Donaldson2c143342023-02-27 14:05:53 -08001685 activeConstructStack.pop_back();
Valentin Clement764f95a2022-03-07 19:55:48 +01001686 }
1687
Valentin Clemente1a12762022-01-28 22:39:44 +01001688 //===--------------------------------------------------------------------===//
1689 // Termination of symbolically referenced execution units
1690 //===--------------------------------------------------------------------===//
1691
khaki3ff7fca72024-11-15 08:44:42 -08001692 /// Exit of a routine
Valentin Clemente1a12762022-01-28 22:39:44 +01001693 ///
khaki3ff7fca72024-11-15 08:44:42 -08001694 /// Generate the cleanup block before the routine exits
1695 void genExitRoutine(bool earlyReturn, mlir::ValueRange retval = {}) {
1696 if (blockIsUnterminated()) {
1697 bridge.openAccCtx().finalizeAndKeep();
1698 bridge.fctCtx().finalizeAndKeep();
1699 builder->create<mlir::func::ReturnOp>(toLocation(), retval);
1700 }
1701 if (!earlyReturn) {
1702 bridge.openAccCtx().pop();
1703 bridge.fctCtx().pop();
1704 }
Valentin Clemente1a12762022-01-28 22:39:44 +01001705 }
Valentin Clemente1a12762022-01-28 22:39:44 +01001706
Valentin Clementad40cc12022-02-14 21:31:46 +01001707 /// END of procedure-like constructs
1708 ///
1709 /// Generate the cleanup block before the procedure exits
1710 void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) {
1711 const Fortran::semantics::Symbol &resultSym =
1712 functionSymbol.get<Fortran::semantics::SubprogramDetails>().result();
1713 Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym);
1714 mlir::Location loc = toLocation();
1715 if (!resultSymBox) {
Valentin Clement39377d52022-07-01 08:29:19 +02001716 mlir::emitError(loc, "internal error when processing function return");
Valentin Clementad40cc12022-02-14 21:31:46 +01001717 return;
1718 }
1719 mlir::Value resultVal = resultSymBox.match(
1720 [&](const fir::CharBoxValue &x) -> mlir::Value {
Valentin Clementde3efd12022-09-24 08:58:50 +02001721 if (Fortran::semantics::IsBindCProcedure(functionSymbol))
1722 return builder->create<fir::LoadOp>(loc, x.getBuffer());
Valentin Clement37e84d92022-02-25 18:21:44 +01001723 return fir::factory::CharacterExprHelper{*builder, loc}
1724 .createEmboxChar(x.getBuffer(), x.getLen());
Valentin Clementad40cc12022-02-14 21:31:46 +01001725 },
Slava Zakharinde8939f2023-09-05 10:26:16 -07001726 [&](const fir::MutableBoxValue &x) -> mlir::Value {
1727 mlir::Value resultRef = resultSymBox.getAddr();
1728 mlir::Value load = builder->create<fir::LoadOp>(loc, resultRef);
1729 unsigned rank = x.rank();
1730 if (x.isAllocatable() && rank > 0) {
1731 // ALLOCATABLE array result must have default lower bounds.
1732 // At the call site the result box of a function reference
1733 // might be considered having default lower bounds, but
1734 // the runtime box should probably comply with this assumption
1735 // as well. If the result box has proper lbounds in runtime,
1736 // this may improve the debugging experience of Fortran apps.
1737 // We may consider removing this, if the overhead of setting
1738 // default lower bounds is too big.
1739 mlir::Value one =
1740 builder->createIntegerConstant(loc, builder->getIndexType(), 1);
1741 llvm::SmallVector<mlir::Value> lbounds{rank, one};
1742 auto shiftTy = fir::ShiftType::get(builder->getContext(), rank);
1743 mlir::Value shiftOp =
1744 builder->create<fir::ShiftOp>(loc, shiftTy, lbounds);
1745 load = builder->create<fir::ReboxOp>(
1746 loc, load.getType(), load, shiftOp, /*slice=*/mlir::Value{});
1747 }
1748 return load;
1749 },
Valentin Clementad40cc12022-02-14 21:31:46 +01001750 [&](const auto &) -> mlir::Value {
1751 mlir::Value resultRef = resultSymBox.getAddr();
1752 mlir::Type resultType = genType(resultSym);
1753 mlir::Type resultRefType = builder->getRefType(resultType);
1754 // A function with multiple entry points returning different types
1755 // tags all result variables with one of the largest types to allow
V Donaldson2c143342023-02-27 14:05:53 -08001756 // them to share the same storage. Convert this to the actual type.
Valentin Clementad40cc12022-02-14 21:31:46 +01001757 if (resultRef.getType() != resultRefType)
Valentin Clement76134f42022-03-15 22:01:34 +01001758 resultRef = builder->createConvert(loc, resultRefType, resultRef);
Valentin Clementad40cc12022-02-14 21:31:46 +01001759 return builder->create<fir::LoadOp>(loc, resultRef);
1760 });
khaki3ff7fca72024-11-15 08:44:42 -08001761 genExitRoutine(false, resultVal);
Valentin Clementad40cc12022-02-14 21:31:46 +01001762 }
1763
Valentin Clement76134f42022-03-15 22:01:34 +01001764 /// Get the return value of a call to \p symbol, which is a subroutine entry
1765 /// point that has alternative return specifiers.
1766 const mlir::Value
1767 getAltReturnResult(const Fortran::semantics::Symbol &symbol) {
1768 assert(Fortran::semantics::HasAlternateReturns(symbol) &&
1769 "subroutine does not have alternate returns");
1770 return getSymbolAddress(symbol);
1771 }
1772
Valentin Clement89275302022-02-01 15:26:47 +01001773 void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit,
1774 const Fortran::semantics::Symbol &symbol) {
Valentin Clement85b89ed2022-02-10 18:35:16 +01001775 if (mlir::Block *finalBlock = funit.finalBlock) {
1776 // The current block must end with a terminator.
1777 if (blockIsUnterminated())
1778 builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock);
1779 // Set insertion point to final block.
1780 builder->setInsertionPoint(finalBlock, finalBlock->end());
1781 }
Valentin Clement89275302022-02-01 15:26:47 +01001782 if (Fortran::semantics::IsFunction(symbol)) {
Valentin Clementad40cc12022-02-14 21:31:46 +01001783 genReturnSymbol(symbol);
Valentin Clement76134f42022-03-15 22:01:34 +01001784 } else if (Fortran::semantics::HasAlternateReturns(symbol)) {
1785 mlir::Value retval = builder->create<fir::LoadOp>(
1786 toLocation(), getAltReturnResult(symbol));
khaki3ff7fca72024-11-15 08:44:42 -08001787 genExitRoutine(false, retval);
Valentin Clement89275302022-02-01 15:26:47 +01001788 } else {
khaki3ff7fca72024-11-15 08:44:42 -08001789 genExitRoutine(false);
Valentin Clement89275302022-02-01 15:26:47 +01001790 }
1791 }
1792
Valentin Clement764f95a2022-03-07 19:55:48 +01001793 //
1794 // Statements that have control-flow semantics
1795 //
1796
1797 /// Generate an If[Then]Stmt condition or its negation.
1798 template <typename A>
1799 mlir::Value genIfCondition(const A *stmt, bool negate = false) {
1800 mlir::Location loc = toLocation();
1801 Fortran::lower::StatementContext stmtCtx;
1802 mlir::Value condExpr = createFIRExpr(
1803 loc,
1804 Fortran::semantics::GetExpr(
1805 std::get<Fortran::parser::ScalarLogicalExpr>(stmt->t)),
1806 stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08001807 stmtCtx.finalizeAndReset();
Valentin Clement764f95a2022-03-07 19:55:48 +01001808 mlir::Value cond =
1809 builder->createConvert(loc, builder->getI1Type(), condExpr);
1810 if (negate)
1811 cond = builder->create<mlir::arith::XOrIOp>(
1812 loc, cond, builder->createIntegerConstant(loc, cond.getType(), 1));
1813 return cond;
1814 }
1815
River Riddle58ceae92022-04-18 11:53:47 -07001816 mlir::func::FuncOp getFunc(llvm::StringRef name, mlir::FunctionType ty) {
1817 if (mlir::func::FuncOp func = builder->getNamedFunction(name)) {
Valentin Clementfe252f82022-03-22 15:40:32 +01001818 assert(func.getFunctionType() == ty);
1819 return func;
Valentin Clement88ae0d62022-03-10 19:43:11 +01001820 }
Valentin Clementfe252f82022-03-22 15:40:32 +01001821 return builder->createFunction(toLocation(), name, ty);
Valentin Clemente641c292022-02-17 18:23:22 +01001822 }
1823
Valentin Clementd0b70a02022-02-23 19:48:07 +01001824 /// Lowering of CALL statement
Valentin Clement99075912022-02-01 13:49:49 +01001825 void genFIR(const Fortran::parser::CallStmt &stmt) {
Valentin Clementd0b70a02022-02-23 19:48:07 +01001826 Fortran::lower::StatementContext stmtCtx;
Valentin Clement88ae0d62022-03-10 19:43:11 +01001827 Fortran::lower::pft::Evaluation &eval = getEval();
Peter Klausler4ad72792023-05-06 15:03:39 -07001828 setCurrentPosition(stmt.source);
Valentin Clementd0b70a02022-02-23 19:48:07 +01001829 assert(stmt.typedCall && "Call was not analyzed");
Jean Periere78e4a12022-12-01 11:09:35 +01001830 mlir::Value res{};
Jean Perier7531c872023-01-20 14:05:42 +01001831 if (lowerToHighLevelFIR()) {
Kazu Hirata91682b22023-01-14 14:06:18 -08001832 std::optional<mlir::Type> resultType;
Jean Periere78e4a12022-12-01 11:09:35 +01001833 if (stmt.typedCall->hasAlternateReturns())
1834 resultType = builder->getIndexType();
1835 auto hlfirRes = Fortran::lower::convertCallToHLFIR(
1836 toLocation(), *this, *stmt.typedCall, resultType, localSymbols,
1837 stmtCtx);
1838 if (hlfirRes)
1839 res = *hlfirRes;
1840 } else {
1841 // Call statement lowering shares code with function call lowering.
1842 res = Fortran::lower::createSubroutineCall(
1843 *this, *stmt.typedCall, explicitIterSpace, implicitIterSpace,
1844 localSymbols, stmtCtx, /*isUserDefAssignment=*/false);
1845 }
V Donaldson2c143342023-02-27 14:05:53 -08001846 stmtCtx.finalizeAndReset();
Valentin Clementd0b70a02022-02-23 19:48:07 +01001847 if (!res)
1848 return; // "Normal" subroutine call.
Valentin Clement88ae0d62022-03-10 19:43:11 +01001849 // Call with alternate return specifiers.
1850 // The call returns an index that selects an alternate return branch target.
1851 llvm::SmallVector<int64_t> indexList;
V Donaldson2c143342023-02-27 14:05:53 -08001852 llvm::SmallVector<Fortran::parser::Label> labelList;
Valentin Clement88ae0d62022-03-10 19:43:11 +01001853 int64_t index = 0;
1854 for (const Fortran::parser::ActualArgSpec &arg :
Peter Klausler4ad72792023-05-06 15:03:39 -07001855 std::get<std::list<Fortran::parser::ActualArgSpec>>(stmt.call.t)) {
Valentin Clement88ae0d62022-03-10 19:43:11 +01001856 const auto &actual = std::get<Fortran::parser::ActualArg>(arg.t);
1857 if (const auto *altReturn =
1858 std::get_if<Fortran::parser::AltReturnSpec>(&actual.u)) {
1859 indexList.push_back(++index);
V Donaldson2c143342023-02-27 14:05:53 -08001860 labelList.push_back(altReturn->v);
Valentin Clement88ae0d62022-03-10 19:43:11 +01001861 }
1862 }
V Donaldson2c143342023-02-27 14:05:53 -08001863 genMultiwayBranch(res, indexList, labelList, eval.nonNopSuccessor());
Valentin Clement99075912022-02-01 13:49:49 +01001864 }
1865
1866 void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) {
Valentin Clement78a127a2022-03-08 20:17:48 +01001867 Fortran::lower::StatementContext stmtCtx;
1868 Fortran::lower::pft::Evaluation &eval = getEval();
1869 mlir::Value selectExpr =
1870 createFIRExpr(toLocation(),
1871 Fortran::semantics::GetExpr(
1872 std::get<Fortran::parser::ScalarIntExpr>(stmt.t)),
1873 stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08001874 stmtCtx.finalizeAndReset();
Valentin Clement78a127a2022-03-08 20:17:48 +01001875 llvm::SmallVector<int64_t> indexList;
V Donaldson2c143342023-02-27 14:05:53 -08001876 llvm::SmallVector<Fortran::parser::Label> labelList;
Valentin Clement78a127a2022-03-08 20:17:48 +01001877 int64_t index = 0;
1878 for (Fortran::parser::Label label :
1879 std::get<std::list<Fortran::parser::Label>>(stmt.t)) {
1880 indexList.push_back(++index);
V Donaldson2c143342023-02-27 14:05:53 -08001881 labelList.push_back(label);
Valentin Clement78a127a2022-03-08 20:17:48 +01001882 }
V Donaldson2c143342023-02-27 14:05:53 -08001883 genMultiwayBranch(selectExpr, indexList, labelList, eval.nonNopSuccessor());
Valentin Clement99075912022-02-01 13:49:49 +01001884 }
1885
1886 void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) {
Valentin Clement78a127a2022-03-08 20:17:48 +01001887 Fortran::lower::StatementContext stmtCtx;
Valentin Clement78a127a2022-03-08 20:17:48 +01001888 mlir::Value expr = createFIRExpr(
1889 toLocation(),
1890 Fortran::semantics::GetExpr(std::get<Fortran::parser::Expr>(stmt.t)),
1891 stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08001892 stmtCtx.finalizeAndReset();
1893 // Raise an exception if REAL expr is a NaN.
Christian Siggfac349a2024-04-28 22:01:42 +02001894 if (mlir::isa<mlir::FloatType>(expr.getType()))
V Donaldson2c143342023-02-27 14:05:53 -08001895 expr = builder->create<mlir::arith::AddFOp>(toLocation(), expr, expr);
V Donaldson5e521582023-03-31 09:36:16 -07001896 // An empty valueList indicates to genMultiwayBranch that the branch is
1897 // an ArithmeticIfStmt that has two branches on value 0 or 0.0.
V Donaldson2c143342023-02-27 14:05:53 -08001898 llvm::SmallVector<int64_t> valueList;
1899 llvm::SmallVector<Fortran::parser::Label> labelList;
1900 labelList.push_back(std::get<1>(stmt.t));
1901 labelList.push_back(std::get<3>(stmt.t));
1902 const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap =
1903 getEval().getOwningProcedure()->labelEvaluationMap;
1904 const auto iter = labelEvaluationMap.find(std::get<2>(stmt.t));
1905 assert(iter != labelEvaluationMap.end() && "label missing from map");
1906 genMultiwayBranch(expr, valueList, labelList, *iter->second);
Valentin Clement99075912022-02-01 13:49:49 +01001907 }
1908
1909 void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) {
V Donaldsonfd922e62023-04-05 11:13:36 -07001910 // See Fortran 90 Clause 8.2.4.
1911 // Relax the requirement that the GOTO variable must have a value in the
1912 // label list when a list is present, and allow a branch to any non-format
1913 // target that has an ASSIGN statement for the variable.
Valentin Clement78a127a2022-03-08 20:17:48 +01001914 mlir::Location loc = toLocation();
1915 Fortran::lower::pft::Evaluation &eval = getEval();
V Donaldsonfd922e62023-04-05 11:13:36 -07001916 Fortran::lower::pft::FunctionLikeUnit &owningProc =
1917 *eval.getOwningProcedure();
Valentin Clement78a127a2022-03-08 20:17:48 +01001918 const Fortran::lower::pft::SymbolLabelMap &symbolLabelMap =
V Donaldsonfd922e62023-04-05 11:13:36 -07001919 owningProc.assignSymbolLabelMap;
1920 const Fortran::lower::pft::LabelEvalMap &labelEvalMap =
1921 owningProc.labelEvaluationMap;
Valentin Clement78a127a2022-03-08 20:17:48 +01001922 const Fortran::semantics::Symbol &symbol =
1923 *std::get<Fortran::parser::Name>(stmt.t).symbol;
V Donaldsonfd922e62023-04-05 11:13:36 -07001924 auto labelSetIter = symbolLabelMap.find(symbol);
V Donaldson2c143342023-02-27 14:05:53 -08001925 llvm::SmallVector<int64_t> valueList;
1926 llvm::SmallVector<Fortran::parser::Label> labelList;
V Donaldsonfd922e62023-04-05 11:13:36 -07001927 if (labelSetIter != symbolLabelMap.end()) {
1928 for (auto &label : labelSetIter->second) {
1929 const auto evalIter = labelEvalMap.find(label);
1930 assert(evalIter != labelEvalMap.end() && "assigned goto label missing");
1931 if (evalIter->second->block) { // non-format statement
1932 valueList.push_back(label); // label as an integer
1933 labelList.push_back(label);
1934 }
Valentin Clement78a127a2022-03-08 20:17:48 +01001935 }
1936 }
V Donaldsonfd922e62023-04-05 11:13:36 -07001937 if (!labelList.empty()) {
1938 auto selectExpr =
1939 builder->create<fir::LoadOp>(loc, getSymbolAddress(symbol));
1940 // Add a default error target in case the goto is nonconforming.
1941 mlir::Block *errorBlock =
1942 builder->getBlock()->splitBlock(builder->getInsertionPoint());
1943 genMultiwayBranch(selectExpr, valueList, labelList,
1944 eval.nonNopSuccessor(), errorBlock);
1945 startBlock(errorBlock);
1946 }
1947 fir::runtime::genReportFatalUserError(
1948 *builder, loc,
1949 "Assigned GOTO variable '" + symbol.name().ToString() +
1950 "' does not have a valid target label value");
1951 builder->create<fir::UnreachableOp>(loc);
Valentin Clement99075912022-02-01 13:49:49 +01001952 }
1953
khaki3f11e08f2024-06-10 08:41:05 -07001954 fir::ReduceOperationEnum
1955 getReduceOperationEnum(const Fortran::parser::ReductionOperator &rOpr) {
1956 switch (rOpr.v) {
1957 case Fortran::parser::ReductionOperator::Operator::Plus:
1958 return fir::ReduceOperationEnum::Add;
1959 case Fortran::parser::ReductionOperator::Operator::Multiply:
1960 return fir::ReduceOperationEnum::Multiply;
1961 case Fortran::parser::ReductionOperator::Operator::And:
1962 return fir::ReduceOperationEnum::AND;
1963 case Fortran::parser::ReductionOperator::Operator::Or:
1964 return fir::ReduceOperationEnum::OR;
1965 case Fortran::parser::ReductionOperator::Operator::Eqv:
1966 return fir::ReduceOperationEnum::EQV;
1967 case Fortran::parser::ReductionOperator::Operator::Neqv:
1968 return fir::ReduceOperationEnum::NEQV;
1969 case Fortran::parser::ReductionOperator::Operator::Max:
1970 return fir::ReduceOperationEnum::MAX;
1971 case Fortran::parser::ReductionOperator::Operator::Min:
1972 return fir::ReduceOperationEnum::MIN;
1973 case Fortran::parser::ReductionOperator::Operator::Iand:
1974 return fir::ReduceOperationEnum::IAND;
1975 case Fortran::parser::ReductionOperator::Operator::Ior:
1976 return fir::ReduceOperationEnum::IOR;
1977 case Fortran::parser::ReductionOperator::Operator::Ieor:
1978 return fir::ReduceOperationEnum::EIOR;
1979 }
1980 llvm_unreachable("illegal reduction operator");
1981 }
1982
Kareem Ergawy30990c02025-04-16 14:20:27 +02001983 /// Collect DO CONCURRENT or FORALL loop control information.
Mats Petersson84b9ae62022-06-07 14:00:08 +01001984 IncrementLoopNestInfo getConcurrentControl(
1985 const Fortran::parser::ConcurrentHeader &header,
1986 const std::list<Fortran::parser::LocalitySpec> &localityList = {}) {
1987 IncrementLoopNestInfo incrementLoopNestInfo;
1988 for (const Fortran::parser::ConcurrentControl &control :
1989 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t))
1990 incrementLoopNestInfo.emplace_back(
1991 *std::get<0>(control.t).symbol, std::get<1>(control.t),
1992 std::get<2>(control.t), std::get<3>(control.t), /*isUnordered=*/true);
1993 IncrementLoopInfo &info = incrementLoopNestInfo.back();
1994 info.maskExpr = Fortran::semantics::GetExpr(
1995 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(header.t));
1996 for (const Fortran::parser::LocalitySpec &x : localityList) {
V Donaldson335b3992023-08-07 13:29:17 -07001997 if (const auto *localList =
1998 std::get_if<Fortran::parser::LocalitySpec::Local>(&x.u))
1999 for (const Fortran::parser::Name &x : localList->v)
2000 info.localSymList.push_back(x.symbol);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002001 if (const auto *localInitList =
2002 std::get_if<Fortran::parser::LocalitySpec::LocalInit>(&x.u))
2003 for (const Fortran::parser::Name &x : localInitList->v)
2004 info.localInitSymList.push_back(x.symbol);
khaki385f45932024-06-17 09:21:30 -07002005 for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2006 if (const auto *reduceList =
2007 std::get_if<Fortran::parser::LocalitySpec::Reduce>(&x.u)) {
2008 fir::ReduceOperationEnum reduce_operation = getReduceOperationEnum(
2009 std::get<Fortran::parser::ReductionOperator>(reduceList->t));
2010 for (const Fortran::parser::Name &x :
2011 std::get<std::list<Fortran::parser::Name>>(reduceList->t)) {
2012 info.reduceSymList.push_back(
2013 std::make_pair(reduce_operation, x.symbol));
2014 }
khaki3f11e08f2024-06-10 08:41:05 -07002015 }
2016 }
Mats Petersson84b9ae62022-06-07 14:00:08 +01002017 if (const auto *sharedList =
2018 std::get_if<Fortran::parser::LocalitySpec::Shared>(&x.u))
2019 for (const Fortran::parser::Name &x : sharedList->v)
2020 info.sharedSymList.push_back(x.symbol);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002021 }
2022 return incrementLoopNestInfo;
2023 }
2024
V Donaldson335b3992023-08-07 13:29:17 -07002025 /// Create DO CONCURRENT construct symbol bindings and generate LOCAL_INIT
2026 /// assignments.
2027 void handleLocalitySpecs(const IncrementLoopInfo &info) {
2028 Fortran::semantics::SemanticsContext &semanticsContext =
2029 bridge.getSemanticsContext();
2030 for (const Fortran::semantics::Symbol *sym : info.localSymList)
jeanPerierff78cd52024-12-05 14:09:48 +01002031 createHostAssociateVarClone(*sym, /*skipDefaultInit=*/false);
V Donaldson335b3992023-08-07 13:29:17 -07002032 for (const Fortran::semantics::Symbol *sym : info.localInitSymList) {
jeanPerierff78cd52024-12-05 14:09:48 +01002033 createHostAssociateVarClone(*sym, /*skipDefaultInit=*/true);
V Donaldson335b3992023-08-07 13:29:17 -07002034 const auto *hostDetails =
2035 sym->detailsIf<Fortran::semantics::HostAssocDetails>();
2036 assert(hostDetails && "missing locality spec host symbol");
2037 const Fortran::semantics::Symbol *hostSym = &hostDetails->symbol();
2038 Fortran::evaluate::ExpressionAnalyzer ea{semanticsContext};
2039 Fortran::evaluate::Assignment assign{
2040 ea.Designate(Fortran::evaluate::DataRef{*sym}).value(),
2041 ea.Designate(Fortran::evaluate::DataRef{*hostSym}).value()};
2042 if (Fortran::semantics::IsPointer(*sym))
2043 assign.u = Fortran::evaluate::Assignment::BoundsSpec{};
2044 genAssignment(assign);
2045 }
2046 for (const Fortran::semantics::Symbol *sym : info.sharedSymList) {
2047 const auto *hostDetails =
2048 sym->detailsIf<Fortran::semantics::HostAssocDetails>();
2049 copySymbolBinding(hostDetails->symbol(), *sym);
2050 }
jeanPerierff78cd52024-12-05 14:09:48 +01002051 // Note that allocatable, types with ultimate components, and type
2052 // requiring finalization are forbidden in LOCAL/LOCAL_INIT (F2023 C1130),
2053 // so no clean-up needs to be generated for these entities.
V Donaldson335b3992023-08-07 13:29:17 -07002054 }
2055
V Donaldson2c143342023-02-27 14:05:53 -08002056 /// Generate FIR for a DO construct. There are six variants:
Valentin Clementfe252f82022-03-22 15:40:32 +01002057 /// - unstructured infinite and while loops
2058 /// - structured and unstructured increment loops
2059 /// - structured and unstructured concurrent loops
Valentin Clement99075912022-02-01 13:49:49 +01002060 void genFIR(const Fortran::parser::DoConstruct &doConstruct) {
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002061 setCurrentPositionAt(doConstruct);
2062 // Collect loop nest information.
2063 // Generate begin loop code directly for infinite and while loops.
2064 Fortran::lower::pft::Evaluation &eval = getEval();
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002065 bool unstructuredContext = eval.lowerAsUnstructured();
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002066 Fortran::lower::pft::Evaluation &doStmtEval =
2067 eval.getFirstNestedEvaluation();
2068 auto *doStmt = doStmtEval.getIf<Fortran::parser::NonLabelDoStmt>();
2069 const auto &loopControl =
2070 std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002071 mlir::Block *preheaderBlock = doStmtEval.block;
2072 mlir::Block *beginBlock =
2073 preheaderBlock ? preheaderBlock : builder->getBlock();
2074 auto createNextBeginBlock = [&]() {
2075 // Step beginBlock through unstructured preheader, header, and mask
2076 // blocks, created in outermost to innermost order.
2077 return beginBlock = beginBlock->splitBlock(beginBlock->end());
2078 };
2079 mlir::Block *headerBlock =
2080 unstructuredContext ? createNextBeginBlock() : nullptr;
2081 mlir::Block *bodyBlock = doStmtEval.lexicalSuccessor->block;
2082 mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block;
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002083 IncrementLoopNestInfo incrementLoopNestInfo;
Diana Picus11fb1aa2022-05-25 12:51:10 +00002084 const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr;
Kiran Chandramohan8c349d72022-06-01 11:48:20 +00002085 bool infiniteLoop = !loopControl.has_value();
2086 if (infiniteLoop) {
2087 assert(unstructuredContext && "infinite loop must be unstructured");
2088 startBlock(headerBlock);
2089 } else if ((whileCondition =
2090 std::get_if<Fortran::parser::ScalarLogicalExpr>(
2091 &loopControl->u))) {
Diana Picus11fb1aa2022-05-25 12:51:10 +00002092 assert(unstructuredContext && "while loop must be unstructured");
2093 maybeStartBlock(preheaderBlock); // no block or empty block
2094 startBlock(headerBlock);
V Donaldson2c143342023-02-27 14:05:53 -08002095 genConditionalBranch(*whileCondition, bodyBlock, exitBlock);
Diana Picus11fb1aa2022-05-25 12:51:10 +00002096 } else if (const auto *bounds =
2097 std::get_if<Fortran::parser::LoopControl::Bounds>(
2098 &loopControl->u)) {
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002099 // Non-concurrent increment loop.
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002100 IncrementLoopInfo &info = incrementLoopNestInfo.emplace_back(
2101 *bounds->name.thing.symbol, bounds->lower, bounds->upper,
2102 bounds->step);
2103 if (unstructuredContext) {
2104 maybeStartBlock(preheaderBlock);
Krzysztof Parzyszekdd376f82023-12-04 08:27:57 -06002105 info.hasRealControl = info.loopVariableSym->GetType()->IsNumeric(
Diana Picusa1591282022-05-31 10:55:56 +00002106 Fortran::common::TypeCategory::Real);
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002107 info.headerBlock = headerBlock;
2108 info.bodyBlock = bodyBlock;
2109 info.exitBlock = exitBlock;
2110 }
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002111 } else {
Mats Petersson84b9ae62022-06-07 14:00:08 +01002112 const auto *concurrent =
2113 std::get_if<Fortran::parser::LoopControl::Concurrent>(
2114 &loopControl->u);
2115 assert(concurrent && "invalid DO loop variant");
2116 incrementLoopNestInfo = getConcurrentControl(
2117 std::get<Fortran::parser::ConcurrentHeader>(concurrent->t),
2118 std::get<std::list<Fortran::parser::LocalitySpec>>(concurrent->t));
2119 if (unstructuredContext) {
2120 maybeStartBlock(preheaderBlock);
2121 for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2122 // The original loop body provides the body and latch blocks of the
V Donaldson2c143342023-02-27 14:05:53 -08002123 // innermost dimension. The (first) body block of a non-innermost
Mats Petersson84b9ae62022-06-07 14:00:08 +01002124 // dimension is the preheader block of the immediately enclosed
V Donaldson2c143342023-02-27 14:05:53 -08002125 // dimension. The latch block of a non-innermost dimension is the
Mats Petersson84b9ae62022-06-07 14:00:08 +01002126 // exit block of the immediately enclosed dimension.
2127 auto createNextExitBlock = [&]() {
2128 // Create unstructured loop exit blocks, outermost to innermost.
2129 return exitBlock = insertBlock(exitBlock);
2130 };
2131 bool isInnermost = &info == &incrementLoopNestInfo.back();
2132 bool isOutermost = &info == &incrementLoopNestInfo.front();
2133 info.headerBlock = isOutermost ? headerBlock : createNextBeginBlock();
2134 info.bodyBlock = isInnermost ? bodyBlock : createNextBeginBlock();
2135 info.exitBlock = isOutermost ? exitBlock : createNextExitBlock();
2136 if (info.maskExpr)
2137 info.maskBlock = createNextBeginBlock();
2138 }
2139 }
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002140 }
2141
V Donaldson2c143342023-02-27 14:05:53 -08002142 // Increment loop begin code. (Infinite/while code was already generated.)
Kiran Chandramohan8c349d72022-06-01 11:48:20 +00002143 if (!infiniteLoop && !whileCondition)
David Trubyc6b6e182024-06-14 14:10:41 +01002144 genFIRIncrementLoopBegin(incrementLoopNestInfo, doStmtEval.dirs);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002145
V Donaldson609b7892023-01-03 10:31:30 -08002146 // Loop body code.
2147 auto iter = eval.getNestedEvaluations().begin();
2148 for (auto end = --eval.getNestedEvaluations().end(); iter != end; ++iter)
2149 genFIR(*iter, unstructuredContext);
2150
2151 // An EndDoStmt in unstructured code may start a new block.
2152 Fortran::lower::pft::Evaluation &endDoEval = *iter;
2153 assert(endDoEval.getIf<Fortran::parser::EndDoStmt>() && "no enddo stmt");
2154 if (unstructuredContext)
2155 maybeStartBlock(endDoEval.block);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002156
Kiran Chandramohan8c349d72022-06-01 11:48:20 +00002157 // Loop end code.
2158 if (infiniteLoop || whileCondition)
V Donaldson2c143342023-02-27 14:05:53 -08002159 genBranch(headerBlock);
Diana Picus11fb1aa2022-05-25 12:51:10 +00002160 else
2161 genFIRIncrementLoopEnd(incrementLoopNestInfo);
V Donaldson609b7892023-01-03 10:31:30 -08002162
2163 // This call may generate a branch in some contexts.
2164 genFIR(endDoEval, unstructuredContext);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002165 }
2166
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002167 /// Generate FIR to evaluate loop control values (lower, upper and step).
2168 mlir::Value genControlValue(const Fortran::lower::SomeExpr *expr,
2169 const IncrementLoopInfo &info,
2170 bool *isConst = nullptr) {
2171 mlir::Location loc = toLocation();
2172 mlir::Type controlType = info.isStructured() ? builder->getIndexType()
2173 : info.getLoopVariableType();
2174 Fortran::lower::StatementContext stmtCtx;
2175 if (expr) {
2176 if (isConst)
2177 *isConst = Fortran::evaluate::IsConstantExpr(*expr);
2178 return builder->createConvert(loc, controlType,
2179 createFIRExpr(loc, expr, stmtCtx));
2180 }
2181
2182 if (isConst)
2183 *isConst = true;
2184 if (info.hasRealControl)
2185 return builder->createRealConstant(loc, controlType, 1u);
2186 return builder->createIntegerConstant(loc, controlType, 1); // step
2187 }
2188
Asher Mancinelli6b52fb22025-02-10 08:21:22 -08002189 // For unroll directives without a value, force full unrolling.
2190 // For unroll directives with a value, if the value is greater than 1,
2191 // force unrolling with the given factor. Otherwise, disable unrolling.
2192 mlir::LLVM::LoopUnrollAttr
2193 genLoopUnrollAttr(std::optional<std::uint64_t> directiveArg) {
2194 mlir::BoolAttr falseAttr =
2195 mlir::BoolAttr::get(builder->getContext(), false);
2196 mlir::BoolAttr trueAttr = mlir::BoolAttr::get(builder->getContext(), true);
2197 mlir::IntegerAttr countAttr;
2198 mlir::BoolAttr fullUnrollAttr;
2199 bool shouldUnroll = true;
2200 if (directiveArg.has_value()) {
2201 auto unrollingFactor = directiveArg.value();
2202 if (unrollingFactor == 0 || unrollingFactor == 1) {
2203 shouldUnroll = false;
2204 } else {
2205 countAttr =
2206 builder->getIntegerAttr(builder->getI64Type(), unrollingFactor);
2207 }
2208 } else {
2209 fullUnrollAttr = trueAttr;
2210 }
2211
2212 mlir::BoolAttr disableAttr = shouldUnroll ? falseAttr : trueAttr;
2213 return mlir::LLVM::LoopUnrollAttr::get(
2214 builder->getContext(), /*disable=*/disableAttr, /*count=*/countAttr, {},
2215 /*full=*/fullUnrollAttr, {}, {}, {});
2216 }
2217
Jean-Didier PAILLEUXd6c6bde2025-02-19 16:00:09 +01002218 // Enabling unroll and jamming directive without a value.
2219 // For directives with a value, if the value is greater than 1,
2220 // force unrolling with the given factor. Otherwise, disable unrolling and
2221 // jamming.
2222 mlir::LLVM::LoopUnrollAndJamAttr
2223 genLoopUnrollAndJamAttr(std::optional<std::uint64_t> count) {
2224 mlir::BoolAttr falseAttr =
2225 mlir::BoolAttr::get(builder->getContext(), false);
2226 mlir::BoolAttr trueAttr = mlir::BoolAttr::get(builder->getContext(), true);
2227 mlir::IntegerAttr countAttr;
2228 bool shouldUnroll = true;
2229 if (count.has_value()) {
2230 auto unrollingFactor = count.value();
2231 if (unrollingFactor == 0 || unrollingFactor == 1) {
2232 shouldUnroll = false;
2233 } else {
2234 countAttr =
2235 builder->getIntegerAttr(builder->getI64Type(), unrollingFactor);
2236 }
2237 }
2238
2239 mlir::BoolAttr disableAttr = shouldUnroll ? falseAttr : trueAttr;
2240 return mlir::LLVM::LoopUnrollAndJamAttr::get(
2241 builder->getContext(), /*disable=*/disableAttr, /*count*/ countAttr, {},
2242 {}, {}, {}, {});
2243 }
2244
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002245 void addLoopAnnotationAttr(
2246 IncrementLoopInfo &info,
2247 llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002248 mlir::LLVM::LoopVectorizeAttr va;
2249 mlir::LLVM::LoopUnrollAttr ua;
Jean-Didier PAILLEUXd6c6bde2025-02-19 16:00:09 +01002250 mlir::LLVM::LoopUnrollAndJamAttr uja;
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002251 bool has_attrs = false;
2252 for (const auto *dir : dirs) {
2253 Fortran::common::visit(
2254 Fortran::common::visitors{
2255 [&](const Fortran::parser::CompilerDirective::VectorAlways &) {
Asher Mancinelli6b52fb22025-02-10 08:21:22 -08002256 mlir::BoolAttr falseAttr =
2257 mlir::BoolAttr::get(builder->getContext(), false);
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002258 va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
Asher Mancinelli6b52fb22025-02-10 08:21:22 -08002259 /*disable=*/falseAttr,
2260 {}, {}, {}, {}, {}, {});
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002261 has_attrs = true;
2262 },
2263 [&](const Fortran::parser::CompilerDirective::Unroll &u) {
Asher Mancinelli6b52fb22025-02-10 08:21:22 -08002264 ua = genLoopUnrollAttr(u.v);
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002265 has_attrs = true;
2266 },
Jean-Didier PAILLEUXd6c6bde2025-02-19 16:00:09 +01002267 [&](const Fortran::parser::CompilerDirective::UnrollAndJam &u) {
2268 uja = genLoopUnrollAndJamAttr(u.v);
2269 has_attrs = true;
2270 },
Jean-Didier PAILLEUXc309abd2025-04-02 14:30:01 +02002271 [&](const Fortran::parser::CompilerDirective::NoVector &u) {
2272 mlir::BoolAttr trueAttr =
2273 mlir::BoolAttr::get(builder->getContext(), true);
2274 va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
2275 /*disable=*/trueAttr,
2276 {}, {}, {}, {}, {}, {});
2277 has_attrs = true;
2278 },
2279 [&](const Fortran::parser::CompilerDirective::NoUnroll &u) {
2280 ua = genLoopUnrollAttr(/*unrollingFactor=*/0);
2281 has_attrs = true;
2282 },
2283 [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &u) {
2284 uja = genLoopUnrollAndJamAttr(/*unrollingFactor=*/0);
2285 has_attrs = true;
2286 },
2287
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002288 [&](const auto &) {}},
2289 dir->u);
2290 }
David Trubyc6b6e182024-06-14 14:10:41 +01002291 mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get(
Jean-Didier PAILLEUXd6c6bde2025-02-19 16:00:09 +01002292 builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua,
2293 /*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
Kareem Ergawy30990c02025-04-16 14:20:27 +02002294 if (has_attrs)
2295 info.doLoop.setLoopAnnotationAttr(la);
David Trubyc6b6e182024-06-14 14:10:41 +01002296 }
2297
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002298 /// Generate FIR to begin a structured or unstructured increment loop nest.
David Trubyc6b6e182024-06-14 14:10:41 +01002299 void genFIRIncrementLoopBegin(
2300 IncrementLoopNestInfo &incrementLoopNestInfo,
2301 llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002302 assert(!incrementLoopNestInfo.empty() && "empty loop nest");
2303 mlir::Location loc = toLocation();
Kareem Ergawy30990c02025-04-16 14:20:27 +02002304 mlir::Operation *boundsAndStepIP = nullptr;
Yusuke MINATOe573c6b2024-11-28 08:58:09 +09002305 mlir::arith::IntegerOverflowFlags iofBackup{};
Kareem Ergawy06984822024-10-31 09:19:18 +01002306
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002307 for (IncrementLoopInfo &info : incrementLoopNestInfo) {
Kareem Ergawy30990c02025-04-16 14:20:27 +02002308 mlir::Value lowerValue;
2309 mlir::Value upperValue;
2310 mlir::Value stepValue;
Kareem Ergawy06984822024-10-31 09:19:18 +01002311
Kareem Ergawy30990c02025-04-16 14:20:27 +02002312 {
2313 mlir::OpBuilder::InsertionGuard guard(*builder);
2314
2315 // Set the IP before the first loop in the nest so that all nest bounds
2316 // and step values are created outside the nest.
2317 if (boundsAndStepIP)
2318 builder->setInsertionPointAfter(boundsAndStepIP);
2319
Kareem Ergawy06984822024-10-31 09:19:18 +01002320 info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym,
Kareem Ergawy30990c02025-04-16 14:20:27 +02002321 info.isUnordered);
2322 if (!getLoweringOptions().getIntegerWrapAround()) {
2323 iofBackup = builder->getIntegerOverflowFlags();
2324 builder->setIntegerOverflowFlags(
2325 mlir::arith::IntegerOverflowFlags::nsw);
2326 }
2327 lowerValue = genControlValue(info.lowerExpr, info);
2328 upperValue = genControlValue(info.upperExpr, info);
2329 bool isConst = true;
2330 stepValue = genControlValue(info.stepExpr, info,
2331 info.isStructured() ? nullptr : &isConst);
2332 if (!getLoweringOptions().getIntegerWrapAround())
2333 builder->setIntegerOverflowFlags(iofBackup);
2334 boundsAndStepIP = stepValue.getDefiningOp();
Kareem Ergawy06984822024-10-31 09:19:18 +01002335
Kareem Ergawy30990c02025-04-16 14:20:27 +02002336 // Use a temp variable for unstructured loops with non-const step.
2337 if (!isConst) {
2338 info.stepVariable =
2339 builder->createTemporary(loc, stepValue.getType());
2340 boundsAndStepIP =
2341 builder->create<fir::StoreOp>(loc, stepValue, info.stepVariable);
Kareem Ergawy04b87e12025-04-16 06:14:38 +02002342 }
2343 }
Kareem Ergawy04b87e12025-04-16 06:14:38 +02002344
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002345 // Structured loop - generate fir.do_loop.
2346 if (info.isStructured()) {
V Donaldson609b7892023-01-03 10:31:30 -08002347 mlir::Type loopVarType = info.getLoopVariableType();
Kareem Ergawy30990c02025-04-16 14:20:27 +02002348 mlir::Value loopValue;
2349 if (info.isUnordered) {
2350 llvm::SmallVector<mlir::Value> reduceOperands;
2351 llvm::SmallVector<mlir::Attribute> reduceAttrs;
2352 // Create DO CONCURRENT reduce operands and attributes
2353 for (const auto &reduceSym : info.reduceSymList) {
2354 const fir::ReduceOperationEnum reduce_operation = reduceSym.first;
2355 const Fortran::semantics::Symbol *sym = reduceSym.second;
2356 fir::ExtendedValue exv = getSymbolExtendedValue(*sym, nullptr);
2357 reduceOperands.push_back(fir::getBase(exv));
2358 auto reduce_attr =
2359 fir::ReduceAttr::get(builder->getContext(), reduce_operation);
2360 reduceAttrs.push_back(reduce_attr);
2361 }
2362 // The loop variable value is explicitly updated.
2363 info.doLoop = builder->create<fir::DoLoopOp>(
2364 loc, lowerValue, upperValue, stepValue, /*unordered=*/true,
2365 /*finalCountValue=*/false, /*iterArgs=*/std::nullopt,
2366 llvm::ArrayRef<mlir::Value>(reduceOperands), reduceAttrs);
2367 builder->setInsertionPointToStart(info.doLoop.getBody());
2368 loopValue = builder->createConvert(loc, loopVarType,
2369 info.doLoop.getInductionVar());
2370 } else {
2371 // The loop variable is a doLoop op argument.
2372 info.doLoop = builder->create<fir::DoLoopOp>(
2373 loc, lowerValue, upperValue, stepValue, /*unordered=*/false,
2374 /*finalCountValue=*/true,
2375 builder->createConvert(loc, loopVarType, lowerValue));
2376 builder->setInsertionPointToStart(info.doLoop.getBody());
2377 loopValue = info.doLoop.getRegionIterArgs()[0];
2378 }
V Donaldson609b7892023-01-03 10:31:30 -08002379 // Update the loop variable value in case it has non-index references.
2380 builder->create<fir::StoreOp>(loc, loopValue, info.loopVariable);
Kareem Ergawy30990c02025-04-16 14:20:27 +02002381 if (info.maskExpr) {
2382 Fortran::lower::StatementContext stmtCtx;
2383 mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
2384 stmtCtx.finalizeAndReset();
2385 mlir::Value maskCondCast =
2386 builder->createConvert(loc, builder->getI1Type(), maskCond);
2387 auto ifOp = builder->create<fir::IfOp>(loc, maskCondCast,
2388 /*withElseRegion=*/false);
2389 builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2390 }
2391 if (info.hasLocalitySpecs())
2392 handleLocalitySpecs(info);
2393
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002394 addLoopAnnotationAttr(info, dirs);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002395 continue;
2396 }
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002397
2398 // Unstructured loop preheader - initialize tripVariable and loopVariable.
2399 mlir::Value tripCount;
Diana Picusa1591282022-05-31 10:55:56 +00002400 if (info.hasRealControl) {
2401 auto diff1 =
2402 builder->create<mlir::arith::SubFOp>(loc, upperValue, lowerValue);
2403 auto diff2 =
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002404 builder->create<mlir::arith::AddFOp>(loc, diff1, stepValue);
2405 tripCount = builder->create<mlir::arith::DivFOp>(loc, diff2, stepValue);
Diana Picusa1591282022-05-31 10:55:56 +00002406 tripCount =
2407 builder->createConvert(loc, builder->getIndexType(), tripCount);
Diana Picusa1591282022-05-31 10:55:56 +00002408 } else {
2409 auto diff1 =
2410 builder->create<mlir::arith::SubIOp>(loc, upperValue, lowerValue);
2411 auto diff2 =
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002412 builder->create<mlir::arith::AddIOp>(loc, diff1, stepValue);
Diana Picusa1591282022-05-31 10:55:56 +00002413 tripCount =
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002414 builder->create<mlir::arith::DivSIOp>(loc, diff2, stepValue);
Diana Picusa1591282022-05-31 10:55:56 +00002415 }
Kiran Chandramohan7eecfc02022-06-07 09:57:38 +00002416 if (forceLoopToExecuteOnce) { // minimum tripCount is 1
2417 mlir::Value one =
2418 builder->createIntegerConstant(loc, tripCount.getType(), 1);
2419 auto cond = builder->create<mlir::arith::CmpIOp>(
2420 loc, mlir::arith::CmpIPredicate::slt, tripCount, one);
2421 tripCount =
2422 builder->create<mlir::arith::SelectOp>(loc, cond, one, tripCount);
2423 }
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002424 info.tripVariable = builder->createTemporary(loc, tripCount.getType());
2425 builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
2426 builder->create<fir::StoreOp>(loc, lowerValue, info.loopVariable);
2427
2428 // Unstructured loop header - generate loop condition and mask.
Mats Petersson84b9ae62022-06-07 14:00:08 +01002429 // Note - Currently there is no way to tag a loop as a concurrent loop.
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002430 startBlock(info.headerBlock);
2431 tripCount = builder->create<fir::LoadOp>(loc, info.tripVariable);
2432 mlir::Value zero =
2433 builder->createIntegerConstant(loc, tripCount.getType(), 0);
2434 auto cond = builder->create<mlir::arith::CmpIOp>(
2435 loc, mlir::arith::CmpIPredicate::sgt, tripCount, zero);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002436 if (info.maskExpr) {
V Donaldson2c143342023-02-27 14:05:53 -08002437 genConditionalBranch(cond, info.maskBlock, info.exitBlock);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002438 startBlock(info.maskBlock);
2439 mlir::Block *latchBlock = getEval().getLastNestedEvaluation().block;
2440 assert(latchBlock && "missing masked concurrent loop latch block");
2441 Fortran::lower::StatementContext stmtCtx;
2442 mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
V Donaldson2c143342023-02-27 14:05:53 -08002443 stmtCtx.finalizeAndReset();
2444 genConditionalBranch(maskCond, info.bodyBlock, latchBlock);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002445 } else {
V Donaldson2c143342023-02-27 14:05:53 -08002446 genConditionalBranch(cond, info.bodyBlock, info.exitBlock);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002447 if (&info != &incrementLoopNestInfo.back()) // not innermost
2448 startBlock(info.bodyBlock); // preheader block of enclosed dimension
2449 }
V Donaldson335b3992023-08-07 13:29:17 -07002450 if (info.hasLocalitySpecs()) {
Mats Petersson84b9ae62022-06-07 14:00:08 +01002451 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
2452 builder->setInsertionPointToStart(info.bodyBlock);
V Donaldson335b3992023-08-07 13:29:17 -07002453 handleLocalitySpecs(info);
Mats Petersson84b9ae62022-06-07 14:00:08 +01002454 builder->restoreInsertionPoint(insertPt);
2455 }
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002456 }
2457 }
2458
2459 /// Generate FIR to end a structured or unstructured increment loop nest.
2460 void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
2461 assert(!incrementLoopNestInfo.empty() && "empty loop nest");
2462 mlir::Location loc = toLocation();
Yusuke MINATO526553b2024-05-16 13:16:07 +09002463 mlir::arith::IntegerOverflowFlags flags{};
Yusuke MINATOa88677e2024-12-10 16:26:53 +09002464 if (!getLoweringOptions().getIntegerWrapAround())
Yusuke MINATO526553b2024-05-16 13:16:07 +09002465 flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
2466 auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
2467 builder->getContext(), flags);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002468 for (auto it = incrementLoopNestInfo.rbegin(),
2469 rend = incrementLoopNestInfo.rend();
2470 it != rend; ++it) {
2471 IncrementLoopInfo &info = *it;
2472 if (info.isStructured()) {
Kareem Ergawy30990c02025-04-16 14:20:27 +02002473 // End fir.do_loop.
2474 if (info.isUnordered) {
2475 builder->setInsertionPointAfter(info.doLoop);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002476 continue;
Slava Zakharinaf7edf12022-08-18 14:06:19 -07002477 }
V Donaldson609b7892023-01-03 10:31:30 -08002478 // Decrement tripVariable.
Kareem Ergawy30990c02025-04-16 14:20:27 +02002479 builder->setInsertionPointToEnd(info.doLoop.getBody());
V Donaldson609b7892023-01-03 10:31:30 -08002480 llvm::SmallVector<mlir::Value, 2> results;
2481 results.push_back(builder->create<mlir::arith::AddIOp>(
Kareem Ergawy30990c02025-04-16 14:20:27 +02002482 loc, info.doLoop.getInductionVar(), info.doLoop.getStep(),
2483 iofAttr));
V Donaldson609b7892023-01-03 10:31:30 -08002484 // Step loopVariable to help optimizations such as vectorization.
2485 // Induction variable elimination will clean up as necessary.
2486 mlir::Value step = builder->createConvert(
Kareem Ergawy30990c02025-04-16 14:20:27 +02002487 loc, info.getLoopVariableType(), info.doLoop.getStep());
V Donaldson609b7892023-01-03 10:31:30 -08002488 mlir::Value loopVar =
2489 builder->create<fir::LoadOp>(loc, info.loopVariable);
2490 results.push_back(
Yusuke MINATO526553b2024-05-16 13:16:07 +09002491 builder->create<mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
V Donaldson609b7892023-01-03 10:31:30 -08002492 builder->create<fir::ResultOp>(loc, results);
Kareem Ergawy30990c02025-04-16 14:20:27 +02002493 builder->setInsertionPointAfter(info.doLoop);
V Donaldson609b7892023-01-03 10:31:30 -08002494 // The loop control variable may be used after the loop.
Kareem Ergawy30990c02025-04-16 14:20:27 +02002495 builder->create<fir::StoreOp>(loc, info.doLoop.getResult(1),
V Donaldson609b7892023-01-03 10:31:30 -08002496 info.loopVariable);
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002497 continue;
2498 }
2499
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002500 // Unstructured loop - decrement tripVariable and step loopVariable.
2501 mlir::Value tripCount =
2502 builder->create<fir::LoadOp>(loc, info.tripVariable);
2503 mlir::Value one =
2504 builder->createIntegerConstant(loc, tripCount.getType(), 1);
2505 tripCount = builder->create<mlir::arith::SubIOp>(loc, tripCount, one);
2506 builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
2507 mlir::Value value = builder->create<fir::LoadOp>(loc, info.loopVariable);
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002508 mlir::Value step;
2509 if (info.stepVariable)
2510 step = builder->create<fir::LoadOp>(loc, info.stepVariable);
Diana Picusa1591282022-05-31 10:55:56 +00002511 else
Leandro Lupori3dbb0552023-09-21 15:59:35 +02002512 step = genControlValue(info.stepExpr, info);
2513 if (info.hasRealControl)
2514 value = builder->create<mlir::arith::AddFOp>(loc, value, step);
2515 else
Yusuke MINATO526553b2024-05-16 13:16:07 +09002516 value = builder->create<mlir::arith::AddIOp>(loc, value, step, iofAttr);
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002517 builder->create<fir::StoreOp>(loc, value, info.loopVariable);
2518
V Donaldson2c143342023-02-27 14:05:53 -08002519 genBranch(info.headerBlock);
Kiran Chandramohanaa0e1672022-05-06 09:09:01 +00002520 if (&info != &incrementLoopNestInfo.front()) // not outermost
2521 startBlock(info.exitBlock); // latch block of enclosing dimension
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00002522 }
Valentin Clement99075912022-02-01 13:49:49 +01002523 }
2524
Valentin Clementfe252f82022-03-22 15:40:32 +01002525 /// Generate structured or unstructured FIR for an IF construct.
2526 /// The initial statement may be either an IfStmt or an IfThenStmt.
Valentin Clement99075912022-02-01 13:49:49 +01002527 void genFIR(const Fortran::parser::IfConstruct &) {
Valentin Clement764f95a2022-03-07 19:55:48 +01002528 Fortran::lower::pft::Evaluation &eval = getEval();
vdonaldsoncda82702024-05-03 09:11:10 -04002529
2530 // Structured fir.if nest.
Valentin Clement764f95a2022-03-07 19:55:48 +01002531 if (eval.lowerAsStructured()) {
Valentin Clement764f95a2022-03-07 19:55:48 +01002532 fir::IfOp topIfOp, currentIfOp;
2533 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2534 auto genIfOp = [&](mlir::Value cond) {
vdonaldson8586d032024-08-30 09:07:30 -04002535 Fortran::lower::pft::Evaluation &succ = *e.controlSuccessor;
2536 bool hasElse = succ.isA<Fortran::parser::ElseIfStmt>() ||
2537 succ.isA<Fortran::parser::ElseStmt>();
2538 auto ifOp = builder->create<fir::IfOp>(toLocation(), cond,
2539 /*withElseRegion=*/hasElse);
Valentin Clement764f95a2022-03-07 19:55:48 +01002540 builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2541 return ifOp;
2542 };
vdonaldsoncda82702024-05-03 09:11:10 -04002543 setCurrentPosition(e.position);
Valentin Clement764f95a2022-03-07 19:55:48 +01002544 if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
2545 topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
2546 } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
2547 topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
2548 } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
2549 builder->setInsertionPointToStart(
2550 &currentIfOp.getElseRegion().front());
2551 currentIfOp = genIfOp(genIfCondition(s));
2552 } else if (e.isA<Fortran::parser::ElseStmt>()) {
2553 builder->setInsertionPointToStart(
2554 &currentIfOp.getElseRegion().front());
2555 } else if (e.isA<Fortran::parser::EndIfStmt>()) {
2556 builder->setInsertionPointAfter(topIfOp);
V Donaldson609b7892023-01-03 10:31:30 -08002557 genFIR(e, /*unstructuredContext=*/false); // may generate branch
Valentin Clement764f95a2022-03-07 19:55:48 +01002558 } else {
2559 genFIR(e, /*unstructuredContext=*/false);
2560 }
2561 }
2562 return;
2563 }
2564
2565 // Unstructured branch sequence.
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05002566 llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2567 collectFinalEvaluations(eval, exits, fallThroughs);
2568
Valentin Clement764f95a2022-03-07 19:55:48 +01002569 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2570 auto genIfBranch = [&](mlir::Value cond) {
2571 if (e.lexicalSuccessor == e.controlSuccessor) // empty block -> exit
V Donaldson2c143342023-02-27 14:05:53 -08002572 genConditionalBranch(cond, e.parentConstruct->constructExit,
2573 e.controlSuccessor);
Valentin Clement764f95a2022-03-07 19:55:48 +01002574 else // non-empty block
V Donaldson2c143342023-02-27 14:05:53 -08002575 genConditionalBranch(cond, e.lexicalSuccessor, e.controlSuccessor);
Valentin Clement764f95a2022-03-07 19:55:48 +01002576 };
vdonaldsoncda82702024-05-03 09:11:10 -04002577 setCurrentPosition(e.position);
Valentin Clement764f95a2022-03-07 19:55:48 +01002578 if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
2579 maybeStartBlock(e.block);
2580 genIfBranch(genIfCondition(s, e.negateCondition));
2581 } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
2582 maybeStartBlock(e.block);
2583 genIfBranch(genIfCondition(s, e.negateCondition));
2584 } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
2585 startBlock(e.block);
2586 genIfBranch(genIfCondition(s));
2587 } else {
2588 genFIR(e);
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05002589 if (blockIsUnterminated()) {
2590 if (llvm::is_contained(exits, &e))
2591 genConstructExitBranch(*eval.constructExit);
2592 else if (llvm::is_contained(fallThroughs, &e))
2593 genBranch(e.lexicalSuccessor->block);
2594 }
Valentin Clement764f95a2022-03-07 19:55:48 +01002595 }
2596 }
Valentin Clement99075912022-02-01 13:49:49 +01002597 }
2598
jeanPerierd1aa9ba2024-06-03 17:20:07 +02002599 void genCaseOrRankConstruct() {
V Donaldson2c143342023-02-27 14:05:53 -08002600 Fortran::lower::pft::Evaluation &eval = getEval();
2601 Fortran::lower::StatementContext stmtCtx;
2602 pushActiveConstruct(eval, stmtCtx);
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05002603
2604 llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2605 collectFinalEvaluations(eval, exits, fallThroughs);
2606
Carlos Eduardo Seo9ceb0a72023-05-20 05:16:50 +00002607 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2608 if (e.getIf<Fortran::parser::EndSelectStmt>())
2609 maybeStartBlock(e.block);
2610 else
2611 genFIR(e);
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05002612 if (blockIsUnterminated()) {
2613 if (llvm::is_contained(exits, &e))
2614 genConstructExitBranch(*eval.constructExit);
2615 else if (llvm::is_contained(fallThroughs, &e))
2616 genBranch(e.lexicalSuccessor->block);
2617 }
Carlos Eduardo Seo9ceb0a72023-05-20 05:16:50 +00002618 }
V Donaldson2c143342023-02-27 14:05:53 -08002619 popActiveConstruct();
Valentin Clement99075912022-02-01 13:49:49 +01002620 }
jeanPerierd1aa9ba2024-06-03 17:20:07 +02002621 void genFIR(const Fortran::parser::CaseConstruct &) {
2622 genCaseOrRankConstruct();
2623 }
Valentin Clement99075912022-02-01 13:49:49 +01002624
Valentin Clement7a6a1652022-03-10 18:43:40 +01002625 template <typename A>
2626 void genNestedStatement(const Fortran::parser::Statement<A> &stmt) {
2627 setCurrentPosition(stmt.source);
2628 genFIR(stmt.statement);
2629 }
2630
Valentin Clement88ae0d62022-03-10 19:43:11 +01002631 /// Force the binding of an explicit symbol. This is used to bind and re-bind
2632 /// a concurrent control symbol to its value.
2633 void forceControlVariableBinding(const Fortran::semantics::Symbol *sym,
2634 mlir::Value inducVar) {
2635 mlir::Location loc = toLocation();
2636 assert(sym && "There must be a symbol to bind");
2637 mlir::Type toTy = genType(*sym);
2638 // FIXME: this should be a "per iteration" temporary.
Mats Petersson0ccef6a2023-11-29 16:15:43 +00002639 mlir::Value tmp =
2640 builder->createTemporary(loc, toTy, toStringRef(sym->name()),
2641 llvm::ArrayRef<mlir::NamedAttribute>{
2642 fir::getAdaptToByRefAttr(*builder)});
Valentin Clement88ae0d62022-03-10 19:43:11 +01002643 mlir::Value cast = builder->createConvert(loc, toTy, inducVar);
2644 builder->create<fir::StoreOp>(loc, cast, tmp);
Jean Perierab9c4e92023-02-07 09:22:47 +01002645 addSymbol(*sym, tmp, /*force=*/true);
Valentin Clement88ae0d62022-03-10 19:43:11 +01002646 }
2647
2648 /// Process a concurrent header for a FORALL. (Concurrent headers for DO
2649 /// CONCURRENT loops are lowered elsewhere.)
Valentin Clement99075912022-02-01 13:49:49 +01002650 void genFIR(const Fortran::parser::ConcurrentHeader &header) {
Valentin Clement88ae0d62022-03-10 19:43:11 +01002651 llvm::SmallVector<mlir::Value> lows;
2652 llvm::SmallVector<mlir::Value> highs;
2653 llvm::SmallVector<mlir::Value> steps;
2654 if (explicitIterSpace.isOutermostForall()) {
2655 // For the outermost forall, we evaluate the bounds expressions once.
2656 // Contrastingly, if this forall is nested, the bounds expressions are
2657 // assumed to be pure, possibly dependent on outer concurrent control
2658 // variables, possibly variant with respect to arguments, and will be
2659 // re-evaluated.
2660 mlir::Location loc = toLocation();
2661 mlir::Type idxTy = builder->getIndexType();
2662 Fortran::lower::StatementContext &stmtCtx =
2663 explicitIterSpace.stmtContext();
2664 auto lowerExpr = [&](auto &e) {
2665 return fir::getBase(genExprValue(e, stmtCtx));
2666 };
2667 for (const Fortran::parser::ConcurrentControl &ctrl :
2668 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2669 const Fortran::lower::SomeExpr *lo =
2670 Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
2671 const Fortran::lower::SomeExpr *hi =
2672 Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
2673 auto &optStep =
2674 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
2675 lows.push_back(builder->createConvert(loc, idxTy, lowerExpr(*lo)));
2676 highs.push_back(builder->createConvert(loc, idxTy, lowerExpr(*hi)));
2677 steps.push_back(
2678 optStep.has_value()
2679 ? builder->createConvert(
2680 loc, idxTy,
2681 lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
2682 : builder->createIntegerConstant(loc, idxTy, 1));
2683 }
2684 }
2685 auto lambda = [&, lows, highs, steps]() {
2686 // Create our iteration space from the header spec.
2687 mlir::Location loc = toLocation();
2688 mlir::Type idxTy = builder->getIndexType();
2689 llvm::SmallVector<fir::DoLoopOp> loops;
2690 Fortran::lower::StatementContext &stmtCtx =
2691 explicitIterSpace.stmtContext();
2692 auto lowerExpr = [&](auto &e) {
2693 return fir::getBase(genExprValue(e, stmtCtx));
2694 };
2695 const bool outermost = !lows.empty();
2696 std::size_t headerIndex = 0;
2697 for (const Fortran::parser::ConcurrentControl &ctrl :
2698 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2699 const Fortran::semantics::Symbol *ctrlVar =
2700 std::get<Fortran::parser::Name>(ctrl.t).symbol;
2701 mlir::Value lb;
2702 mlir::Value ub;
2703 mlir::Value by;
2704 if (outermost) {
2705 assert(headerIndex < lows.size());
2706 if (headerIndex == 0)
2707 explicitIterSpace.resetInnerArgs();
2708 lb = lows[headerIndex];
2709 ub = highs[headerIndex];
2710 by = steps[headerIndex++];
2711 } else {
2712 const Fortran::lower::SomeExpr *lo =
2713 Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
2714 const Fortran::lower::SomeExpr *hi =
2715 Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
2716 auto &optStep =
2717 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
2718 lb = builder->createConvert(loc, idxTy, lowerExpr(*lo));
2719 ub = builder->createConvert(loc, idxTy, lowerExpr(*hi));
2720 by = optStep.has_value()
2721 ? builder->createConvert(
2722 loc, idxTy,
2723 lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
2724 : builder->createIntegerConstant(loc, idxTy, 1);
2725 }
2726 auto lp = builder->create<fir::DoLoopOp>(
2727 loc, lb, ub, by, /*unordered=*/true,
2728 /*finalCount=*/false, explicitIterSpace.getInnerArgs());
Valentin Clement0dd4fb02022-07-01 10:36:45 +02002729 if ((!loops.empty() || !outermost) && !lp.getRegionIterArgs().empty())
Valentin Clement88ae0d62022-03-10 19:43:11 +01002730 builder->create<fir::ResultOp>(loc, lp.getResults());
2731 explicitIterSpace.setInnerArgs(lp.getRegionIterArgs());
2732 builder->setInsertionPointToStart(lp.getBody());
2733 forceControlVariableBinding(ctrlVar, lp.getInductionVar());
2734 loops.push_back(lp);
2735 }
2736 if (outermost)
2737 explicitIterSpace.setOuterLoop(loops[0]);
2738 explicitIterSpace.appendLoops(loops);
2739 if (const auto &mask =
2740 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
2741 header.t);
2742 mask.has_value()) {
2743 mlir::Type i1Ty = builder->getI1Type();
2744 fir::ExtendedValue maskExv =
2745 genExprValue(*Fortran::semantics::GetExpr(mask.value()), stmtCtx);
2746 mlir::Value cond =
2747 builder->createConvert(loc, i1Ty, fir::getBase(maskExv));
2748 auto ifOp = builder->create<fir::IfOp>(
2749 loc, explicitIterSpace.innerArgTypes(), cond,
2750 /*withElseRegion=*/true);
2751 builder->create<fir::ResultOp>(loc, ifOp.getResults());
2752 builder->setInsertionPointToStart(&ifOp.getElseRegion().front());
2753 builder->create<fir::ResultOp>(loc, explicitIterSpace.getInnerArgs());
2754 builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2755 }
2756 };
2757 // Push the lambda to gen the loop nest context.
2758 explicitIterSpace.pushLoopNest(lambda);
Valentin Clement99075912022-02-01 13:49:49 +01002759 }
2760
2761 void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07002762 Fortran::common::visit([&](const auto &x) { genFIR(x); }, stmt.u);
Valentin Clement99075912022-02-01 13:49:49 +01002763 }
2764
2765 void genFIR(const Fortran::parser::EndForallStmt &) {
Jean Perierb87e6552023-05-09 09:18:53 +02002766 if (!lowerToHighLevelFIR())
2767 cleanupExplicitSpace();
Valentin Clement99075912022-02-01 13:49:49 +01002768 }
2769
Valentin Clement88ae0d62022-03-10 19:43:11 +01002770 template <typename A>
2771 void prepareExplicitSpace(const A &forall) {
2772 if (!explicitIterSpace.isActive())
2773 analyzeExplicitSpace(forall);
2774 localSymbols.pushScope();
2775 explicitIterSpace.enter();
Valentin Clement99075912022-02-01 13:49:49 +01002776 }
2777
Valentin Clement88ae0d62022-03-10 19:43:11 +01002778 /// Cleanup all the FORALL context information when we exit.
2779 void cleanupExplicitSpace() {
2780 explicitIterSpace.leave();
2781 localSymbols.popScope();
Valentin Clement99075912022-02-01 13:49:49 +01002782 }
2783
Valentin Clement88ae0d62022-03-10 19:43:11 +01002784 /// Generate FIR for a FORALL statement.
2785 void genFIR(const Fortran::parser::ForallStmt &stmt) {
Jean Perierb87e6552023-05-09 09:18:53 +02002786 const auto &concurrentHeader =
2787 std::get<
2788 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
2789 stmt.t)
2790 .value();
2791 if (lowerToHighLevelFIR()) {
Sergio Afonso433ca3e2024-09-10 11:09:25 +01002792 mlir::OpBuilder::InsertionGuard guard(*builder);
2793 Fortran::lower::SymMapScope scope(localSymbols);
Jean Perierb87e6552023-05-09 09:18:53 +02002794 genForallNest(concurrentHeader);
2795 genFIR(std::get<Fortran::parser::UnlabeledStatement<
2796 Fortran::parser::ForallAssignmentStmt>>(stmt.t)
2797 .statement);
Jean Perierb87e6552023-05-09 09:18:53 +02002798 return;
2799 }
Valentin Clement88ae0d62022-03-10 19:43:11 +01002800 prepareExplicitSpace(stmt);
Jean Perierb87e6552023-05-09 09:18:53 +02002801 genFIR(concurrentHeader);
Valentin Clement88ae0d62022-03-10 19:43:11 +01002802 genFIR(std::get<Fortran::parser::UnlabeledStatement<
2803 Fortran::parser::ForallAssignmentStmt>>(stmt.t)
2804 .statement);
2805 cleanupExplicitSpace();
2806 }
2807
2808 /// Generate FIR for a FORALL construct.
2809 void genFIR(const Fortran::parser::ForallConstruct &forall) {
Jean Perierb87e6552023-05-09 09:18:53 +02002810 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
2811 if (lowerToHighLevelFIR())
2812 localSymbols.pushScope();
2813 else
2814 prepareExplicitSpace(forall);
Valentin Clement88ae0d62022-03-10 19:43:11 +01002815 genNestedStatement(
2816 std::get<
2817 Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
2818 forall.t));
2819 for (const Fortran::parser::ForallBodyConstruct &s :
2820 std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07002821 Fortran::common::visit(
Valentin Clement88ae0d62022-03-10 19:43:11 +01002822 Fortran::common::visitors{
2823 [&](const Fortran::parser::WhereConstruct &b) { genFIR(b); },
2824 [&](const Fortran::common::Indirection<
2825 Fortran::parser::ForallConstruct> &b) { genFIR(b.value()); },
2826 [&](const auto &b) { genNestedStatement(b); }},
2827 s.u);
2828 }
2829 genNestedStatement(
2830 std::get<Fortran::parser::Statement<Fortran::parser::EndForallStmt>>(
2831 forall.t));
Jean Perierb87e6552023-05-09 09:18:53 +02002832 if (lowerToHighLevelFIR()) {
2833 localSymbols.popScope();
2834 builder->restoreInsertionPoint(insertPt);
2835 }
Valentin Clement88ae0d62022-03-10 19:43:11 +01002836 }
2837
2838 /// Lower the concurrent header specification.
2839 void genFIR(const Fortran::parser::ForallConstructStmt &stmt) {
Jean Perierb87e6552023-05-09 09:18:53 +02002840 const auto &concurrentHeader =
2841 std::get<
2842 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
2843 stmt.t)
2844 .value();
2845 if (lowerToHighLevelFIR())
2846 genForallNest(concurrentHeader);
2847 else
2848 genFIR(concurrentHeader);
2849 }
2850
2851 /// Generate hlfir.forall and hlfir.forall_mask nest given a Forall
2852 /// concurrent header
2853 void genForallNest(const Fortran::parser::ConcurrentHeader &header) {
2854 mlir::Location loc = getCurrentLocation();
2855 const bool isOutterForall = !isInsideHlfirForallOrWhere();
2856 hlfir::ForallOp outerForall;
2857 auto evaluateControl = [&](const auto &parserExpr, mlir::Region &region,
2858 bool isMask = false) {
2859 if (region.empty())
2860 builder->createBlock(&region);
2861 Fortran::lower::StatementContext localStmtCtx;
2862 const Fortran::semantics::SomeExpr *anlalyzedExpr =
2863 Fortran::semantics::GetExpr(parserExpr);
2864 assert(anlalyzedExpr && "expression semantics failed");
2865 // Generate the controls of outer forall outside of the hlfir.forall
2866 // region. They do not depend on any previous forall indices (C1123) and
2867 // no assignment has been made yet that could modify their value. This
2868 // will simplify hlfir.forall analysis because the SSA integer value
2869 // yielded will obviously not depend on any variable modified by the
2870 // forall when produced outside of it.
2871 // This is not done for the mask because it may (and in usual code, does)
2872 // depend on the forall indices that have just been defined as
2873 // hlfir.forall block arguments.
2874 mlir::OpBuilder::InsertPoint innerInsertionPoint;
2875 if (outerForall && !isMask) {
2876 innerInsertionPoint = builder->saveInsertionPoint();
2877 builder->setInsertionPoint(outerForall);
2878 }
2879 mlir::Value exprVal =
2880 fir::getBase(genExprValue(*anlalyzedExpr, localStmtCtx, &loc));
2881 localStmtCtx.finalizeAndPop();
2882 if (isMask)
2883 exprVal = builder->createConvert(loc, builder->getI1Type(), exprVal);
2884 if (innerInsertionPoint.isSet())
2885 builder->restoreInsertionPoint(innerInsertionPoint);
2886 builder->create<hlfir::YieldOp>(loc, exprVal);
2887 };
2888 for (const Fortran::parser::ConcurrentControl &control :
2889 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2890 auto forallOp = builder->create<hlfir::ForallOp>(loc);
2891 if (isOutterForall && !outerForall)
2892 outerForall = forallOp;
2893 evaluateControl(std::get<1>(control.t), forallOp.getLbRegion());
2894 evaluateControl(std::get<2>(control.t), forallOp.getUbRegion());
2895 if (const auto &optionalStep =
2896 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
2897 control.t))
2898 evaluateControl(*optionalStep, forallOp.getStepRegion());
2899 // Create block argument and map it to a symbol via an hlfir.forall_index
2900 // op (symbols must be mapped to in memory values).
2901 const Fortran::semantics::Symbol *controlVar =
2902 std::get<Fortran::parser::Name>(control.t).symbol;
2903 assert(controlVar && "symbol analysis failed");
2904 mlir::Type controlVarType = genType(*controlVar);
2905 mlir::Block *forallBody = builder->createBlock(&forallOp.getBody(), {},
2906 {controlVarType}, {loc});
2907 auto forallIndex = builder->create<hlfir::ForallIndexOp>(
2908 loc, fir::ReferenceType::get(controlVarType),
2909 forallBody->getArguments()[0],
2910 builder->getStringAttr(controlVar->name().ToString()));
2911 localSymbols.addVariableDefinition(*controlVar, forallIndex,
2912 /*force=*/true);
2913 auto end = builder->create<fir::FirEndOp>(loc);
2914 builder->setInsertionPoint(end);
2915 }
2916
2917 if (const auto &maskExpr =
2918 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
2919 header.t)) {
2920 // Create hlfir.forall_mask and set insertion point in its body.
2921 auto forallMaskOp = builder->create<hlfir::ForallMaskOp>(loc);
2922 evaluateControl(*maskExpr, forallMaskOp.getMaskRegion(), /*isMask=*/true);
2923 builder->createBlock(&forallMaskOp.getBody());
2924 auto end = builder->create<fir::FirEndOp>(loc);
2925 builder->setInsertionPoint(end);
2926 }
Valentin Clement99075912022-02-01 13:49:49 +01002927 }
2928
David Trubyc6b6e182024-06-14 14:10:41 +01002929 void attachDirectiveToLoop(const Fortran::parser::CompilerDirective &dir,
2930 Fortran::lower::pft::Evaluation *e) {
2931 while (e->isDirective())
2932 e = e->lexicalSuccessor;
2933
2934 if (e->isA<Fortran::parser::NonLabelDoStmt>())
2935 e->dirs.push_back(&dir);
David Trubyc6b6e182024-06-14 14:10:41 +01002936 }
2937
2938 void genFIR(const Fortran::parser::CompilerDirective &dir) {
2939 Fortran::lower::pft::Evaluation &eval = getEval();
2940
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07002941 Fortran::common::visit(
David Trubyc6b6e182024-06-14 14:10:41 +01002942 Fortran::common::visitors{
2943 [&](const Fortran::parser::CompilerDirective::VectorAlways &) {
2944 attachDirectiveToLoop(dir, &eval);
2945 },
Jean-Didier PAILLEUXe811cb02025-01-29 09:44:09 +01002946 [&](const Fortran::parser::CompilerDirective::Unroll &) {
2947 attachDirectiveToLoop(dir, &eval);
2948 },
Jean-Didier PAILLEUXd6c6bde2025-02-19 16:00:09 +01002949 [&](const Fortran::parser::CompilerDirective::UnrollAndJam &) {
2950 attachDirectiveToLoop(dir, &eval);
2951 },
Jean-Didier PAILLEUXc309abd2025-04-02 14:30:01 +02002952 [&](const Fortran::parser::CompilerDirective::NoVector &) {
2953 attachDirectiveToLoop(dir, &eval);
2954 },
2955 [&](const Fortran::parser::CompilerDirective::NoUnroll &) {
2956 attachDirectiveToLoop(dir, &eval);
2957 },
2958 [&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
2959 attachDirectiveToLoop(dir, &eval);
2960 },
David Trubyc6b6e182024-06-14 14:10:41 +01002961 [&](const auto &) {}},
2962 dir.u);
Valentin Clement99075912022-02-01 13:49:49 +01002963 }
2964
Valentin Clement12d22ce2022-03-24 15:00:52 +01002965 void genFIR(const Fortran::parser::OpenACCConstruct &acc) {
2966 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
Razvan Lupusorue070ea42023-09-11 13:58:10 -07002967 localSymbols.pushScope();
Valentin Clement (バレンタイン クレメン)a9a5af82023-11-30 14:25:03 -08002968 mlir::Value exitCond = genOpenACCConstruct(
2969 *this, bridge.getSemanticsContext(), getEval(), acc);
Valentin Clement (バレンタイン クレメン)5062a172024-01-22 10:31:37 -08002970
2971 const Fortran::parser::OpenACCLoopConstruct *accLoop =
2972 std::get_if<Fortran::parser::OpenACCLoopConstruct>(&acc.u);
2973 const Fortran::parser::OpenACCCombinedConstruct *accCombined =
2974 std::get_if<Fortran::parser::OpenACCCombinedConstruct>(&acc.u);
2975
2976 Fortran::lower::pft::Evaluation *curEval = &getEval();
2977
2978 if (accLoop || accCombined) {
2979 int64_t collapseValue;
2980 if (accLoop) {
2981 const Fortran::parser::AccBeginLoopDirective &beginLoopDir =
2982 std::get<Fortran::parser::AccBeginLoopDirective>(accLoop->t);
2983 const Fortran::parser::AccClauseList &clauseList =
2984 std::get<Fortran::parser::AccClauseList>(beginLoopDir.t);
2985 collapseValue = Fortran::lower::getCollapseValue(clauseList);
2986 } else if (accCombined) {
2987 const Fortran::parser::AccBeginCombinedDirective &beginCombinedDir =
2988 std::get<Fortran::parser::AccBeginCombinedDirective>(
2989 accCombined->t);
2990 const Fortran::parser::AccClauseList &clauseList =
2991 std::get<Fortran::parser::AccClauseList>(beginCombinedDir.t);
2992 collapseValue = Fortran::lower::getCollapseValue(clauseList);
2993 }
2994
2995 if (curEval->lowerAsStructured()) {
2996 curEval = &curEval->getFirstNestedEvaluation();
2997 for (int64_t i = 1; i < collapseValue; i++)
2998 curEval = &*std::next(curEval->getNestedEvaluations().begin());
2999 }
3000 }
3001
3002 for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
Valentin Clement12d22ce2022-03-24 15:00:52 +01003003 genFIR(e);
Razvan Lupusorue070ea42023-09-11 13:58:10 -07003004 localSymbols.popScope();
Valentin Clement12d22ce2022-03-24 15:00:52 +01003005 builder->restoreInsertionPoint(insertPt);
Valentin Clement (バレンタイン クレメン)a9a5af82023-11-30 14:25:03 -08003006
Valentin Clement (バレンタイン クレメン)a9a5af82023-11-30 14:25:03 -08003007 if (accLoop && exitCond) {
3008 Fortran::lower::pft::FunctionLikeUnit *funit =
3009 getEval().getOwningProcedure();
3010 assert(funit && "not inside main program, function or subroutine");
3011 mlir::Block *continueBlock =
3012 builder->getBlock()->splitBlock(builder->getBlock()->end());
3013 builder->create<mlir::cf::CondBranchOp>(toLocation(), exitCond,
3014 funit->finalBlock, continueBlock);
3015 builder->setInsertionPointToEnd(continueBlock);
3016 }
Valentin Clement99075912022-02-01 13:49:49 +01003017 }
3018
Peixin-Qiaob6b8d342022-04-28 09:40:30 +08003019 void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &accDecl) {
Valentin Clementc217ff82023-07-26 09:55:57 -07003020 genOpenACCDeclarativeConstruct(*this, bridge.getSemanticsContext(),
Valentin Clement (バレンタイン クレメン)a3700cc2023-11-14 14:42:11 -08003021 bridge.openAccCtx(), accDecl,
3022 accRoutineInfos);
Peixin-Qiaob6b8d342022-04-28 09:40:30 +08003023 for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
3024 genFIR(e);
Valentin Clement99075912022-02-01 13:49:49 +01003025 }
3026
Valentin Clement (バレンタイン クレメン)82867432023-10-24 09:17:48 -07003027 void genFIR(const Fortran::parser::OpenACCRoutineConstruct &acc) {
3028 // Handled by genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &)
3029 }
3030
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003031 void genFIR(const Fortran::parser::CUFKernelDoConstruct &kernel) {
Sergio Afonso433ca3e2024-09-10 11:09:25 +01003032 Fortran::lower::SymMapScope scope(localSymbols);
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003033 const Fortran::parser::CUFKernelDoConstruct::Directive &dir =
3034 std::get<Fortran::parser::CUFKernelDoConstruct::Directive>(kernel.t);
3035
3036 mlir::Location loc = genLocation(dir.source);
3037
3038 Fortran::lower::StatementContext stmtCtx;
3039
3040 unsigned nestedLoops = 1;
3041
3042 const auto &nLoops =
3043 std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>(dir.t);
3044 if (nLoops)
3045 nestedLoops = *Fortran::semantics::GetIntValue(*nLoops);
3046
3047 mlir::IntegerAttr n;
3048 if (nestedLoops > 1)
3049 n = builder->getIntegerAttr(builder->getI64Type(), nestedLoops);
3050
Valentin Clement (バレンタイン クレメン)37143fe2024-11-12 16:49:44 -08003051 const auto &launchConfig = std::get<std::optional<
3052 Fortran::parser::CUFKernelDoConstruct::LaunchConfiguration>>(dir.t);
3053
Iman Hosseini7665d3d2024-06-12 19:18:41 +01003054 const std::list<Fortran::parser::CUFReduction> &cufreds =
Valentin Clement (バレンタイン クレメン)37143fe2024-11-12 16:49:44 -08003055 std::get<2>(dir.t);
Iman Hosseini7665d3d2024-06-12 19:18:41 +01003056
3057 llvm::SmallVector<mlir::Value> reduceOperands;
3058 llvm::SmallVector<mlir::Attribute> reduceAttrs;
3059
3060 for (const Fortran::parser::CUFReduction &cufred : cufreds) {
3061 fir::ReduceOperationEnum redOpEnum = getReduceOperationEnum(
3062 std::get<Fortran::parser::ReductionOperator>(cufred.t));
3063 const std::list<Fortran::parser::Scalar<Fortran::parser::Variable>>
3064 &scalarvars = std::get<1>(cufred.t);
3065 for (const Fortran::parser::Scalar<Fortran::parser::Variable> &scalarvar :
3066 scalarvars) {
3067 auto reduce_attr =
3068 fir::ReduceAttr::get(builder->getContext(), redOpEnum);
3069 reduceAttrs.push_back(reduce_attr);
3070 const Fortran::parser::Variable &var = scalarvar.thing;
3071 if (const auto *iDesignator = std::get_if<
3072 Fortran::common::Indirection<Fortran::parser::Designator>>(
3073 &var.u)) {
3074 const Fortran::parser::Designator &designator = iDesignator->value();
3075 if (const auto *name =
3076 Fortran::semantics::getDesignatorNameIfDataRef(designator)) {
3077 auto val = getSymbolAddress(*name->symbol);
3078 reduceOperands.push_back(val);
3079 }
3080 }
3081 }
3082 }
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003083
Valentin Clement (バレンタイン クレメン)f6a2a552024-03-18 19:46:11 -07003084 auto isOnlyStars =
3085 [&](const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr>
3086 &list) -> bool {
3087 for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
3088 list) {
3089 if (expr.v)
3090 return false;
3091 }
3092 return true;
3093 };
3094
3095 mlir::Value zero =
3096 builder->createIntegerConstant(loc, builder->getI32Type(), 0);
3097
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003098 llvm::SmallVector<mlir::Value> gridValues;
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003099 llvm::SmallVector<mlir::Value> blockValues;
Valentin Clement (バレンタイン クレメン)37143fe2024-11-12 16:49:44 -08003100 mlir::Value streamValue;
3101
3102 if (launchConfig) {
3103 const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr> &grid =
3104 std::get<0>(launchConfig->t);
3105 const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr>
3106 &block = std::get<1>(launchConfig->t);
3107 const std::optional<Fortran::parser::ScalarIntExpr> &stream =
3108 std::get<2>(launchConfig->t);
3109 if (!isOnlyStars(grid)) {
3110 for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
3111 grid) {
3112 if (expr.v) {
3113 gridValues.push_back(fir::getBase(
3114 genExprValue(*Fortran::semantics::GetExpr(*expr.v), stmtCtx)));
3115 } else {
3116 gridValues.push_back(zero);
3117 }
Valentin Clement (バレンタイン クレメン)f6a2a552024-03-18 19:46:11 -07003118 }
Peter Klausler60fa2b02024-03-15 13:57:42 -07003119 }
Valentin Clement (バレンタイン クレメン)37143fe2024-11-12 16:49:44 -08003120 if (!isOnlyStars(block)) {
3121 for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
3122 block) {
3123 if (expr.v) {
3124 blockValues.push_back(fir::getBase(
3125 genExprValue(*Fortran::semantics::GetExpr(*expr.v), stmtCtx)));
3126 } else {
3127 blockValues.push_back(zero);
3128 }
3129 }
3130 }
3131
3132 if (stream)
3133 streamValue = builder->createConvert(
3134 loc, builder->getI32Type(),
3135 fir::getBase(
3136 genExprValue(*Fortran::semantics::GetExpr(*stream), stmtCtx)));
Peter Klausler60fa2b02024-03-15 13:57:42 -07003137 }
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003138
3139 const auto &outerDoConstruct =
3140 std::get<std::optional<Fortran::parser::DoConstruct>>(kernel.t);
3141
3142 llvm::SmallVector<mlir::Location> locs;
3143 locs.push_back(loc);
3144 llvm::SmallVector<mlir::Value> lbs, ubs, steps;
3145
3146 mlir::Type idxTy = builder->getIndexType();
3147
3148 llvm::SmallVector<mlir::Type> ivTypes;
3149 llvm::SmallVector<mlir::Location> ivLocs;
3150 llvm::SmallVector<mlir::Value> ivValues;
Valentin Clement (バレンタイン クレメン)f7245402024-05-07 08:29:21 -07003151 Fortran::lower::pft::Evaluation *loopEval =
3152 &getEval().getFirstNestedEvaluation();
Zhen Wanga67566b2025-02-20 14:05:44 -08003153 if (outerDoConstruct->IsDoConcurrent()) {
3154 // Handle DO CONCURRENT
3155 locs.push_back(
3156 genLocation(Fortran::parser::FindSourceLocation(outerDoConstruct)));
3157 const Fortran::parser::LoopControl *loopControl =
3158 &*outerDoConstruct->GetLoopControl();
3159 const auto &concurrent =
3160 std::get<Fortran::parser::LoopControl::Concurrent>(loopControl->u);
3161
3162 if (!std::get<std::list<Fortran::parser::LocalitySpec>>(concurrent.t)
3163 .empty())
3164 TODO(loc, "DO CONCURRENT with locality spec");
3165
3166 const auto &concurrentHeader =
3167 std::get<Fortran::parser::ConcurrentHeader>(concurrent.t);
3168 const auto &controls =
3169 std::get<std::list<Fortran::parser::ConcurrentControl>>(
3170 concurrentHeader.t);
3171
3172 for (const auto &control : controls) {
3173 mlir::Value lb = fir::getBase(genExprValue(
3174 *Fortran::semantics::GetExpr(std::get<1>(control.t)), stmtCtx));
3175 mlir::Value ub = fir::getBase(genExprValue(
3176 *Fortran::semantics::GetExpr(std::get<2>(control.t)), stmtCtx));
3177 mlir::Value step;
3178
3179 if (const auto &expr =
3180 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
3181 control.t))
3182 step = fir::getBase(
3183 genExprValue(*Fortran::semantics::GetExpr(*expr), stmtCtx));
3184 else
3185 step = builder->create<mlir::arith::ConstantIndexOp>(
3186 loc, 1); // Use index type directly
3187
3188 // Ensure lb, ub, and step are of index type using fir.convert
Zhen Wangd1abbb42025-03-05 14:50:42 -08003189 lb = builder->create<fir::ConvertOp>(loc, idxTy, lb);
3190 ub = builder->create<fir::ConvertOp>(loc, idxTy, ub);
3191 step = builder->create<fir::ConvertOp>(loc, idxTy, step);
Zhen Wanga67566b2025-02-20 14:05:44 -08003192
3193 lbs.push_back(lb);
3194 ubs.push_back(ub);
3195 steps.push_back(step);
3196
3197 const auto &name = std::get<Fortran::parser::Name>(control.t);
3198
3199 // Handle induction variable
3200 mlir::Value ivValue = getSymbolAddress(*name.symbol);
Zhen Wanga67566b2025-02-20 14:05:44 -08003201
3202 if (!ivValue) {
3203 // DO CONCURRENT induction variables are not mapped yet since they are
3204 // local to the DO CONCURRENT scope.
3205 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
3206 builder->setInsertionPointToStart(builder->getAllocaBlock());
3207 ivValue = builder->createTemporaryAlloc(
Zhen Wangd1abbb42025-03-05 14:50:42 -08003208 loc, idxTy, toStringRef(name.symbol->name()));
Zhen Wanga67566b2025-02-20 14:05:44 -08003209 builder->restoreInsertionPoint(insPt);
3210 }
3211
Zhen Wanga67566b2025-02-20 14:05:44 -08003212 // Bind the symbol to the declared variable
3213 bindSymbol(*name.symbol, ivValue);
Zhen Wang8f0d8d22025-04-06 19:31:09 -07003214 Fortran::lower::SymbolBox hsb = localSymbols.lookupSymbol(*name.symbol);
3215 fir::ExtendedValue extIvValue = symBoxToExtendedValue(hsb);
3216 ivValue = fir::getBase(extIvValue);
Zhen Wanga67566b2025-02-20 14:05:44 -08003217 ivValues.push_back(ivValue);
Zhen Wangd1abbb42025-03-05 14:50:42 -08003218 ivTypes.push_back(idxTy);
Zhen Wanga67566b2025-02-20 14:05:44 -08003219 ivLocs.push_back(loc);
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003220 }
Zhen Wanga67566b2025-02-20 14:05:44 -08003221 } else {
3222 for (unsigned i = 0; i < nestedLoops; ++i) {
3223 const Fortran::parser::LoopControl *loopControl;
3224 mlir::Location crtLoc = loc;
3225 if (i == 0) {
3226 loopControl = &*outerDoConstruct->GetLoopControl();
3227 crtLoc = genLocation(
3228 Fortran::parser::FindSourceLocation(outerDoConstruct));
3229 } else {
3230 auto *doCons = loopEval->getIf<Fortran::parser::DoConstruct>();
3231 assert(doCons && "expect do construct");
3232 loopControl = &*doCons->GetLoopControl();
3233 crtLoc = genLocation(Fortran::parser::FindSourceLocation(*doCons));
3234 }
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003235
Zhen Wanga67566b2025-02-20 14:05:44 -08003236 locs.push_back(crtLoc);
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003237
Zhen Wanga67566b2025-02-20 14:05:44 -08003238 const Fortran::parser::LoopControl::Bounds *bounds =
3239 std::get_if<Fortran::parser::LoopControl::Bounds>(&loopControl->u);
3240 assert(bounds && "Expected bounds on the loop construct");
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003241
Zhen Wanga67566b2025-02-20 14:05:44 -08003242 Fortran::semantics::Symbol &ivSym =
3243 bounds->name.thing.symbol->GetUltimate();
3244 ivValues.push_back(getSymbolAddress(ivSym));
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003245
Zhen Wanga67566b2025-02-20 14:05:44 -08003246 lbs.push_back(builder->createConvert(
Valentin Clement (バレンタイン クレメン)0469bb92024-12-10 09:48:15 -08003247 crtLoc, idxTy,
3248 fir::getBase(genExprValue(
Zhen Wanga67566b2025-02-20 14:05:44 -08003249 *Fortran::semantics::GetExpr(bounds->lower), stmtCtx))));
3250 ubs.push_back(builder->createConvert(
3251 crtLoc, idxTy,
3252 fir::getBase(genExprValue(
3253 *Fortran::semantics::GetExpr(bounds->upper), stmtCtx))));
3254 if (bounds->step)
3255 steps.push_back(builder->createConvert(
3256 crtLoc, idxTy,
3257 fir::getBase(genExprValue(
3258 *Fortran::semantics::GetExpr(bounds->step), stmtCtx))));
3259 else // If `step` is not present, assume it is `1`.
3260 steps.push_back(builder->createIntegerConstant(loc, idxTy, 1));
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003261
Zhen Wanga67566b2025-02-20 14:05:44 -08003262 ivTypes.push_back(idxTy);
3263 ivLocs.push_back(crtLoc);
3264 if (i < nestedLoops - 1)
3265 loopEval = &*std::next(loopEval->getNestedEvaluations().begin());
3266 }
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003267 }
3268
Iman Hosseini7665d3d2024-06-12 19:18:41 +01003269 auto op = builder->create<cuf::KernelOp>(
3270 loc, gridValues, blockValues, streamValue, lbs, ubs, steps, n,
3271 mlir::ValueRange(reduceOperands), builder->getArrayAttr(reduceAttrs));
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003272 builder->createBlock(&op.getRegion(), op.getRegion().end(), ivTypes,
3273 ivLocs);
3274 mlir::Block &b = op.getRegion().back();
3275 builder->setInsertionPointToStart(&b);
3276
Valentin Clement (バレンタイン クレメン)c81b4302024-09-04 08:43:13 -07003277 Fortran::lower::pft::Evaluation *crtEval = &getEval();
3278 if (crtEval->lowerAsUnstructured())
3279 Fortran::lower::createEmptyRegionBlocks<fir::FirEndOp>(
3280 *builder, crtEval->getNestedEvaluations());
3281 builder->setInsertionPointToStart(&b);
3282
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003283 for (auto [arg, value] : llvm::zip(
3284 op.getLoopRegions().front()->front().getArguments(), ivValues)) {
3285 mlir::Value convArg =
3286 builder->createConvert(loc, fir::unwrapRefType(value.getType()), arg);
3287 builder->create<fir::StoreOp>(loc, convArg, value);
3288 }
3289
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003290 if (crtEval->lowerAsStructured()) {
3291 crtEval = &crtEval->getFirstNestedEvaluation();
3292 for (int64_t i = 1; i < nestedLoops; i++)
3293 crtEval = &*std::next(crtEval->getNestedEvaluations().begin());
3294 }
3295
3296 // Generate loop body
3297 for (Fortran::lower::pft::Evaluation &e : crtEval->getNestedEvaluations())
3298 genFIR(e);
3299
Valentin Clement (バレンタイン クレメン)f815d1f2024-04-30 08:27:28 -07003300 builder->create<fir::FirEndOp>(loc);
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003301 builder->setInsertionPointAfter(op);
Valentin Clement (バレンタイン クレメン)b3189b12024-02-27 11:23:17 -08003302 }
3303
Shraiysh Vaishaye0f549a2022-03-10 22:40:23 +05303304 void genFIR(const Fortran::parser::OpenMPConstruct &omp) {
3305 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
Krzysztof Parzyszekaeb48212023-12-15 09:01:08 -06003306 genOpenMPConstruct(*this, localSymbols, bridge.getSemanticsContext(),
3307 getEval(), omp);
Shraiysh Vaishaye0f549a2022-03-10 22:40:23 +05303308 builder->restoreInsertionPoint(insertPt);
Sergio Afonso29aa7492023-03-29 18:13:48 +01003309
3310 // Register if a target region was found
3311 ompDeviceCodeFound =
3312 ompDeviceCodeFound || Fortran::lower::isOpenMPTargetConstruct(omp);
Valentin Clement99075912022-02-01 13:49:49 +01003313 }
3314
Valentin Clementfe252f82022-03-22 15:40:32 +01003315 void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &ompDecl) {
Peixin-Qiaob6b8d342022-04-28 09:40:30 +08003316 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
Sergio Afonso29aa7492023-03-29 18:13:48 +01003317 // Register if a declare target construct intended for a target device was
3318 // found
3319 ompDeviceCodeFound =
3320 ompDeviceCodeFound ||
Krzysztof Parzyszek1af073a2024-02-12 19:15:55 -06003321 Fortran::lower::isOpenMPDeviceDeclareTarget(
3322 *this, bridge.getSemanticsContext(), getEval(), ompDecl);
agozillonafb05cd2024-03-05 17:27:16 +01003323 Fortran::lower::gatherOpenMPDeferredDeclareTargets(
3324 *this, bridge.getSemanticsContext(), getEval(), ompDecl,
3325 ompDeferredDeclareTarget);
Krzysztof Parzyszekc5a9e352024-01-15 08:01:41 -06003326 genOpenMPDeclarativeConstruct(
3327 *this, localSymbols, bridge.getSemanticsContext(), getEval(), ompDecl);
Peixin-Qiaob6b8d342022-04-28 09:40:30 +08003328 builder->restoreInsertionPoint(insertPt);
Valentin Clement99075912022-02-01 13:49:49 +01003329 }
3330
Valentin Clement308fc3f2022-03-18 15:39:57 +01003331 /// Generate FIR for a SELECT CASE statement.
Peter Klauslerfc97d2e2024-12-18 07:02:37 -08003332 /// The selector may have CHARACTER, INTEGER, UNSIGNED, or LOGICAL type.
Valentin Clement308fc3f2022-03-18 15:39:57 +01003333 void genFIR(const Fortran::parser::SelectCaseStmt &stmt) {
3334 Fortran::lower::pft::Evaluation &eval = getEval();
V Donaldson2c143342023-02-27 14:05:53 -08003335 Fortran::lower::pft::Evaluation *parentConstruct = eval.parentConstruct;
3336 assert(!activeConstructStack.empty() &&
3337 &activeConstructStack.back().eval == parentConstruct &&
3338 "select case construct is not active");
3339 Fortran::lower::StatementContext &stmtCtx =
3340 activeConstructStack.back().stmtCtx;
Valentin Clement308fc3f2022-03-18 15:39:57 +01003341 const Fortran::lower::SomeExpr *expr = Fortran::semantics::GetExpr(
3342 std::get<Fortran::parser::Scalar<Fortran::parser::Expr>>(stmt.t));
3343 bool isCharSelector = isCharacterCategory(expr->GetType()->category());
3344 bool isLogicalSelector = isLogicalCategory(expr->GetType()->category());
V Donaldson2c143342023-02-27 14:05:53 -08003345 mlir::MLIRContext *context = builder->getContext();
3346 mlir::Location loc = toLocation();
Valentin Clement308fc3f2022-03-18 15:39:57 +01003347 auto charValue = [&](const Fortran::lower::SomeExpr *expr) {
3348 fir::ExtendedValue exv = genExprAddr(*expr, stmtCtx, &loc);
3349 return exv.match(
3350 [&](const fir::CharBoxValue &cbv) {
3351 return fir::factory::CharacterExprHelper{*builder, loc}
3352 .createEmboxChar(cbv.getAddr(), cbv.getLen());
3353 },
3354 [&](auto) {
3355 fir::emitFatalError(loc, "not a character");
3356 return mlir::Value{};
3357 });
3358 };
3359 mlir::Value selector;
3360 if (isCharSelector) {
3361 selector = charValue(expr);
3362 } else {
3363 selector = createFIRExpr(loc, expr, stmtCtx);
3364 if (isLogicalSelector)
3365 selector = builder->createConvert(loc, builder->getI1Type(), selector);
3366 }
3367 mlir::Type selectType = selector.getType();
Peter Klauslerfc97d2e2024-12-18 07:02:37 -08003368 if (selectType.isUnsignedInteger())
3369 selectType = mlir::IntegerType::get(
3370 builder->getContext(), selectType.getIntOrFloatBitWidth(),
3371 mlir::IntegerType::SignednessSemantics::Signless);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003372 llvm::SmallVector<mlir::Attribute> attrList;
3373 llvm::SmallVector<mlir::Value> valueList;
3374 llvm::SmallVector<mlir::Block *> blockList;
V Donaldson2c143342023-02-27 14:05:53 -08003375 mlir::Block *defaultBlock = parentConstruct->constructExit->block;
Valentin Clement308fc3f2022-03-18 15:39:57 +01003376 using CaseValue = Fortran::parser::Scalar<Fortran::parser::ConstantExpr>;
3377 auto addValue = [&](const CaseValue &caseValue) {
3378 const Fortran::lower::SomeExpr *expr =
3379 Fortran::semantics::GetExpr(caseValue.thing);
3380 if (isCharSelector)
3381 valueList.push_back(charValue(expr));
3382 else if (isLogicalSelector)
3383 valueList.push_back(builder->createConvert(
3384 loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx)));
Peter Klauslerfc97d2e2024-12-18 07:02:37 -08003385 else {
Valentin Clement308fc3f2022-03-18 15:39:57 +01003386 valueList.push_back(builder->createIntegerConstant(
3387 loc, selectType, *Fortran::evaluate::ToInt64(*expr)));
Peter Klauslerfc97d2e2024-12-18 07:02:37 -08003388 }
Valentin Clement308fc3f2022-03-18 15:39:57 +01003389 };
3390 for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3391 e = e->controlSuccessor) {
3392 const auto &caseStmt = e->getIf<Fortran::parser::CaseStmt>();
3393 assert(e->block && "missing CaseStmt block");
3394 const auto &caseSelector =
3395 std::get<Fortran::parser::CaseSelector>(caseStmt->t);
3396 const auto *caseValueRangeList =
3397 std::get_if<std::list<Fortran::parser::CaseValueRange>>(
3398 &caseSelector.u);
3399 if (!caseValueRangeList) {
3400 defaultBlock = e->block;
3401 continue;
3402 }
3403 for (const Fortran::parser::CaseValueRange &caseValueRange :
3404 *caseValueRangeList) {
3405 blockList.push_back(e->block);
3406 if (const auto *caseValue = std::get_if<CaseValue>(&caseValueRange.u)) {
3407 attrList.push_back(fir::PointIntervalAttr::get(context));
3408 addValue(*caseValue);
3409 continue;
3410 }
3411 const auto &caseRange =
3412 std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u);
3413 if (caseRange.lower && caseRange.upper) {
3414 attrList.push_back(fir::ClosedIntervalAttr::get(context));
3415 addValue(*caseRange.lower);
3416 addValue(*caseRange.upper);
3417 } else if (caseRange.lower) {
3418 attrList.push_back(fir::LowerBoundAttr::get(context));
3419 addValue(*caseRange.lower);
3420 } else {
3421 attrList.push_back(fir::UpperBoundAttr::get(context));
3422 addValue(*caseRange.upper);
3423 }
3424 }
3425 }
3426 // Skip a logical default block that can never be referenced.
3427 if (isLogicalSelector && attrList.size() == 2)
V Donaldson2c143342023-02-27 14:05:53 -08003428 defaultBlock = parentConstruct->constructExit->block;
Valentin Clement308fc3f2022-03-18 15:39:57 +01003429 attrList.push_back(mlir::UnitAttr::get(context));
3430 blockList.push_back(defaultBlock);
3431
V Donaldson2c143342023-02-27 14:05:53 -08003432 // Generate a fir::SelectCaseOp. Explicit branch code is better for the
3433 // LOGICAL type. The CHARACTER type does not have downstream SelectOp
3434 // support. The -no-structured-fir option can be used to force generation
3435 // of INTEGER type branch code.
3436 if (!isLogicalSelector && !isCharSelector &&
3437 !getEval().forceAsUnstructured()) {
3438 // The selector is in an ssa register. Any temps that may have been
3439 // generated while evaluating it can be cleaned up now.
3440 stmtCtx.finalizeAndReset();
Valentin Clement308fc3f2022-03-18 15:39:57 +01003441 builder->create<fir::SelectCaseOp>(loc, selector, attrList, valueList,
3442 blockList);
3443 return;
3444 }
3445
3446 // Generate a sequence of case value comparisons and branches.
3447 auto caseValue = valueList.begin();
3448 auto caseBlock = blockList.begin();
V Donaldson2c143342023-02-27 14:05:53 -08003449 for (mlir::Attribute attr : attrList) {
Christian Siggfac349a2024-04-28 22:01:42 +02003450 if (mlir::isa<mlir::UnitAttr>(attr)) {
V Donaldson2c143342023-02-27 14:05:53 -08003451 genBranch(*caseBlock++);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003452 break;
3453 }
3454 auto genCond = [&](mlir::Value rhs,
3455 mlir::arith::CmpIPredicate pred) -> mlir::Value {
3456 if (!isCharSelector)
3457 return builder->create<mlir::arith::CmpIOp>(loc, pred, selector, rhs);
3458 fir::factory::CharacterExprHelper charHelper{*builder, loc};
3459 std::pair<mlir::Value, mlir::Value> lhsVal =
3460 charHelper.createUnboxChar(selector);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003461 std::pair<mlir::Value, mlir::Value> rhsVal =
3462 charHelper.createUnboxChar(rhs);
V Donaldson2c143342023-02-27 14:05:53 -08003463 return fir::runtime::genCharCompare(*builder, loc, pred, lhsVal.first,
3464 lhsVal.second, rhsVal.first,
3465 rhsVal.second);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003466 };
3467 mlir::Block *newBlock = insertBlock(*caseBlock);
Christian Siggfac349a2024-04-28 22:01:42 +02003468 if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
Valentin Clement308fc3f2022-03-18 15:39:57 +01003469 mlir::Block *newBlock2 = insertBlock(*caseBlock);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003470 mlir::Value cond =
3471 genCond(*caseValue++, mlir::arith::CmpIPredicate::sge);
V Donaldson2c143342023-02-27 14:05:53 -08003472 genConditionalBranch(cond, newBlock, newBlock2);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003473 builder->setInsertionPointToEnd(newBlock);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003474 mlir::Value cond2 =
3475 genCond(*caseValue++, mlir::arith::CmpIPredicate::sle);
V Donaldson2c143342023-02-27 14:05:53 -08003476 genConditionalBranch(cond2, *caseBlock++, newBlock2);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003477 builder->setInsertionPointToEnd(newBlock2);
3478 continue;
3479 }
3480 mlir::arith::CmpIPredicate pred;
Christian Siggfac349a2024-04-28 22:01:42 +02003481 if (mlir::isa<fir::PointIntervalAttr>(attr)) {
Valentin Clement308fc3f2022-03-18 15:39:57 +01003482 pred = mlir::arith::CmpIPredicate::eq;
Christian Siggfac349a2024-04-28 22:01:42 +02003483 } else if (mlir::isa<fir::LowerBoundAttr>(attr)) {
Valentin Clement308fc3f2022-03-18 15:39:57 +01003484 pred = mlir::arith::CmpIPredicate::sge;
3485 } else {
Christian Siggfac349a2024-04-28 22:01:42 +02003486 assert(mlir::isa<fir::UpperBoundAttr>(attr) && "unexpected predicate");
Valentin Clement308fc3f2022-03-18 15:39:57 +01003487 pred = mlir::arith::CmpIPredicate::sle;
3488 }
3489 mlir::Value cond = genCond(*caseValue++, pred);
V Donaldson2c143342023-02-27 14:05:53 -08003490 genConditionalBranch(cond, *caseBlock++, newBlock);
Valentin Clement308fc3f2022-03-18 15:39:57 +01003491 builder->setInsertionPointToEnd(newBlock);
3492 }
3493 assert(caseValue == valueList.end() && caseBlock == blockList.end() &&
3494 "select case list mismatch");
Valentin Clement99075912022-02-01 13:49:49 +01003495 }
3496
Valentin Clementb3eb0e12022-03-08 18:47:28 +01003497 fir::ExtendedValue
3498 genAssociateSelector(const Fortran::lower::SomeExpr &selector,
3499 Fortran::lower::StatementContext &stmtCtx) {
Jean Periere5921ef2023-02-27 09:05:11 +01003500 if (lowerToHighLevelFIR())
3501 return genExprAddr(selector, stmtCtx);
Eric Schweitz1bffc752022-04-22 13:59:17 -07003502 return Fortran::lower::isArraySectionWithoutVectorSubscript(selector)
Valentin Clementb3eb0e12022-03-08 18:47:28 +01003503 ? Fortran::lower::createSomeArrayBox(*this, selector,
3504 localSymbols, stmtCtx)
3505 : genExprAddr(selector, stmtCtx);
3506 }
3507
Valentin Clement99075912022-02-01 13:49:49 +01003508 void genFIR(const Fortran::parser::AssociateConstruct &) {
Valentin Clementa49bf0a2022-03-08 22:08:02 +01003509 Fortran::lower::pft::Evaluation &eval = getEval();
V Donaldson2c143342023-02-27 14:05:53 -08003510 Fortran::lower::StatementContext stmtCtx;
3511 pushActiveConstruct(eval, stmtCtx);
Valentin Clementa49bf0a2022-03-08 22:08:02 +01003512 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
vdonaldsoncda82702024-05-03 09:11:10 -04003513 setCurrentPosition(e.position);
Valentin Clementa49bf0a2022-03-08 22:08:02 +01003514 if (auto *stmt = e.getIf<Fortran::parser::AssociateStmt>()) {
3515 if (eval.lowerAsUnstructured())
3516 maybeStartBlock(e.block);
3517 localSymbols.pushScope();
3518 for (const Fortran::parser::Association &assoc :
3519 std::get<std::list<Fortran::parser::Association>>(stmt->t)) {
3520 Fortran::semantics::Symbol &sym =
3521 *std::get<Fortran::parser::Name>(assoc.t).symbol;
3522 const Fortran::lower::SomeExpr &selector =
3523 *sym.get<Fortran::semantics::AssocEntityDetails>().expr();
Jean Perierab9c4e92023-02-07 09:22:47 +01003524 addSymbol(sym, genAssociateSelector(selector, stmtCtx));
Valentin Clementa49bf0a2022-03-08 22:08:02 +01003525 }
3526 } else if (e.getIf<Fortran::parser::EndAssociateStmt>()) {
3527 if (eval.lowerAsUnstructured())
3528 maybeStartBlock(e.block);
Valentin Clementa49bf0a2022-03-08 22:08:02 +01003529 localSymbols.popScope();
3530 } else {
3531 genFIR(e);
3532 }
3533 }
V Donaldson2c143342023-02-27 14:05:53 -08003534 popActiveConstruct();
Valentin Clement99075912022-02-01 13:49:49 +01003535 }
3536
3537 void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) {
V Donaldson2c143342023-02-27 14:05:53 -08003538 Fortran::lower::pft::Evaluation &eval = getEval();
3539 Fortran::lower::StatementContext stmtCtx;
3540 pushActiveConstruct(eval, stmtCtx);
3541 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
vdonaldsoncda82702024-05-03 09:11:10 -04003542 setCurrentPosition(e.position);
V Donaldson2c143342023-02-27 14:05:53 -08003543 if (e.getIf<Fortran::parser::BlockStmt>()) {
3544 if (eval.lowerAsUnstructured())
3545 maybeStartBlock(e.block);
V Donaldson2c143342023-02-27 14:05:53 -08003546 const Fortran::parser::CharBlock &endPosition =
3547 eval.getLastNestedEvaluation().position;
3548 localSymbols.pushScope();
Tom Eccles5aaf384b2024-09-16 12:33:37 +01003549 mlir::Value stackPtr = builder->genStackSave(toLocation());
V Donaldson2c143342023-02-27 14:05:53 -08003550 mlir::Location endLoc = genLocation(endPosition);
Tom Eccles5aaf384b2024-09-16 12:33:37 +01003551 stmtCtx.attachCleanup(
3552 [=]() { builder->genStackRestore(endLoc, stackPtr); });
V Donaldson2c143342023-02-27 14:05:53 -08003553 Fortran::semantics::Scope &scope =
3554 bridge.getSemanticsContext().FindScope(endPosition);
3555 scopeBlockIdMap.try_emplace(&scope, ++blockId);
3556 Fortran::lower::AggregateStoreMap storeMap;
3557 for (const Fortran::lower::pft::Variable &var :
jeanPerierbfcd0532023-10-17 09:11:53 +02003558 Fortran::lower::pft::getScopeVariableList(scope)) {
3559 // Do no instantiate again variables from the block host
3560 // that appears in specification of block variables.
3561 if (!var.hasSymbol() || !lookupSymbol(var.getSymbol()))
3562 instantiateVar(var, storeMap);
3563 }
V Donaldson2c143342023-02-27 14:05:53 -08003564 } else if (e.getIf<Fortran::parser::EndBlockStmt>()) {
3565 if (eval.lowerAsUnstructured())
3566 maybeStartBlock(e.block);
V Donaldson2c143342023-02-27 14:05:53 -08003567 localSymbols.popScope();
3568 } else {
3569 genFIR(e);
3570 }
3571 }
3572 popActiveConstruct();
Valentin Clement99075912022-02-01 13:49:49 +01003573 }
3574
3575 void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) {
Pete Steinfeld5db47792023-10-16 12:37:57 -07003576 TODO(toLocation(), "coarray: ChangeTeamConstruct");
Valentin Clement99075912022-02-01 13:49:49 +01003577 }
Valentin Clement99075912022-02-01 13:49:49 +01003578 void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) {
Pete Steinfeld5db47792023-10-16 12:37:57 -07003579 TODO(toLocation(), "coarray: ChangeTeamStmt");
Valentin Clement99075912022-02-01 13:49:49 +01003580 }
Valentin Clement99075912022-02-01 13:49:49 +01003581 void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) {
Pete Steinfeld5db47792023-10-16 12:37:57 -07003582 TODO(toLocation(), "coarray: EndChangeTeamStmt");
Valentin Clement99075912022-02-01 13:49:49 +01003583 }
3584
3585 void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) {
Valentin Clementfe252f82022-03-22 15:40:32 +01003586 setCurrentPositionAt(criticalConstruct);
Pete Steinfeld5db47792023-10-16 12:37:57 -07003587 TODO(toLocation(), "coarray: CriticalConstruct");
Valentin Clement99075912022-02-01 13:49:49 +01003588 }
Valentin Clement99075912022-02-01 13:49:49 +01003589 void genFIR(const Fortran::parser::CriticalStmt &) {
Pete Steinfeld5db47792023-10-16 12:37:57 -07003590 TODO(toLocation(), "coarray: CriticalStmt");
Valentin Clement99075912022-02-01 13:49:49 +01003591 }
Valentin Clement99075912022-02-01 13:49:49 +01003592 void genFIR(const Fortran::parser::EndCriticalStmt &) {
Pete Steinfeld5db47792023-10-16 12:37:57 -07003593 TODO(toLocation(), "coarray: EndCriticalStmt");
Valentin Clement99075912022-02-01 13:49:49 +01003594 }
3595
3596 void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) {
Valentin Clementfe252f82022-03-22 15:40:32 +01003597 setCurrentPositionAt(selectRankConstruct);
jeanPerierd1aa9ba2024-06-03 17:20:07 +02003598 genCaseOrRankConstruct();
Valentin Clement99075912022-02-01 13:49:49 +01003599 }
jeanPerierd1aa9ba2024-06-03 17:20:07 +02003600
3601 void genFIR(const Fortran::parser::SelectRankStmt &selectRankStmt) {
3602 // Generate a fir.select_case with the selector rank. The RANK(*) case,
3603 // if any, is handles with a conditional branch before the fir.select_case.
3604 mlir::Type rankType = builder->getIntegerType(8);
3605 mlir::MLIRContext *context = builder->getContext();
3606 mlir::Location loc = toLocation();
3607 // Build block list for fir.select_case, and identify RANK(*) block, if any.
3608 // Default block must be placed last in the fir.select_case block list.
3609 mlir::Block *rankStarBlock = nullptr;
3610 Fortran::lower::pft::Evaluation &eval = getEval();
3611 mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
3612 llvm::SmallVector<mlir::Attribute> attrList;
3613 llvm::SmallVector<mlir::Value> valueList;
3614 llvm::SmallVector<mlir::Block *> blockList;
3615 for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3616 e = e->controlSuccessor) {
3617 if (const auto *rankCaseStmt =
3618 e->getIf<Fortran::parser::SelectRankCaseStmt>()) {
3619 const auto &rank = std::get<Fortran::parser::SelectRankCaseStmt::Rank>(
3620 rankCaseStmt->t);
3621 assert(e->block && "missing SelectRankCaseStmt block");
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07003622 Fortran::common::visit(
jeanPerierd1aa9ba2024-06-03 17:20:07 +02003623 Fortran::common::visitors{
3624 [&](const Fortran::parser::ScalarIntConstantExpr &rankExpr) {
3625 blockList.emplace_back(e->block);
3626 attrList.emplace_back(fir::PointIntervalAttr::get(context));
3627 std::optional<std::int64_t> rankCst =
3628 Fortran::evaluate::ToInt64(
3629 Fortran::semantics::GetExpr(rankExpr));
3630 assert(rankCst.has_value() &&
3631 "rank expr must be constant integer");
3632 valueList.emplace_back(
3633 builder->createIntegerConstant(loc, rankType, *rankCst));
3634 },
3635 [&](const Fortran::parser::Star &) {
3636 rankStarBlock = e->block;
3637 },
3638 [&](const Fortran::parser::Default &) {
3639 defaultBlock = e->block;
3640 }},
3641 rank.u);
3642 }
3643 }
3644 attrList.push_back(mlir::UnitAttr::get(context));
3645 blockList.push_back(defaultBlock);
3646
3647 // Lower selector.
3648 assert(!activeConstructStack.empty() && "must be inside construct");
3649 assert(!activeConstructStack.back().selector &&
3650 "selector should not yet be set");
3651 Fortran::lower::StatementContext &stmtCtx =
3652 activeConstructStack.back().stmtCtx;
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07003653 const Fortran::lower::SomeExpr *selectorExpr = Fortran::common::visit(
3654 [](const auto &x) { return Fortran::semantics::GetExpr(x); },
3655 std::get<Fortran::parser::Selector>(selectRankStmt.t).u);
jeanPerierd1aa9ba2024-06-03 17:20:07 +02003656 assert(selectorExpr && "failed to retrieve selector expr");
3657 hlfir::Entity selector = Fortran::lower::convertExprToHLFIR(
3658 loc, *this, *selectorExpr, localSymbols, stmtCtx);
3659 activeConstructStack.back().selector = selector;
3660
3661 // Deal with assumed-size first. They must fall into RANK(*) if present, or
3662 // the default case (F'2023 11.1.10.2.). The selector cannot be an
3663 // assumed-size if it is allocatable or pointer, so the check is skipped.
3664 if (!Fortran::evaluate::IsAllocatableOrPointerObject(*selectorExpr)) {
3665 mlir::Value isAssumedSize = builder->create<fir::IsAssumedSizeOp>(
3666 loc, builder->getI1Type(), selector);
3667 // Create new block to hold the fir.select_case for the non assumed-size
3668 // cases.
3669 mlir::Block *selectCaseBlock = insertBlock(blockList[0]);
3670 mlir::Block *assumedSizeBlock =
3671 rankStarBlock ? rankStarBlock : defaultBlock;
3672 builder->create<mlir::cf::CondBranchOp>(loc, isAssumedSize,
3673 assumedSizeBlock, std::nullopt,
3674 selectCaseBlock, std::nullopt);
3675 startBlock(selectCaseBlock);
3676 }
3677 // Create fir.select_case for the other rank cases.
3678 mlir::Value rank = builder->create<fir::BoxRankOp>(loc, rankType, selector);
3679 stmtCtx.finalizeAndReset();
3680 builder->create<fir::SelectCaseOp>(loc, rank, attrList, valueList,
3681 blockList);
Valentin Clement99075912022-02-01 13:49:49 +01003682 }
jeanPerierd1aa9ba2024-06-03 17:20:07 +02003683
3684 // Get associating entity symbol inside case statement scope.
3685 static const Fortran::semantics::Symbol &
3686 getAssociatingEntitySymbol(const Fortran::semantics::Scope &scope) {
3687 const Fortran::semantics::Symbol *assocSym = nullptr;
3688 for (const auto &sym : scope.GetSymbols()) {
3689 if (sym->has<Fortran::semantics::AssocEntityDetails>()) {
3690 assert(!assocSym &&
3691 "expect only one associating entity symbol in this scope");
3692 assocSym = &*sym;
3693 }
3694 }
3695 assert(assocSym && "should contain associating entity symbol");
3696 return *assocSym;
3697 }
3698
3699 void genFIR(const Fortran::parser::SelectRankCaseStmt &stmt) {
3700 assert(!activeConstructStack.empty() &&
3701 "must be inside select rank construct");
3702 // Pop previous associating entity mapping, if any, and push scope for new
3703 // mapping.
3704 if (activeConstructStack.back().pushedScope)
3705 localSymbols.popScope();
3706 localSymbols.pushScope();
3707 activeConstructStack.back().pushedScope = true;
3708 const Fortran::semantics::Symbol &assocEntitySymbol =
3709 getAssociatingEntitySymbol(
3710 bridge.getSemanticsContext().FindScope(getEval().position));
3711 const auto &details =
3712 assocEntitySymbol.get<Fortran::semantics::AssocEntityDetails>();
3713 assert(!activeConstructStack.empty() &&
3714 activeConstructStack.back().selector.has_value() &&
3715 "selector must have been created");
3716 // Get lowered value for the selector.
3717 hlfir::Entity selector = *activeConstructStack.back().selector;
3718 assert(selector.isVariable() && "assumed-rank selector are variables");
3719 // Cook selector mlir::Value according to rank case and map it to
3720 // associating entity symbol.
3721 Fortran::lower::StatementContext stmtCtx;
3722 mlir::Location loc = toLocation();
3723 if (details.IsAssumedRank()) {
3724 fir::ExtendedValue selectorExv = Fortran::lower::translateToExtendedValue(
3725 loc, *builder, selector, stmtCtx);
3726 addSymbol(assocEntitySymbol, selectorExv);
3727 } else if (details.IsAssumedSize()) {
3728 // Create rank-1 assumed-size from descriptor. Assumed-size are contiguous
3729 // so a new entity can be built from scratch using the base address, type
3730 // parameters and dynamic type. The selector cannot be a
3731 // POINTER/ALLOCATBLE as per F'2023 C1160.
3732 fir::ExtendedValue newExv;
3733 llvm::SmallVector assumeSizeExtents{
3734 builder->createMinusOneInteger(loc, builder->getIndexType())};
3735 mlir::Value baseAddr =
3736 hlfir::genVariableRawAddress(loc, *builder, selector);
3737 mlir::Type eleType =
3738 fir::unwrapSequenceType(fir::unwrapRefType(baseAddr.getType()));
3739 mlir::Type rank1Type =
3740 fir::ReferenceType::get(builder->getVarLenSeqTy(eleType, 1));
3741 baseAddr = builder->createConvert(loc, rank1Type, baseAddr);
3742 if (selector.isCharacter()) {
3743 mlir::Value len = hlfir::genCharLength(loc, *builder, selector);
3744 newExv = fir::CharArrayBoxValue{baseAddr, len, assumeSizeExtents};
3745 } else if (selector.isDerivedWithLengthParameters()) {
3746 TODO(loc, "RANK(*) with parameterized derived type selector");
3747 } else if (selector.isPolymorphic()) {
3748 TODO(loc, "RANK(*) with polymorphic selector");
3749 } else {
3750 // Simple intrinsic or derived type.
3751 newExv = fir::ArrayBoxValue{baseAddr, assumeSizeExtents};
3752 }
3753 addSymbol(assocEntitySymbol, newExv);
3754 } else {
3755 int rank = details.rank().value();
3756 auto boxTy =
3757 mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(selector.getType()));
3758 mlir::Type newBoxType = boxTy.getBoxTypeWithNewShape(rank);
3759 if (fir::isa_ref_type(selector.getType()))
3760 newBoxType = fir::ReferenceType::get(newBoxType);
3761 // Give rank info to value via cast, and get rid of the box if not needed
3762 // (simple scalars, contiguous arrays... This is done by
3763 // translateVariableToExtendedValue).
3764 hlfir::Entity rankedBox{
3765 builder->createConvert(loc, newBoxType, selector)};
3766 bool isSimplyContiguous = Fortran::evaluate::IsSimplyContiguous(
3767 assocEntitySymbol, getFoldingContext());
3768 fir::ExtendedValue newExv = Fortran::lower::translateToExtendedValue(
3769 loc, *builder, rankedBox, stmtCtx, isSimplyContiguous);
3770
3771 // Non deferred length parameters of character allocatable/pointer
3772 // MutableBoxValue should be properly set before binding it to a symbol in
3773 // order to get correct assignment semantics.
3774 if (const fir::MutableBoxValue *mutableBox =
3775 newExv.getBoxOf<fir::MutableBoxValue>()) {
3776 if (selector.isCharacter()) {
3777 auto dynamicType =
3778 Fortran::evaluate::DynamicType::From(assocEntitySymbol);
3779 if (!dynamicType.value().HasDeferredTypeParameter()) {
3780 llvm::SmallVector<mlir::Value> lengthParams;
3781 hlfir::genLengthParameters(loc, *builder, selector, lengthParams);
3782 newExv = fir::MutableBoxValue{rankedBox, lengthParams,
3783 mutableBox->getMutableProperties()};
3784 }
3785 }
3786 }
3787 addSymbol(assocEntitySymbol, newExv);
3788 }
3789 // Statements inside rank case are lowered by SelectRankConstruct visit.
Valentin Clement99075912022-02-01 13:49:49 +01003790 }
3791
3792 void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) {
Valentin Clementf677c5e2022-11-14 10:46:53 +01003793 mlir::MLIRContext *context = builder->getContext();
3794 Fortran::lower::StatementContext stmtCtx;
3795 fir::ExtendedValue selector;
3796 llvm::SmallVector<mlir::Attribute> attrList;
3797 llvm::SmallVector<mlir::Block *> blockList;
3798 unsigned typeGuardIdx = 0;
Valentin Clementa459a242023-01-19 17:32:02 +01003799 std::size_t defaultAttrPos = std::numeric_limits<size_t>::max();
Valentin Clementf677c5e2022-11-14 10:46:53 +01003800 bool hasLocalScope = false;
Valentin Clementb0de8722023-02-16 09:05:12 +01003801 llvm::SmallVector<const Fortran::semantics::Scope *> typeCaseScopes;
3802
3803 const auto &typeCaseList =
3804 std::get<std::list<Fortran::parser::SelectTypeConstruct::TypeCase>>(
3805 selectTypeConstruct.t);
3806 for (const auto &typeCase : typeCaseList) {
3807 const auto &stmt =
3808 std::get<Fortran::parser::Statement<Fortran::parser::TypeGuardStmt>>(
3809 typeCase.t);
3810 const Fortran::semantics::Scope &scope =
3811 bridge.getSemanticsContext().FindScope(stmt.source);
3812 typeCaseScopes.push_back(&scope);
3813 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01003814
V Donaldson2c143342023-02-27 14:05:53 -08003815 pushActiveConstruct(getEval(), stmtCtx);
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05003816 llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
3817 collectFinalEvaluations(getEval(), exits, fallThroughs);
3818 Fortran::lower::pft::Evaluation &constructExit = *getEval().constructExit;
3819
Valentin Clementf677c5e2022-11-14 10:46:53 +01003820 for (Fortran::lower::pft::Evaluation &eval :
3821 getEval().getNestedEvaluations()) {
vdonaldsoncda82702024-05-03 09:11:10 -04003822 setCurrentPosition(eval.position);
3823 mlir::Location loc = toLocation();
Valentin Clementf677c5e2022-11-14 10:46:53 +01003824 if (auto *selectTypeStmt =
3825 eval.getIf<Fortran::parser::SelectTypeStmt>()) {
V Donaldson609b7892023-01-03 10:31:30 -08003826 // A genFIR(SelectTypeStmt) call would have unwanted side effects.
3827 maybeStartBlock(eval.block);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003828 // Retrieve the selector
3829 const auto &s = std::get<Fortran::parser::Selector>(selectTypeStmt->t);
3830 if (const auto *v = std::get_if<Fortran::parser::Variable>(&s.u))
3831 selector = genExprBox(loc, *Fortran::semantics::GetExpr(*v), stmtCtx);
Valentin Clementf5cca3c2023-02-16 20:59:54 +01003832 else if (const auto *e = std::get_if<Fortran::parser::Expr>(&s.u))
3833 selector = genExprBox(loc, *Fortran::semantics::GetExpr(*e), stmtCtx);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003834
3835 // Going through the controlSuccessor first to create the
3836 // fir.select_type operation.
3837 mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
3838 for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3839 e = e->controlSuccessor) {
3840 const auto &typeGuardStmt =
3841 e->getIf<Fortran::parser::TypeGuardStmt>();
3842 const auto &guard =
3843 std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
3844 assert(e->block && "missing TypeGuardStmt block");
3845 // CLASS DEFAULT
3846 if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
3847 defaultBlock = e->block;
Valentin Clementa459a242023-01-19 17:32:02 +01003848 // Keep track of the actual position of the CLASS DEFAULT type guard
3849 // in the SELECT TYPE construct.
3850 defaultAttrPos = attrList.size();
Valentin Clementf677c5e2022-11-14 10:46:53 +01003851 continue;
3852 }
3853
3854 blockList.push_back(e->block);
3855 if (const auto *typeSpec =
3856 std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
3857 // TYPE IS
3858 mlir::Type ty;
3859 if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
3860 typeSpec->u)) {
3861 const Fortran::semantics::IntrinsicTypeSpec *intrinsic =
3862 typeSpec->declTypeSpec->AsIntrinsic();
3863 int kind =
3864 Fortran::evaluate::ToInt64(intrinsic->kind()).value_or(kind);
3865 llvm::SmallVector<Fortran::lower::LenParameterTy> params;
Valentin Clementf677c5e2022-11-14 10:46:53 +01003866 ty = genType(intrinsic->category(), kind, params);
3867 } else {
3868 const Fortran::semantics::DerivedTypeSpec *derived =
3869 typeSpec->declTypeSpec->AsDerived();
3870 ty = genType(*derived);
3871 }
3872 attrList.push_back(fir::ExactTypeAttr::get(ty));
3873 } else if (const auto *derived =
3874 std::get_if<Fortran::parser::DerivedTypeSpec>(
3875 &guard.u)) {
3876 // CLASS IS
3877 assert(derived->derivedTypeSpec && "derived type spec is null");
3878 mlir::Type ty = genType(*(derived->derivedTypeSpec));
3879 attrList.push_back(fir::SubclassAttr::get(ty));
3880 }
3881 }
3882 attrList.push_back(mlir::UnitAttr::get(context));
3883 blockList.push_back(defaultBlock);
3884 builder->create<fir::SelectTypeOp>(loc, fir::getBase(selector),
3885 attrList, blockList);
Valentin Clementa459a242023-01-19 17:32:02 +01003886
3887 // If the actual position of CLASS DEFAULT type guard is not the last
3888 // one, it needs to be put back at its correct position for the rest of
3889 // the processing. TypeGuardStmt are processed in the same order they
3890 // appear in the Fortran code.
3891 if (defaultAttrPos < attrList.size() - 1) {
3892 auto attrIt = attrList.begin();
3893 attrIt = attrIt + defaultAttrPos;
3894 auto blockIt = blockList.begin();
3895 blockIt = blockIt + defaultAttrPos;
3896 attrList.insert(attrIt, mlir::UnitAttr::get(context));
3897 blockList.insert(blockIt, defaultBlock);
3898 attrList.pop_back();
3899 blockList.pop_back();
3900 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01003901 } else if (auto *typeGuardStmt =
3902 eval.getIf<Fortran::parser::TypeGuardStmt>()) {
3903 // Map the type guard local symbol for the selector to a more precise
3904 // typed entity in the TypeGuardStmt when necessary.
V Donaldson609b7892023-01-03 10:31:30 -08003905 genFIR(eval);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003906 const auto &guard =
3907 std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
3908 if (hasLocalScope)
3909 localSymbols.popScope();
3910 localSymbols.pushScope();
3911 hasLocalScope = true;
3912 assert(attrList.size() >= typeGuardIdx &&
3913 "TypeGuard attribute missing");
3914 mlir::Attribute typeGuardAttr = attrList[typeGuardIdx];
3915 mlir::Block *typeGuardBlock = blockList[typeGuardIdx];
Valentin Clementf677c5e2022-11-14 10:46:53 +01003916 mlir::OpBuilder::InsertPoint crtInsPt = builder->saveInsertionPoint();
3917 builder->setInsertionPointToStart(typeGuardBlock);
3918
3919 auto addAssocEntitySymbol = [&](fir::ExtendedValue exv) {
Valentin Clementb0de8722023-02-16 09:05:12 +01003920 for (auto &symbol : typeCaseScopes[typeGuardIdx]->GetSymbols()) {
Valentin Clementf677c5e2022-11-14 10:46:53 +01003921 if (symbol->GetUltimate()
3922 .detailsIf<Fortran::semantics::AssocEntityDetails>()) {
Jean Perierab9c4e92023-02-07 09:22:47 +01003923 addSymbol(symbol, exv);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003924 break;
3925 }
3926 }
3927 };
3928
Valentin Clement9379ca02022-12-15 12:02:11 +01003929 mlir::Type baseTy = fir::getBase(selector).getType();
3930 bool isPointer = fir::isPointerType(baseTy);
3931 bool isAllocatable = fir::isAllocatableType(baseTy);
3932 bool isArray =
Christian Siggfac349a2024-04-28 22:01:42 +02003933 mlir::isa<fir::SequenceType>(fir::dyn_cast_ptrOrBoxEleTy(baseTy));
Valentin Clement9379ca02022-12-15 12:02:11 +01003934 const fir::BoxValue *selectorBox = selector.getBoxOf<fir::BoxValue>();
Valentin Clementf677c5e2022-11-14 10:46:53 +01003935 if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
3936 // CLASS DEFAULT
3937 addAssocEntitySymbol(selector);
3938 } else if (const auto *typeSpec =
3939 std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
3940 // TYPE IS
3941 fir::ExactTypeAttr attr =
Christian Siggfac349a2024-04-28 22:01:42 +02003942 mlir::dyn_cast<fir::ExactTypeAttr>(typeGuardAttr);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003943 mlir::Value exactValue;
Valentin Clement9379ca02022-12-15 12:02:11 +01003944 mlir::Type addrTy = attr.getType();
3945 if (isArray) {
Christian Siggfac349a2024-04-28 22:01:42 +02003946 auto seqTy = mlir::dyn_cast<fir::SequenceType>(
3947 fir::dyn_cast_ptrOrBoxEleTy(baseTy));
Valentin Clement9379ca02022-12-15 12:02:11 +01003948 addrTy = fir::SequenceType::get(seqTy.getShape(), attr.getType());
3949 }
3950 if (isPointer)
3951 addrTy = fir::PointerType::get(addrTy);
3952 if (isAllocatable)
3953 addrTy = fir::HeapType::get(addrTy);
Valentin Clementf677c5e2022-11-14 10:46:53 +01003954 if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
3955 typeSpec->u)) {
Valentin Clement9379ca02022-12-15 12:02:11 +01003956 mlir::Type refTy = fir::ReferenceType::get(addrTy);
3957 if (isPointer || isAllocatable)
3958 refTy = addrTy;
Valentin Clementf677c5e2022-11-14 10:46:53 +01003959 exactValue = builder->create<fir::BoxAddrOp>(
Valentin Clement9379ca02022-12-15 12:02:11 +01003960 loc, refTy, fir::getBase(selector));
Valentin Clementc44292f2022-12-02 09:52:06 +01003961 const Fortran::semantics::IntrinsicTypeSpec *intrinsic =
3962 typeSpec->declTypeSpec->AsIntrinsic();
Valentin Clement9379ca02022-12-15 12:02:11 +01003963 if (isArray) {
3964 mlir::Value exact = builder->create<fir::ConvertOp>(
3965 loc, fir::BoxType::get(addrTy), fir::getBase(selector));
3966 addAssocEntitySymbol(selectorBox->clone(exact));
3967 } else if (intrinsic->category() ==
3968 Fortran::common::TypeCategory::Character) {
Christian Siggfac349a2024-04-28 22:01:42 +02003969 auto charTy = mlir::dyn_cast<fir::CharacterType>(attr.getType());
Valentin Clementc44292f2022-12-02 09:52:06 +01003970 mlir::Value charLen =
3971 fir::factory::CharacterExprHelper(*builder, loc)
3972 .readLengthFromBox(fir::getBase(selector), charTy);
3973 addAssocEntitySymbol(fir::CharBoxValue(exactValue, charLen));
3974 } else {
3975 addAssocEntitySymbol(exactValue);
3976 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01003977 } else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
3978 typeSpec->u)) {
3979 exactValue = builder->create<fir::ConvertOp>(
Valentin Clement9379ca02022-12-15 12:02:11 +01003980 loc, fir::BoxType::get(addrTy), fir::getBase(selector));
3981 addAssocEntitySymbol(selectorBox->clone(exactValue));
Valentin Clementf677c5e2022-11-14 10:46:53 +01003982 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01003983 } else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
3984 guard.u)) {
3985 // CLASS IS
Christian Siggfac349a2024-04-28 22:01:42 +02003986 fir::SubclassAttr attr =
3987 mlir::dyn_cast<fir::SubclassAttr>(typeGuardAttr);
Valentin Clement9379ca02022-12-15 12:02:11 +01003988 mlir::Type addrTy = attr.getType();
3989 if (isArray) {
Christian Siggfac349a2024-04-28 22:01:42 +02003990 auto seqTy = mlir::dyn_cast<fir::SequenceType>(
3991 fir::dyn_cast_ptrOrBoxEleTy(baseTy));
Valentin Clement9379ca02022-12-15 12:02:11 +01003992 addrTy = fir::SequenceType::get(seqTy.getShape(), attr.getType());
3993 }
3994 if (isPointer)
3995 addrTy = fir::PointerType::get(addrTy);
3996 if (isAllocatable)
3997 addrTy = fir::HeapType::get(addrTy);
3998 mlir::Type classTy = fir::ClassType::get(addrTy);
3999 if (classTy == baseTy) {
4000 addAssocEntitySymbol(selector);
4001 } else {
4002 mlir::Value derived = builder->create<fir::ConvertOp>(
4003 loc, classTy, fir::getBase(selector));
4004 addAssocEntitySymbol(selectorBox->clone(derived));
4005 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01004006 }
4007 builder->restoreInsertionPoint(crtInsPt);
4008 ++typeGuardIdx;
4009 } else if (eval.getIf<Fortran::parser::EndSelectStmt>()) {
Carlos Eduardo Seo9ceb0a72023-05-20 05:16:50 +00004010 maybeStartBlock(eval.block);
Valentin Clementf677c5e2022-11-14 10:46:53 +01004011 if (hasLocalScope)
4012 localSymbols.popScope();
V Donaldson609b7892023-01-03 10:31:30 -08004013 } else {
4014 genFIR(eval);
Valentin Clementf677c5e2022-11-14 10:46:53 +01004015 }
Krzysztof Parzyszekc1b5b7c2024-05-21 08:19:54 -05004016 if (blockIsUnterminated()) {
4017 if (llvm::is_contained(exits, &eval))
4018 genConstructExitBranch(constructExit);
4019 else if (llvm::is_contained(fallThroughs, &eval))
4020 genBranch(eval.lexicalSuccessor->block);
4021 }
Valentin Clementf677c5e2022-11-14 10:46:53 +01004022 }
V Donaldson2c143342023-02-27 14:05:53 -08004023 popActiveConstruct();
Valentin Clement99075912022-02-01 13:49:49 +01004024 }
4025
4026 //===--------------------------------------------------------------------===//
4027 // IO statements (see io.h)
4028 //===--------------------------------------------------------------------===//
4029
4030 void genFIR(const Fortran::parser::BackspaceStmt &stmt) {
Valentin Clement46f46a32022-03-02 17:58:38 +01004031 mlir::Value iostat = genBackspaceStatement(*this, stmt);
4032 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004033 }
Valentin Clement99075912022-02-01 13:49:49 +01004034 void genFIR(const Fortran::parser::CloseStmt &stmt) {
Valentin Clementdb48f7b2022-03-02 17:55:10 +01004035 mlir::Value iostat = genCloseStatement(*this, stmt);
4036 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004037 }
Valentin Clement99075912022-02-01 13:49:49 +01004038 void genFIR(const Fortran::parser::EndfileStmt &stmt) {
Valentin Clement46f46a32022-03-02 17:58:38 +01004039 mlir::Value iostat = genEndfileStatement(*this, stmt);
4040 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004041 }
Valentin Clement99075912022-02-01 13:49:49 +01004042 void genFIR(const Fortran::parser::FlushStmt &stmt) {
Valentin Clement46f46a32022-03-02 17:58:38 +01004043 mlir::Value iostat = genFlushStatement(*this, stmt);
4044 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004045 }
Valentin Clement99075912022-02-01 13:49:49 +01004046 void genFIR(const Fortran::parser::InquireStmt &stmt) {
Valentin Clement7e32cad2022-03-02 18:02:41 +01004047 mlir::Value iostat = genInquireStatement(*this, stmt);
4048 if (const auto *specs =
4049 std::get_if<std::list<Fortran::parser::InquireSpec>>(&stmt.u))
4050 genIoConditionBranches(getEval(), *specs, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004051 }
Valentin Clement99075912022-02-01 13:49:49 +01004052 void genFIR(const Fortran::parser::OpenStmt &stmt) {
Valentin Clementdb48f7b2022-03-02 17:55:10 +01004053 mlir::Value iostat = genOpenStatement(*this, stmt);
4054 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004055 }
Valentin Clement99075912022-02-01 13:49:49 +01004056 void genFIR(const Fortran::parser::PrintStmt &stmt) {
Valentin Clement8c22cb82022-03-01 21:47:40 +01004057 genPrintStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01004058 }
Valentin Clement99075912022-02-01 13:49:49 +01004059 void genFIR(const Fortran::parser::ReadStmt &stmt) {
Valentin Clement8c22cb82022-03-01 21:47:40 +01004060 mlir::Value iostat = genReadStatement(*this, stmt);
4061 genIoConditionBranches(getEval(), stmt.controls, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004062 }
Valentin Clement99075912022-02-01 13:49:49 +01004063 void genFIR(const Fortran::parser::RewindStmt &stmt) {
Valentin Clement46f46a32022-03-02 17:58:38 +01004064 mlir::Value iostat = genRewindStatement(*this, stmt);
4065 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004066 }
Valentin Clement99075912022-02-01 13:49:49 +01004067 void genFIR(const Fortran::parser::WaitStmt &stmt) {
Valentin Clement46f46a32022-03-02 17:58:38 +01004068 mlir::Value iostat = genWaitStatement(*this, stmt);
4069 genIoConditionBranches(getEval(), stmt.v, iostat);
Valentin Clement99075912022-02-01 13:49:49 +01004070 }
Valentin Clement99075912022-02-01 13:49:49 +01004071 void genFIR(const Fortran::parser::WriteStmt &stmt) {
Valentin Clement8c22cb82022-03-01 21:47:40 +01004072 mlir::Value iostat = genWriteStatement(*this, stmt);
4073 genIoConditionBranches(getEval(), stmt.controls, iostat);
4074 }
4075
4076 template <typename A>
4077 void genIoConditionBranches(Fortran::lower::pft::Evaluation &eval,
4078 const A &specList, mlir::Value iostat) {
4079 if (!iostat)
4080 return;
4081
V Donaldson2c143342023-02-27 14:05:53 -08004082 Fortran::parser::Label endLabel{};
4083 Fortran::parser::Label eorLabel{};
4084 Fortran::parser::Label errLabel{};
V Donaldson5e521582023-03-31 09:36:16 -07004085 bool hasIostat{};
Valentin Clement8c22cb82022-03-01 21:47:40 +01004086 for (const auto &spec : specList) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07004087 Fortran::common::visit(
V Donaldson5e521582023-03-31 09:36:16 -07004088 Fortran::common::visitors{
4089 [&](const Fortran::parser::EndLabel &label) {
4090 endLabel = label.v;
4091 },
4092 [&](const Fortran::parser::EorLabel &label) {
4093 eorLabel = label.v;
4094 },
4095 [&](const Fortran::parser::ErrLabel &label) {
4096 errLabel = label.v;
4097 },
4098 [&](const Fortran::parser::StatVariable &) { hasIostat = true; },
4099 [](const auto &) {}},
4100 spec.u);
Valentin Clement8c22cb82022-03-01 21:47:40 +01004101 }
V Donaldson2c143342023-02-27 14:05:53 -08004102 if (!endLabel && !eorLabel && !errLabel)
Valentin Clement8c22cb82022-03-01 21:47:40 +01004103 return;
4104
V Donaldson5e521582023-03-31 09:36:16 -07004105 // An ERR specifier branch is taken on any positive error value rather than
4106 // some single specific value. If ERR and IOSTAT specifiers are given and
4107 // END and EOR specifiers are allowed, the latter two specifiers must have
4108 // explicit branch targets to allow the ERR branch to be implemented as a
4109 // default/else target. A label=0 target for an absent END or EOR specifier
4110 // indicates that these specifiers have a fallthrough target. END and EOR
4111 // specifiers may appear on READ and WAIT statements.
4112 bool allSpecifiersRequired = errLabel && hasIostat &&
4113 (eval.isA<Fortran::parser::ReadStmt>() ||
4114 eval.isA<Fortran::parser::WaitStmt>());
V Donaldson2c143342023-02-27 14:05:53 -08004115 mlir::Value selector =
4116 builder->createConvert(toLocation(), builder->getIndexType(), iostat);
V Donaldson5e521582023-03-31 09:36:16 -07004117 llvm::SmallVector<int64_t> valueList;
V Donaldson2c143342023-02-27 14:05:53 -08004118 llvm::SmallVector<Fortran::parser::Label> labelList;
V Donaldson5e521582023-03-31 09:36:16 -07004119 if (eorLabel || allSpecifiersRequired) {
4120 valueList.push_back(Fortran::runtime::io::IostatEor);
4121 labelList.push_back(eorLabel ? eorLabel : 0);
Valentin Clement8c22cb82022-03-01 21:47:40 +01004122 }
V Donaldson5e521582023-03-31 09:36:16 -07004123 if (endLabel || allSpecifiersRequired) {
4124 valueList.push_back(Fortran::runtime::io::IostatEnd);
4125 labelList.push_back(endLabel ? endLabel : 0);
Valentin Clement8c22cb82022-03-01 21:47:40 +01004126 }
V Donaldson2c143342023-02-27 14:05:53 -08004127 if (errLabel) {
V Donaldson5e521582023-03-31 09:36:16 -07004128 // Must be last. Value 0 is interpreted as any positive value, or
4129 // equivalently as any value other than 0, IostatEor, or IostatEnd.
4130 valueList.push_back(0);
V Donaldson2c143342023-02-27 14:05:53 -08004131 labelList.push_back(errLabel);
Valentin Clement8c22cb82022-03-01 21:47:40 +01004132 }
V Donaldson5e521582023-03-31 09:36:16 -07004133 genMultiwayBranch(selector, valueList, labelList, eval.nonNopSuccessor());
Valentin Clement99075912022-02-01 13:49:49 +01004134 }
4135
4136 //===--------------------------------------------------------------------===//
4137 // Memory allocation and deallocation
4138 //===--------------------------------------------------------------------===//
4139
4140 void genFIR(const Fortran::parser::AllocateStmt &stmt) {
Valentin Clementc5cf1b92022-03-07 21:22:28 +01004141 Fortran::lower::genAllocateStmt(*this, stmt, toLocation());
Valentin Clement99075912022-02-01 13:49:49 +01004142 }
4143
4144 void genFIR(const Fortran::parser::DeallocateStmt &stmt) {
Valentin Clementc5cf1b92022-03-07 21:22:28 +01004145 Fortran::lower::genDeallocateStmt(*this, stmt, toLocation());
Valentin Clement99075912022-02-01 13:49:49 +01004146 }
4147
Valentin Clement72276bd2022-03-10 20:19:57 +01004148 /// Nullify pointer object list
4149 ///
4150 /// For each pointer object, reset the pointer to a disassociated status.
4151 /// We do this by setting each pointer to null.
Valentin Clement99075912022-02-01 13:49:49 +01004152 void genFIR(const Fortran::parser::NullifyStmt &stmt) {
Valentin Clement72276bd2022-03-10 20:19:57 +01004153 mlir::Location loc = toLocation();
4154 for (auto &pointerObject : stmt.v) {
4155 const Fortran::lower::SomeExpr *expr =
4156 Fortran::semantics::GetExpr(pointerObject);
4157 assert(expr);
Daniel Chenaf092192023-11-22 11:51:12 -05004158 if (Fortran::evaluate::IsProcedurePointer(*expr)) {
4159 Fortran::lower::StatementContext stmtCtx;
4160 hlfir::Entity pptr = Fortran::lower::convertExprToHLFIR(
4161 loc, *this, *expr, localSymbols, stmtCtx);
4162 auto boxTy{
4163 Fortran::lower::getUntypedBoxProcType(builder->getContext())};
4164 hlfir::Entity nullBoxProc(
4165 fir::factory::createNullBoxProc(*builder, loc, boxTy));
4166 builder->createStoreWithConvert(loc, nullBoxProc, pptr);
Daniel Chenb081e9d2024-02-09 10:56:57 -05004167 } else {
4168 fir::MutableBoxValue box = genExprMutableBox(loc, *expr);
4169 fir::factory::disassociateMutableBox(*builder, loc, box);
Valentin Clement (バレンタイン クレメン)91658482025-01-03 14:37:14 -08004170 cuf::genPointerSync(box.getAddr(), *builder);
Daniel Chenaf092192023-11-22 11:51:12 -05004171 }
Valentin Clement72276bd2022-03-10 20:19:57 +01004172 }
Valentin Clement99075912022-02-01 13:49:49 +01004173 }
4174
4175 //===--------------------------------------------------------------------===//
4176
Katherine Rasmussena2d7af72024-01-02 10:40:47 -08004177 void genFIR(const Fortran::parser::NotifyWaitStmt &stmt) {
4178 genNotifyWaitStatement(*this, stmt);
4179 }
4180
Valentin Clement99075912022-02-01 13:49:49 +01004181 void genFIR(const Fortran::parser::EventPostStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02004182 genEventPostStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01004183 }
4184
4185 void genFIR(const Fortran::parser::EventWaitStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02004186 genEventWaitStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01004187 }
4188
4189 void genFIR(const Fortran::parser::FormTeamStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02004190 genFormTeamStatement(*this, getEval(), stmt);
Valentin Clement99075912022-02-01 13:49:49 +01004191 }
4192
4193 void genFIR(const Fortran::parser::LockStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02004194 genLockStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01004195 }
4196
Valentin Clementfe252f82022-03-22 15:40:32 +01004197 fir::ExtendedValue
4198 genInitializerExprValue(const Fortran::lower::SomeExpr &expr,
4199 Fortran::lower::StatementContext &stmtCtx) {
4200 return Fortran::lower::createSomeInitializerExpression(
4201 toLocation(), *this, expr, localSymbols, stmtCtx);
4202 }
4203
Valentin Clement7a6a1652022-03-10 18:43:40 +01004204 /// Return true if the current context is a conditionalized and implied
4205 /// iteration space.
4206 bool implicitIterationSpace() { return !implicitIterSpace.empty(); }
4207
4208 /// Return true if context is currently an explicit iteration space. A scalar
4209 /// assignment expression may be contextually within a user-defined iteration
4210 /// space, transforming it into an array expression.
4211 bool explicitIterationSpace() { return explicitIterSpace.isActive(); }
4212
Valentin Clementf9704f02022-02-24 21:09:40 +01004213 /// Generate an array assignment.
4214 /// This is an assignment expression with rank > 0. The assignment may or may
4215 /// not be in a WHERE and/or FORALL context.
Eric Schweitz1bffc752022-04-22 13:59:17 -07004216 /// In a FORALL context, the assignment may be a pointer assignment and the \p
4217 /// lbounds and \p ubounds parameters should only be used in such a pointer
4218 /// assignment case. (If both are None then the array assignment cannot be a
4219 /// pointer assignment.)
4220 void genArrayAssignment(
4221 const Fortran::evaluate::Assignment &assign,
Jean Periere6238ab2022-09-20 10:39:39 +02004222 Fortran::lower::StatementContext &localStmtCtx,
Kazu Hiratac0921582023-01-07 22:26:48 -08004223 std::optional<llvm::SmallVector<mlir::Value>> lbounds = std::nullopt,
4224 std::optional<llvm::SmallVector<mlir::Value>> ubounds = std::nullopt) {
Jean Periere6238ab2022-09-20 10:39:39 +02004225
4226 Fortran::lower::StatementContext &stmtCtx =
4227 explicitIterationSpace()
4228 ? explicitIterSpace.stmtContext()
4229 : (implicitIterationSpace() ? implicitIterSpace.stmtContext()
4230 : localStmtCtx);
Eric Schweitz1bffc752022-04-22 13:59:17 -07004231 if (Fortran::lower::isWholeAllocatable(assign.lhs)) {
Valentin Clementf9704f02022-02-24 21:09:40 +01004232 // Assignment to allocatables may require the lhs to be
4233 // deallocated/reallocated. See Fortran 2018 10.2.1.3 p3
4234 Fortran::lower::createAllocatableArrayAssignment(
4235 *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
4236 localSymbols, stmtCtx);
4237 return;
4238 }
4239
Kazu Hirata5413bf12022-06-20 11:33:56 -07004240 if (lbounds) {
Eric Schweitz1bffc752022-04-22 13:59:17 -07004241 // Array of POINTER entities, with elemental assignment.
4242 if (!Fortran::lower::isWholePointer(assign.lhs))
4243 fir::emitFatalError(toLocation(), "pointer assignment to non-pointer");
4244
4245 Fortran::lower::createArrayOfPointerAssignment(
4246 *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
Kazu Hirataed8fcea2022-06-20 23:35:53 -07004247 *lbounds, ubounds, localSymbols, stmtCtx);
Eric Schweitz1bffc752022-04-22 13:59:17 -07004248 return;
4249 }
4250
Valentin Clement7a6a1652022-03-10 18:43:40 +01004251 if (!implicitIterationSpace() && !explicitIterationSpace()) {
4252 // No masks and the iteration space is implied by the array, so create a
4253 // simple array assignment.
4254 Fortran::lower::createSomeArrayAssignment(*this, assign.lhs, assign.rhs,
4255 localSymbols, stmtCtx);
4256 return;
4257 }
4258
4259 // If there is an explicit iteration space, generate an array assignment
4260 // with a user-specified iteration space and possibly with masks. These
4261 // assignments may *appear* to be scalar expressions, but the scalar
4262 // expression is evaluated at all points in the user-defined space much like
4263 // an ordinary array assignment. More specifically, the semantics inside the
4264 // FORALL much more closely resembles that of WHERE than a scalar
4265 // assignment.
4266 // Otherwise, generate a masked array assignment. The iteration space is
4267 // implied by the lhs array expression.
4268 Fortran::lower::createAnyMaskedArrayAssignment(
4269 *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
Jean Periere6238ab2022-09-20 10:39:39 +02004270 localSymbols, stmtCtx);
Valentin Clementf9704f02022-02-24 21:09:40 +01004271 }
4272
Valentin Clementfe252f82022-03-22 15:40:32 +01004273#if !defined(NDEBUG)
4274 static bool isFuncResultDesignator(const Fortran::lower::SomeExpr &expr) {
4275 const Fortran::semantics::Symbol *sym =
4276 Fortran::evaluate::GetFirstSymbol(expr);
4277 return sym && sym->IsFuncResult();
4278 }
4279#endif
4280
Eric Schweitz1bffc752022-04-22 13:59:17 -07004281 inline fir::MutableBoxValue
4282 genExprMutableBox(mlir::Location loc,
4283 const Fortran::lower::SomeExpr &expr) override final {
Jean Perier7531c872023-01-20 14:05:42 +01004284 if (lowerToHighLevelFIR())
4285 return Fortran::lower::convertExprToMutableBox(loc, *this, expr,
4286 localSymbols);
Eric Schweitz1bffc752022-04-22 13:59:17 -07004287 return Fortran::lower::createMutableBox(loc, *this, expr, localSymbols);
Valentin Clementfe252f82022-03-22 15:40:32 +01004288 }
4289
Valentin Clementdda01632023-02-07 09:15:54 +01004290 // Create the [newRank] array with the lower bounds to be passed to the
4291 // runtime as a descriptor.
4292 mlir::Value createLboundArray(llvm::ArrayRef<mlir::Value> lbounds,
4293 mlir::Location loc) {
4294 mlir::Type indexTy = builder->getIndexType();
4295 mlir::Type boundArrayTy = fir::SequenceType::get(
4296 {static_cast<int64_t>(lbounds.size())}, builder->getI64Type());
4297 mlir::Value boundArray = builder->create<fir::AllocaOp>(loc, boundArrayTy);
4298 mlir::Value array = builder->create<fir::UndefOp>(loc, boundArrayTy);
4299 for (unsigned i = 0; i < lbounds.size(); ++i) {
4300 array = builder->create<fir::InsertValueOp>(
4301 loc, boundArrayTy, array, lbounds[i],
4302 builder->getArrayAttr({builder->getIntegerAttr(
4303 builder->getIndexType(), static_cast<int>(i))}));
4304 }
4305 builder->create<fir::StoreOp>(loc, array, boundArray);
4306 mlir::Type boxTy = fir::BoxType::get(boundArrayTy);
4307 mlir::Value ext =
4308 builder->createIntegerConstant(loc, indexTy, lbounds.size());
4309 llvm::SmallVector<mlir::Value> shapes = {ext};
4310 mlir::Value shapeOp = builder->genShape(loc, shapes);
4311 return builder->create<fir::EmboxOp>(loc, boxTy, boundArray, shapeOp);
4312 }
4313
Jean Perier7531c872023-01-20 14:05:42 +01004314 // Generate pointer assignment with possibly empty bounds-spec. R1035: a
4315 // bounds-spec is a lower bound value.
4316 void genPointerAssignment(
4317 mlir::Location loc, const Fortran::evaluate::Assignment &assign,
4318 const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4319 Fortran::lower::StatementContext stmtCtx;
Daniel Chenaf092192023-11-22 11:51:12 -05004320
Peter Klauslerc7593342024-06-03 12:58:39 -07004321 if (!lowerToHighLevelFIR() &&
4322 Fortran::evaluate::IsProcedureDesignator(assign.rhs))
Jean Perier7531c872023-01-20 14:05:42 +01004323 TODO(loc, "procedure pointer assignment");
Daniel Chenaf092192023-11-22 11:51:12 -05004324 if (Fortran::evaluate::IsProcedurePointer(assign.lhs)) {
4325 hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR(
4326 loc, *this, assign.lhs, localSymbols, stmtCtx);
Daniel Chenbd8bec22024-01-31 11:24:17 -05004327 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4328 assign.rhs)) {
4329 // rhs is null(). rhs being null(pptr) is handled in genNull.
Daniel Chen49985872024-03-26 11:29:24 -04004330 auto boxTy{
4331 Fortran::lower::getUntypedBoxProcType(builder->getContext())};
Daniel Chenaf092192023-11-22 11:51:12 -05004332 hlfir::Entity rhs(
4333 fir::factory::createNullBoxProc(*builder, loc, boxTy));
4334 builder->createStoreWithConvert(loc, rhs, lhs);
4335 return;
4336 }
4337 hlfir::Entity rhs(getBase(Fortran::lower::convertExprToAddress(
4338 loc, *this, assign.rhs, localSymbols, stmtCtx)));
4339 builder->createStoreWithConvert(loc, rhs, lhs);
4340 return;
4341 }
Jean Perier7531c872023-01-20 14:05:42 +01004342
4343 std::optional<Fortran::evaluate::DynamicType> lhsType =
4344 assign.lhs.GetType();
4345 // Delegate pointer association to unlimited polymorphic pointer
4346 // to the runtime. element size, type code, attribute and of
4347 // course base_addr might need to be updated.
4348 if (lhsType && lhsType->IsPolymorphic()) {
4349 if (!lowerToHighLevelFIR() && explicitIterationSpace())
4350 TODO(loc, "polymorphic pointer assignment in FORALL");
Valentin Clementdda01632023-02-07 09:15:54 +01004351 llvm::SmallVector<mlir::Value> lbounds;
4352 for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
4353 lbounds.push_back(
4354 fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
Jean Perier04a920b72023-04-03 09:18:41 +02004355 fir::MutableBoxValue lhsMutableBox = genExprMutableBox(loc, assign.lhs);
4356 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4357 assign.rhs)) {
4358 fir::factory::disassociateMutableBox(*builder, loc, lhsMutableBox);
4359 return;
4360 }
4361 mlir::Value lhs = lhsMutableBox.getAddr();
Jean Perier7531c872023-01-20 14:05:42 +01004362 mlir::Value rhs = fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
Valentin Clementdda01632023-02-07 09:15:54 +01004363 if (!lbounds.empty()) {
4364 mlir::Value boundsDesc = createLboundArray(lbounds, loc);
4365 Fortran::lower::genPointerAssociateLowerBounds(*builder, loc, lhs, rhs,
4366 boundsDesc);
4367 return;
4368 }
Jean Perier7531c872023-01-20 14:05:42 +01004369 Fortran::lower::genPointerAssociate(*builder, loc, lhs, rhs);
4370 return;
4371 }
4372
4373 llvm::SmallVector<mlir::Value> lbounds;
4374 for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
4375 lbounds.push_back(fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
4376 if (!lowerToHighLevelFIR() && explicitIterationSpace()) {
4377 // Pointer assignment in FORALL context. Copy the rhs box value
4378 // into the lhs box variable.
4379 genArrayAssignment(assign, stmtCtx, lbounds);
4380 return;
4381 }
4382 fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
4383 Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs, lbounds,
4384 stmtCtx);
4385 }
Valentin Clement3b73fc32023-02-06 21:06:44 +01004386
jeanPerier3ff3b292025-03-14 10:51:46 +01004387 void genForallPointerAssignment(mlir::Location loc,
4388 const Fortran::evaluate::Assignment &assign) {
4389 // Lower pointer assignment inside forall with hlfir.region_assign with
4390 // descriptor address/value and later implemented with a store.
4391 // The RHS is fully prepared in lowering, so that all that is left
4392 // in hlfir.region_assign code generation is the store.
jeanPerier7302e1b2025-03-05 11:24:04 +01004393 auto regionAssignOp = builder->create<hlfir::RegionAssignOp>(loc);
4394
4395 // Lower LHS in its own region.
4396 builder->createBlock(&regionAssignOp.getLhsRegion());
4397 Fortran::lower::StatementContext lhsContext;
4398 hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR(
4399 loc, *this, assign.lhs, localSymbols, lhsContext);
jeanPerier7302e1b2025-03-05 11:24:04 +01004400 auto lhsYieldOp = builder->create<hlfir::YieldOp>(loc, lhs);
4401 Fortran::lower::genCleanUpInRegionIfAny(
4402 loc, *builder, lhsYieldOp.getCleanup(), lhsContext);
4403
4404 // Lower RHS in its own region.
4405 builder->createBlock(&regionAssignOp.getRhsRegion());
4406 Fortran::lower::StatementContext rhsContext;
jeanPerier40e245a2025-03-07 10:28:02 +01004407 mlir::Value rhs =
4408 genForallPointerAssignmentRhs(loc, lhs, assign, rhsContext);
4409 auto rhsYieldOp = builder->create<hlfir::YieldOp>(loc, rhs);
4410 Fortran::lower::genCleanUpInRegionIfAny(
4411 loc, *builder, rhsYieldOp.getCleanup(), rhsContext);
4412
4413 builder->setInsertionPointAfter(regionAssignOp);
4414 }
4415
jeanPerier3ff3b292025-03-14 10:51:46 +01004416 mlir::Value lowerToIndexValue(mlir::Location loc,
4417 const Fortran::evaluate::ExtentExpr &expr,
4418 Fortran::lower::StatementContext &stmtCtx) {
4419 mlir::Value val = fir::getBase(genExprValue(toEvExpr(expr), stmtCtx));
4420 return builder->createConvert(loc, builder->getIndexType(), val);
4421 }
4422
jeanPerier40e245a2025-03-07 10:28:02 +01004423 mlir::Value
4424 genForallPointerAssignmentRhs(mlir::Location loc, mlir::Value lhs,
4425 const Fortran::evaluate::Assignment &assign,
4426 Fortran::lower::StatementContext &rhsContext) {
jeanPerier3ff3b292025-03-14 10:51:46 +01004427 if (Fortran::evaluate::IsProcedureDesignator(assign.lhs)) {
4428 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4429 assign.rhs))
4430 return fir::factory::createNullBoxProc(
4431 *builder, loc, fir::unwrapRefType(lhs.getType()));
jeanPerier40e245a2025-03-07 10:28:02 +01004432 return fir::getBase(Fortran::lower::convertExprToAddress(
4433 loc, *this, assign.rhs, localSymbols, rhsContext));
jeanPerier3ff3b292025-03-14 10:51:46 +01004434 }
jeanPerier40e245a2025-03-07 10:28:02 +01004435 // Data target.
jeanPerier3ff3b292025-03-14 10:51:46 +01004436 auto lhsBoxType =
4437 llvm::cast<fir::BaseBoxType>(fir::unwrapRefType(lhs.getType()));
4438 // For NULL, create disassociated descriptor whose dynamic type is
4439 // the static type of the LHS.
4440 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4441 assign.rhs))
4442 return fir::factory::createUnallocatedBox(*builder, loc, lhsBoxType,
4443 std::nullopt);
jeanPerier7302e1b2025-03-05 11:24:04 +01004444 hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR(
4445 loc, *this, assign.rhs, localSymbols, rhsContext);
4446 // Create pointer descriptor value from the RHS.
4447 if (rhs.isMutableBox())
4448 rhs = hlfir::Entity{builder->create<fir::LoadOp>(loc, rhs)};
jeanPerier3ff3b292025-03-14 10:51:46 +01004449 mlir::Value rhsBox = hlfir::genVariableBox(
4450 loc, *builder, rhs, lhsBoxType.getBoxTypeWithNewShape(rhs.getRank()));
4451 // Apply lower bounds or reshaping if any.
4452 if (const auto *lbExprs =
4453 std::get_if<Fortran::evaluate::Assignment::BoundsSpec>(&assign.u);
4454 lbExprs && !lbExprs->empty()) {
4455 // Override target lower bounds with the LHS bounds spec.
4456 llvm::SmallVector<mlir::Value> lbounds;
4457 for (const Fortran::evaluate::ExtentExpr &lbExpr : *lbExprs)
4458 lbounds.push_back(lowerToIndexValue(loc, lbExpr, rhsContext));
4459 mlir::Value shift = builder->genShift(loc, lbounds);
4460 rhsBox = builder->create<fir::ReboxOp>(loc, lhsBoxType, rhsBox, shift,
4461 /*slice=*/mlir::Value{});
4462 } else if (const auto *boundExprs =
4463 std::get_if<Fortran::evaluate::Assignment::BoundsRemapping>(
4464 &assign.u);
4465 boundExprs && !boundExprs->empty()) {
4466 // Reshape the target according to the LHS bounds remapping.
4467 llvm::SmallVector<mlir::Value> lbounds;
4468 llvm::SmallVector<mlir::Value> extents;
4469 mlir::Type indexTy = builder->getIndexType();
4470 mlir::Value zero = builder->createIntegerConstant(loc, indexTy, 0);
4471 mlir::Value one = builder->createIntegerConstant(loc, indexTy, 1);
4472 for (const auto &[lbExpr, ubExpr] : *boundExprs) {
4473 lbounds.push_back(lowerToIndexValue(loc, lbExpr, rhsContext));
4474 mlir::Value ub = lowerToIndexValue(loc, ubExpr, rhsContext);
4475 extents.push_back(fir::factory::computeExtent(
4476 *builder, loc, lbounds.back(), ub, zero, one));
4477 }
4478 mlir::Value shape = builder->genShape(loc, lbounds, extents);
4479 rhsBox = builder->create<fir::ReboxOp>(loc, lhsBoxType, rhsBox, shape,
4480 /*slice=*/mlir::Value{});
4481 }
4482 return rhsBox;
jeanPerier7302e1b2025-03-05 11:24:04 +01004483 }
4484
Valentin Clement3b73fc32023-02-06 21:06:44 +01004485 // Create the 2 x newRank array with the bounds to be passed to the runtime as
4486 // a descriptor.
4487 mlir::Value createBoundArray(llvm::ArrayRef<mlir::Value> lbounds,
4488 llvm::ArrayRef<mlir::Value> ubounds,
4489 mlir::Location loc) {
4490 assert(lbounds.size() && ubounds.size());
4491 mlir::Type indexTy = builder->getIndexType();
4492 mlir::Type boundArrayTy = fir::SequenceType::get(
4493 {2, static_cast<int64_t>(lbounds.size())}, builder->getI64Type());
4494 mlir::Value boundArray = builder->create<fir::AllocaOp>(loc, boundArrayTy);
4495 mlir::Value array = builder->create<fir::UndefOp>(loc, boundArrayTy);
4496 for (unsigned i = 0; i < lbounds.size(); ++i) {
4497 array = builder->create<fir::InsertValueOp>(
4498 loc, boundArrayTy, array, lbounds[i],
4499 builder->getArrayAttr(
4500 {builder->getIntegerAttr(builder->getIndexType(), 0),
4501 builder->getIntegerAttr(builder->getIndexType(),
4502 static_cast<int>(i))}));
4503 array = builder->create<fir::InsertValueOp>(
4504 loc, boundArrayTy, array, ubounds[i],
4505 builder->getArrayAttr(
4506 {builder->getIntegerAttr(builder->getIndexType(), 1),
4507 builder->getIntegerAttr(builder->getIndexType(),
4508 static_cast<int>(i))}));
4509 }
4510 builder->create<fir::StoreOp>(loc, array, boundArray);
4511 mlir::Type boxTy = fir::BoxType::get(boundArrayTy);
4512 mlir::Value ext =
4513 builder->createIntegerConstant(loc, indexTy, lbounds.size());
4514 mlir::Value c2 = builder->createIntegerConstant(loc, indexTy, 2);
4515 llvm::SmallVector<mlir::Value> shapes = {c2, ext};
4516 mlir::Value shapeOp = builder->genShape(loc, shapes);
4517 return builder->create<fir::EmboxOp>(loc, boxTy, boundArray, shapeOp);
4518 }
4519
Jean Perier7531c872023-01-20 14:05:42 +01004520 // Pointer assignment with bounds-remapping. R1036: a bounds-remapping is a
4521 // pair, lower bound and upper bound.
4522 void genPointerAssignment(
4523 mlir::Location loc, const Fortran::evaluate::Assignment &assign,
4524 const Fortran::evaluate::Assignment::BoundsRemapping &boundExprs) {
4525 Fortran::lower::StatementContext stmtCtx;
4526 llvm::SmallVector<mlir::Value> lbounds;
4527 llvm::SmallVector<mlir::Value> ubounds;
4528 for (const std::pair<Fortran::evaluate::ExtentExpr,
4529 Fortran::evaluate::ExtentExpr> &pair : boundExprs) {
4530 const Fortran::evaluate::ExtentExpr &lbExpr = pair.first;
4531 const Fortran::evaluate::ExtentExpr &ubExpr = pair.second;
4532 lbounds.push_back(fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
4533 ubounds.push_back(fir::getBase(genExprValue(toEvExpr(ubExpr), stmtCtx)));
4534 }
4535
4536 std::optional<Fortran::evaluate::DynamicType> lhsType =
4537 assign.lhs.GetType();
4538 std::optional<Fortran::evaluate::DynamicType> rhsType =
4539 assign.rhs.GetType();
4540 // Polymorphic lhs/rhs need more care. See F2018 10.2.2.3.
4541 if ((lhsType && lhsType->IsPolymorphic()) ||
4542 (rhsType && rhsType->IsPolymorphic())) {
4543 if (!lowerToHighLevelFIR() && explicitIterationSpace())
4544 TODO(loc, "polymorphic pointer assignment in FORALL");
4545
Jean Perier04a920b72023-04-03 09:18:41 +02004546 fir::MutableBoxValue lhsMutableBox = genExprMutableBox(loc, assign.lhs);
4547 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4548 assign.rhs)) {
4549 fir::factory::disassociateMutableBox(*builder, loc, lhsMutableBox);
4550 return;
4551 }
4552 mlir::Value lhs = lhsMutableBox.getAddr();
Jean Perier7531c872023-01-20 14:05:42 +01004553 mlir::Value rhs = fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
Valentin Clement3b73fc32023-02-06 21:06:44 +01004554 mlir::Value boundsDesc = createBoundArray(lbounds, ubounds, loc);
Jean Perier7531c872023-01-20 14:05:42 +01004555 Fortran::lower::genPointerAssociateRemapping(*builder, loc, lhs, rhs,
4556 boundsDesc);
4557 return;
4558 }
4559 if (!lowerToHighLevelFIR() && explicitIterationSpace()) {
4560 // Pointer assignment in FORALL context. Copy the rhs box value
4561 // into the lhs box variable.
4562 genArrayAssignment(assign, stmtCtx, lbounds, ubounds);
4563 return;
4564 }
4565 fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
4566 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4567 assign.rhs)) {
4568 fir::factory::disassociateMutableBox(*builder, loc, lhs);
4569 return;
4570 }
jeanPeriere769fb82024-02-15 09:06:42 +01004571 if (lowerToHighLevelFIR()) {
4572 fir::ExtendedValue rhs = genExprAddr(assign.rhs, stmtCtx);
4573 fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs, rhs,
4574 lbounds, ubounds);
4575 return;
4576 }
4577 // Legacy lowering below.
Jean Perier7531c872023-01-20 14:05:42 +01004578 // Do not generate a temp in case rhs is an array section.
4579 fir::ExtendedValue rhs =
4580 Fortran::lower::isArraySectionWithoutVectorSubscript(assign.rhs)
4581 ? Fortran::lower::createSomeArrayBox(*this, assign.rhs,
4582 localSymbols, stmtCtx)
4583 : genExprAddr(assign.rhs, stmtCtx);
4584 fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs, rhs, lbounds,
4585 ubounds);
jeanPeriere769fb82024-02-15 09:06:42 +01004586 if (explicitIterationSpace()) {
Jean Perier7531c872023-01-20 14:05:42 +01004587 mlir::ValueRange inners = explicitIterSpace.getInnerArgs();
4588 if (!inners.empty())
4589 builder->create<fir::ResultOp>(loc, inners);
4590 }
4591 }
4592
jeanPerier70462022023-10-27 09:07:48 +02004593 /// Given converted LHS and RHS of the assignment, materialize any
4594 /// implicit conversion of the RHS to the LHS type. The front-end
4595 /// usually already makes those explicit, except for non-standard
4596 /// LOGICAL <-> INTEGER, or if the LHS is a whole allocatable
4597 /// (making the conversion explicit in the front-end would prevent
4598 /// propagation of the LHS lower bound in the reallocation).
4599 /// If array temporaries or values are created, the cleanups are
4600 /// added in the statement context.
4601 hlfir::Entity genImplicitConvert(const Fortran::evaluate::Assignment &assign,
4602 hlfir::Entity rhs, bool preserveLowerBounds,
4603 Fortran::lower::StatementContext &stmtCtx) {
Slava Zakharinec2c0e02023-05-04 08:47:28 -07004604 mlir::Location loc = toLocation();
4605 auto &builder = getFirOpBuilder();
jeanPerier70462022023-10-27 09:07:48 +02004606 mlir::Type toType = genType(assign.lhs);
4607 auto valueAndPair = hlfir::genTypeAndKindConvert(loc, builder, rhs, toType,
4608 preserveLowerBounds);
4609 if (valueAndPair.second)
4610 stmtCtx.attachCleanup(*valueAndPair.second);
4611 return hlfir::Entity{valueAndPair.first};
Jean Perierb87e6552023-05-09 09:18:53 +02004612 }
4613
Jean Perier67169232023-06-26 13:06:43 +02004614 bool firstDummyIsPointerOrAllocatable(
4615 const Fortran::evaluate::ProcedureRef &userDefinedAssignment) {
4616 using DummyAttr = Fortran::evaluate::characteristics::DummyDataObject::Attr;
4617 if (auto procedure =
4618 Fortran::evaluate::characteristics::Procedure::Characterize(
Peter Klauslercb263912024-04-22 15:21:45 -07004619 userDefinedAssignment.proc(), getFoldingContext(),
4620 /*emitError=*/false))
Jean Perier67169232023-06-26 13:06:43 +02004621 if (!procedure->dummyArguments.empty())
4622 if (const auto *dataArg = std::get_if<
4623 Fortran::evaluate::characteristics::DummyDataObject>(
4624 &procedure->dummyArguments[0].u))
4625 return dataArg->attrs.test(DummyAttr::Pointer) ||
4626 dataArg->attrs.test(DummyAttr::Allocatable);
4627 return false;
4628 }
4629
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004630 void genCUDADataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
4631 const Fortran::evaluate::Assignment &assign,
4632 hlfir::Entity &lhs, hlfir::Entity &rhs) {
Valentin Clement (バレンタイン クレメン)8e8dccd2024-06-19 13:35:02 -07004633 bool lhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.lhs);
4634 bool rhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.rhs);
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004635
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004636 auto getRefFromValue = [](mlir::Value val) -> mlir::Value {
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004637 if (auto loadOp =
4638 mlir::dyn_cast_or_null<fir::LoadOp>(val.getDefiningOp()))
4639 return loadOp.getMemref();
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004640 if (!mlir::isa<fir::BaseBoxType>(val.getType()))
4641 return val;
4642 if (auto declOp =
4643 mlir::dyn_cast_or_null<hlfir::DeclareOp>(val.getDefiningOp())) {
4644 if (!declOp.getShape())
4645 return val;
4646 if (mlir::isa<fir::ReferenceType>(declOp.getMemref().getType()))
Valentin Clement (バレンタイン クレメン)ccbee712024-08-27 17:36:31 -07004647 return declOp.getResults()[1];
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004648 }
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004649 return val;
4650 };
4651
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004652 auto getShapeFromDecl = [](mlir::Value val) -> mlir::Value {
4653 if (!mlir::isa<fir::BaseBoxType>(val.getType()))
4654 return {};
4655 if (auto declOp =
4656 mlir::dyn_cast_or_null<hlfir::DeclareOp>(val.getDefiningOp()))
4657 return declOp.getShape();
4658 return {};
4659 };
4660
4661 mlir::Value rhsVal = getRefFromValue(rhs.getBase());
4662 mlir::Value lhsVal = getRefFromValue(lhs.getBase());
4663 // Get shape from the rhs if available otherwise get it from lhs.
4664 mlir::Value shape = getShapeFromDecl(rhs.getBase());
4665 if (!shape)
4666 shape = getShapeFromDecl(lhs.getBase());
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004667
4668 // device = host
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004669 if (lhsIsDevice && !rhsIsDevice) {
Valentin Clement (バレンタイン クレメン)45daa4f2024-05-17 09:37:53 -07004670 auto transferKindAttr = cuf::DataTransferKindAttr::get(
4671 builder.getContext(), cuf::DataTransferKind::HostDevice);
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004672 if (!rhs.isVariable()) {
Valentin Clement (バレンタイン クレメン)3ad7108c2024-07-17 08:39:18 -07004673 mlir::Value base = rhs;
4674 if (auto convertOp =
4675 mlir::dyn_cast<fir::ConvertOp>(rhs.getDefiningOp()))
4676 base = convertOp.getValue();
Valentin Clement (バレンタイン クレメン)0bc710f2024-05-21 12:42:30 -07004677 // Special case if the rhs is a constant.
Valentin Clement (バレンタイン クレメン)3ad7108c2024-07-17 08:39:18 -07004678 if (matchPattern(base.getDefiningOp(), mlir::m_Constant())) {
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004679 builder.create<cuf::DataTransferOp>(loc, base, lhsVal, shape,
4680 transferKindAttr);
Valentin Clement (バレンタイン クレメン)0bc710f2024-05-21 12:42:30 -07004681 } else {
4682 auto associate = hlfir::genAssociateExpr(
4683 loc, builder, rhs, rhs.getType(), ".cuf_host_tmp");
4684 builder.create<cuf::DataTransferOp>(loc, associate.getBase(), lhsVal,
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004685 shape, transferKindAttr);
Valentin Clement (バレンタイン クレメン)0bc710f2024-05-21 12:42:30 -07004686 builder.create<hlfir::EndAssociateOp>(loc, associate);
4687 }
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004688 } else {
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004689 builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
4690 transferKindAttr);
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004691 }
4692 return;
4693 }
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004694
4695 // host = device
4696 if (!lhsIsDevice && rhsIsDevice) {
Valentin Clement (バレンタイン クレメン)45daa4f2024-05-17 09:37:53 -07004697 auto transferKindAttr = cuf::DataTransferKindAttr::get(
4698 builder.getContext(), cuf::DataTransferKind::DeviceHost);
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004699 builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004700 transferKindAttr);
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004701 return;
4702 }
4703
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004704 // device = device
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004705 if (lhsIsDevice && rhsIsDevice) {
4706 assert(rhs.isVariable() && "CUDA Fortran assignment rhs is not legal");
Valentin Clement (バレンタイン クレメン)45daa4f2024-05-17 09:37:53 -07004707 auto transferKindAttr = cuf::DataTransferKindAttr::get(
4708 builder.getContext(), cuf::DataTransferKind::DeviceDevice);
Valentin Clement (バレンタイン クレメン)900cd622024-08-27 10:03:15 -07004709 builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
Valentin Clement (バレンタイン クレメン)1fc3ce1c2024-05-21 11:23:55 -07004710 transferKindAttr);
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004711 return;
4712 }
4713 llvm_unreachable("Unhandled CUDA data transfer");
4714 }
4715
4716 llvm::SmallVector<mlir::Value>
4717 genCUDAImplicitDataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
4718 const Fortran::evaluate::Assignment &assign) {
4719 llvm::SmallVector<mlir::Value> temps;
4720 localSymbols.pushScope();
Valentin Clement (バレンタイン クレメン)45daa4f2024-05-17 09:37:53 -07004721 auto transferKindAttr = cuf::DataTransferKindAttr::get(
4722 builder.getContext(), cuf::DataTransferKind::DeviceHost);
Jie Fu3f2f7002024-04-06 07:31:53 +08004723 [[maybe_unused]] unsigned nbDeviceResidentObject = 0;
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004724 for (const Fortran::semantics::Symbol &sym :
4725 Fortran::evaluate::CollectSymbols(assign.rhs)) {
4726 if (const auto *details =
4727 sym.GetUltimate()
4728 .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
Valentin Clement (バレンタイン クレメン)8e8dccd2024-06-19 13:35:02 -07004729 if (details->cudaDataAttr() &&
4730 *details->cudaDataAttr() != Fortran::common::CUDADataAttr::Pinned) {
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004731 if (sym.owner().IsDerivedType() && IsAllocatable(sym.GetUltimate()))
4732 TODO(loc, "Device resident allocatable derived-type component");
4733 // TODO: This should probably being checked in semantic and give a
4734 // proper error.
4735 assert(
4736 nbDeviceResidentObject <= 1 &&
4737 "Only one reference to the device resident object is supported");
4738 auto addr = getSymbolAddress(sym);
4739 hlfir::Entity entity{addr};
4740 auto [temp, cleanup] =
4741 hlfir::createTempFromMold(loc, builder, entity);
4742 auto needCleanup = fir::getIntIfConstant(cleanup);
Valentin Clement (バレンタイン クレメン)9b6504e2024-07-11 17:15:54 -07004743 if (needCleanup && *needCleanup) {
4744 if (auto declareOp =
4745 mlir::dyn_cast<hlfir::DeclareOp>(temp.getDefiningOp()))
4746 temps.push_back(declareOp.getMemref());
4747 else
4748 temps.push_back(temp);
4749 }
Valentin Clement (バレンタイン クレメン)09cdfd62024-04-25 08:50:52 -07004750 addSymbol(sym,
4751 hlfir::translateToExtendedValue(loc, builder, temp).first,
4752 /*forced=*/true);
Valentin Clement (バレンタイン クレメン)7af61d52024-08-26 09:50:17 -07004753 builder.create<cuf::DataTransferOp>(
4754 loc, addr, temp, /*shape=*/mlir::Value{}, transferKindAttr);
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004755 ++nbDeviceResidentObject;
4756 }
4757 }
4758 }
4759 return temps;
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004760 }
4761
Jean Perierb87e6552023-05-09 09:18:53 +02004762 void genDataAssignment(
4763 const Fortran::evaluate::Assignment &assign,
4764 const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
4765 mlir::Location loc = getCurrentLocation();
4766 fir::FirOpBuilder &builder = getFirOpBuilder();
Valentin Clement (バレンタイン クレメン)8a6a0f12024-03-18 17:11:04 -07004767
Valentin Clement (バレンタイン クレメン)478e5162025-03-06 19:19:51 -08004768 bool isInDeviceContext = cuf::isCUDADeviceContext(builder.getRegion());
Valentin Clement (バレンタイン クレメン)0a41c8e2024-08-29 11:27:42 -07004769
Valentin Clement (バレンタイン クレメン)d1fd3692025-03-02 16:12:01 -08004770 bool isCUDATransfer =
4771 IsCUDADataTransfer(assign.lhs, assign.rhs) && !isInDeviceContext;
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004772 bool hasCUDAImplicitTransfer =
Valentin Clement (バレンタイン クレメン)d1fd3692025-03-02 16:12:01 -08004773 isCUDATransfer &&
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004774 Fortran::evaluate::HasCUDAImplicitTransfer(assign.rhs);
4775 llvm::SmallVector<mlir::Value> implicitTemps;
Valentin Clement (バレンタイン クレメン)3433e412024-11-26 17:04:00 -08004776
Valentin Clement (バレンタイン クレメン)5cfd5d12024-04-25 08:50:34 -07004777 if (hasCUDAImplicitTransfer && !isInDeviceContext)
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004778 implicitTemps = genCUDAImplicitDataTransfer(builder, loc, assign);
Valentin Clement (バレンタイン クレメン)8a6a0f12024-03-18 17:11:04 -07004779
Jean Perierb87e6552023-05-09 09:18:53 +02004780 // Gather some information about the assignment that will impact how it is
4781 // lowered.
4782 const bool isWholeAllocatableAssignment =
Jean Perier54c88fc2023-05-09 09:21:09 +02004783 !userDefinedAssignment && !isInsideHlfirWhere() &&
Slava Zakharin9d338742024-12-17 09:06:05 -08004784 Fortran::lower::isWholeAllocatable(assign.lhs) &&
4785 bridge.getLoweringOptions().getReallocateLHS();
Jean Perier67169232023-06-26 13:06:43 +02004786 const bool isUserDefAssignToPointerOrAllocatable =
4787 userDefinedAssignment &&
4788 firstDummyIsPointerOrAllocatable(*userDefinedAssignment);
Jean Perierb87e6552023-05-09 09:18:53 +02004789 std::optional<Fortran::evaluate::DynamicType> lhsType =
4790 assign.lhs.GetType();
4791 const bool keepLhsLengthInAllocatableAssignment =
4792 isWholeAllocatableAssignment && lhsType.has_value() &&
4793 lhsType->category() == Fortran::common::TypeCategory::Character &&
4794 !lhsType->HasDeferredTypeParameter();
4795 const bool lhsHasVectorSubscripts =
4796 Fortran::evaluate::HasVectorSubscript(assign.lhs);
4797
4798 // Helper to generate the code evaluating the right-hand side.
4799 auto evaluateRhs = [&](Fortran::lower::StatementContext &stmtCtx) {
4800 hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR(
4801 loc, *this, assign.rhs, localSymbols, stmtCtx);
4802 // Load trivial scalar RHS to allow the loads to be hoisted outside of
4803 // loops early if possible. This also dereferences pointer and
4804 // allocatable RHS: the target is being assigned from.
4805 rhs = hlfir::loadTrivialScalar(loc, builder, rhs);
jeanPerier70462022023-10-27 09:07:48 +02004806 // In intrinsic assignments, the LHS type may not match the RHS type, in
4807 // which case an implicit conversion of the LHS must be done. The
4808 // front-end usually makes it explicit, unless it cannot (whole
4809 // allocatable LHS or Logical<->Integer assignment extension). Recognize
4810 // any type mismatches here and insert explicit scalar convert or
4811 // ElementalOp for array assignment. Preserve the RHS lower bounds on the
4812 // converted entity in case of assignment to whole allocatables so to
4813 // propagate the lower bounds to the LHS in case of reallocation.
Jean Perierb87e6552023-05-09 09:18:53 +02004814 if (!userDefinedAssignment)
jeanPerier70462022023-10-27 09:07:48 +02004815 rhs = genImplicitConvert(assign, rhs, isWholeAllocatableAssignment,
4816 stmtCtx);
Jean Perierb87e6552023-05-09 09:18:53 +02004817 return rhs;
4818 };
4819
4820 // Helper to generate the code evaluating the left-hand side.
4821 auto evaluateLhs = [&](Fortran::lower::StatementContext &stmtCtx) {
4822 hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR(
4823 loc, *this, assign.lhs, localSymbols, stmtCtx);
4824 // Dereference pointer LHS: the target is being assigned to.
4825 // Same for allocatables outside of whole allocatable assignments.
Jean Perier67169232023-06-26 13:06:43 +02004826 if (!isWholeAllocatableAssignment &&
4827 !isUserDefAssignToPointerOrAllocatable)
Jean Perierb87e6552023-05-09 09:18:53 +02004828 lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
4829 return lhs;
4830 };
4831
4832 if (!isInsideHlfirForallOrWhere() && !lhsHasVectorSubscripts &&
4833 !userDefinedAssignment) {
4834 Fortran::lower::StatementContext localStmtCtx;
4835 hlfir::Entity rhs = evaluateRhs(localStmtCtx);
4836 hlfir::Entity lhs = evaluateLhs(localStmtCtx);
Valentin Clement (バレンタイン クレメン)eb5907d2024-04-26 13:31:34 -07004837 if (isCUDATransfer && !hasCUDAImplicitTransfer)
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004838 genCUDADataTransfer(builder, loc, assign, lhs, rhs);
4839 else
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004840 builder.create<hlfir::AssignOp>(loc, rhs, lhs,
4841 isWholeAllocatableAssignment,
4842 keepLhsLengthInAllocatableAssignment);
Valentin Clement (バレンタイン クレメン)5cfd5d12024-04-25 08:50:34 -07004843 if (hasCUDAImplicitTransfer && !isInDeviceContext) {
Valentin Clement (バレンタイン クレメン)953aa102024-04-05 09:11:37 -07004844 localSymbols.popScope();
4845 for (mlir::Value temp : implicitTemps)
4846 builder.create<fir::FreeMemOp>(loc, temp);
Valentin Clement (バレンタイン クレメン)4e6745c2024-03-25 11:53:39 -07004847 }
Jean Perierb87e6552023-05-09 09:18:53 +02004848 return;
4849 }
4850 // Assignments inside Forall, Where, or assignments to a vector subscripted
4851 // left-hand side requires using an hlfir.region_assign in HLFIR. The
4852 // right-hand side and left-hand side must be evaluated inside the
4853 // hlfir.region_assign regions.
4854 auto regionAssignOp = builder.create<hlfir::RegionAssignOp>(loc);
4855
4856 // Lower RHS in its own region.
4857 builder.createBlock(&regionAssignOp.getRhsRegion());
4858 Fortran::lower::StatementContext rhsContext;
4859 hlfir::Entity rhs = evaluateRhs(rhsContext);
4860 auto rhsYieldOp = builder.create<hlfir::YieldOp>(loc, rhs);
jeanPerierc7c56662024-05-14 13:34:46 +02004861 Fortran::lower::genCleanUpInRegionIfAny(
4862 loc, builder, rhsYieldOp.getCleanup(), rhsContext);
Jean Perierb87e6552023-05-09 09:18:53 +02004863 // Lower LHS in its own region.
4864 builder.createBlock(&regionAssignOp.getLhsRegion());
4865 Fortran::lower::StatementContext lhsContext;
Jean Perier67169232023-06-26 13:06:43 +02004866 mlir::Value lhsYield = nullptr;
Jean Perierb87e6552023-05-09 09:18:53 +02004867 if (!lhsHasVectorSubscripts) {
4868 hlfir::Entity lhs = evaluateLhs(lhsContext);
4869 auto lhsYieldOp = builder.create<hlfir::YieldOp>(loc, lhs);
jeanPerierc7c56662024-05-14 13:34:46 +02004870 Fortran::lower::genCleanUpInRegionIfAny(
4871 loc, builder, lhsYieldOp.getCleanup(), lhsContext);
Jean Perier67169232023-06-26 13:06:43 +02004872 lhsYield = lhs;
Jean Perierb87e6552023-05-09 09:18:53 +02004873 } else {
Jean Perierc7ff45a2023-05-09 09:22:24 +02004874 hlfir::ElementalAddrOp elementalAddr =
4875 Fortran::lower::convertVectorSubscriptedExprToElementalAddr(
4876 loc, *this, assign.lhs, localSymbols, lhsContext);
jeanPerierc7c56662024-05-14 13:34:46 +02004877 Fortran::lower::genCleanUpInRegionIfAny(
4878 loc, builder, elementalAddr.getCleanup(), lhsContext);
Jean Perier67169232023-06-26 13:06:43 +02004879 lhsYield = elementalAddr.getYieldOp().getEntity();
Jean Perierb87e6552023-05-09 09:18:53 +02004880 }
Jean Perier67169232023-06-26 13:06:43 +02004881 assert(lhsYield && "must have been set");
Jean Perierb87e6552023-05-09 09:18:53 +02004882
4883 // Add "realloc" flag to hlfir.region_assign.
4884 if (isWholeAllocatableAssignment)
4885 TODO(loc, "assignment to a whole allocatable inside FORALL");
Jean Perierb87e6552023-05-09 09:18:53 +02004886
Jean Perier67169232023-06-26 13:06:43 +02004887 // Generate the hlfir.region_assign userDefinedAssignment region.
4888 if (userDefinedAssignment) {
4889 mlir::Type rhsType = rhs.getType();
4890 mlir::Type lhsType = lhsYield.getType();
4891 if (userDefinedAssignment->IsElemental()) {
4892 rhsType = hlfir::getEntityElementType(rhs);
4893 lhsType = hlfir::getEntityElementType(hlfir::Entity{lhsYield});
4894 }
4895 builder.createBlock(&regionAssignOp.getUserDefinedAssignment(),
4896 mlir::Region::iterator{}, {rhsType, lhsType},
4897 {loc, loc});
4898 auto end = builder.create<fir::FirEndOp>(loc);
4899 builder.setInsertionPoint(end);
4900 hlfir::Entity lhsBlockArg{regionAssignOp.getUserAssignmentLhs()};
4901 hlfir::Entity rhsBlockArg{regionAssignOp.getUserAssignmentRhs()};
4902 Fortran::lower::convertUserDefinedAssignmentToHLFIR(
4903 loc, *this, *userDefinedAssignment, lhsBlockArg, rhsBlockArg,
4904 localSymbols);
4905 }
Jean Perierb87e6552023-05-09 09:18:53 +02004906 builder.setInsertionPointAfter(regionAssignOp);
Slava Zakharinec2c0e02023-05-04 08:47:28 -07004907 }
4908
Valentin Clementfe252f82022-03-22 15:40:32 +01004909 /// Shared for both assignments and pointer assignments.
4910 void genAssignment(const Fortran::evaluate::Assignment &assign) {
Valentin Clementfe252f82022-03-22 15:40:32 +01004911 mlir::Location loc = toLocation();
Jean Perier7531c872023-01-20 14:05:42 +01004912 if (lowerToHighLevelFIR()) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07004913 Fortran::common::visit(
Jean Perierdd73bfa2022-11-15 12:01:21 +01004914 Fortran::common::visitors{
Jean Perierdd73bfa2022-11-15 12:01:21 +01004915 [&](const Fortran::evaluate::Assignment::Intrinsic &) {
Jean Perierb87e6552023-05-09 09:18:53 +02004916 genDataAssignment(assign, /*userDefinedAssignment=*/nullptr);
Jean Perierdd73bfa2022-11-15 12:01:21 +01004917 },
Jean Perierdd73bfa2022-11-15 12:01:21 +01004918 [&](const Fortran::evaluate::ProcedureRef &procRef) {
Jean Perierb87e6552023-05-09 09:18:53 +02004919 genDataAssignment(assign, /*userDefinedAssignment=*/&procRef);
Jean Perierdd73bfa2022-11-15 12:01:21 +01004920 },
Jean Perierdd73bfa2022-11-15 12:01:21 +01004921 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
Jean Perierb87e6552023-05-09 09:18:53 +02004922 if (isInsideHlfirForallOrWhere())
jeanPerier3ff3b292025-03-14 10:51:46 +01004923 genForallPointerAssignment(loc, assign);
jeanPerier7302e1b2025-03-05 11:24:04 +01004924 else
4925 genPointerAssignment(loc, assign, lbExprs);
Jean Perierdd73bfa2022-11-15 12:01:21 +01004926 },
Jean Perier7531c872023-01-20 14:05:42 +01004927 [&](const Fortran::evaluate::Assignment::BoundsRemapping
4928 &boundExprs) {
Jean Perierb87e6552023-05-09 09:18:53 +02004929 if (isInsideHlfirForallOrWhere())
jeanPerier3ff3b292025-03-14 10:51:46 +01004930 genForallPointerAssignment(loc, assign);
4931 else
4932 genPointerAssignment(loc, assign, boundExprs);
Jean Perierdd73bfa2022-11-15 12:01:21 +01004933 },
4934 },
4935 assign.u);
4936 return;
4937 }
Valentin Clementfe252f82022-03-22 15:40:32 +01004938 if (explicitIterationSpace()) {
4939 Fortran::lower::createArrayLoads(*this, explicitIterSpace, localSymbols);
4940 explicitIterSpace.genLoopNest();
4941 }
Jean Perier7531c872023-01-20 14:05:42 +01004942 Fortran::lower::StatementContext stmtCtx;
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07004943 Fortran::common::visit(
Valentin Clementfe252f82022-03-22 15:40:32 +01004944 Fortran::common::visitors{
4945 // [1] Plain old assignment.
4946 [&](const Fortran::evaluate::Assignment::Intrinsic &) {
4947 const Fortran::semantics::Symbol *sym =
4948 Fortran::evaluate::GetLastSymbol(assign.lhs);
4949
4950 if (!sym)
4951 TODO(loc, "assignment to pointer result of function reference");
4952
4953 std::optional<Fortran::evaluate::DynamicType> lhsType =
4954 assign.lhs.GetType();
4955 assert(lhsType && "lhs cannot be typeless");
Valentin Clement33c29a82023-02-21 10:14:00 +01004956 std::optional<Fortran::evaluate::DynamicType> rhsType =
4957 assign.rhs.GetType();
Valentin Clement97492fd1a2023-01-31 13:46:12 +01004958
Valentin Clement33c29a82023-02-21 10:14:00 +01004959 // Assignment to/from polymorphic entities are done with the
4960 // runtime.
4961 if (lhsType->IsPolymorphic() ||
4962 lhsType->IsUnlimitedPolymorphic() ||
Peter Steinfeld18983df2023-02-22 10:51:54 -08004963 (rhsType && (rhsType->IsPolymorphic() ||
4964 rhsType->IsUnlimitedPolymorphic()))) {
Valentin Clement33c29a82023-02-21 10:14:00 +01004965 mlir::Value lhs;
4966 if (Fortran::lower::isWholeAllocatable(assign.lhs))
4967 lhs = genExprMutableBox(loc, assign.lhs).getAddr();
4968 else
4969 lhs = fir::getBase(genExprBox(loc, assign.lhs, stmtCtx));
Valentin Clementf8ea3492022-12-02 15:51:01 +01004970 mlir::Value rhs =
4971 fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
Valentin Clement4f3c98542023-03-06 09:35:36 +01004972 if ((lhsType->IsPolymorphic() ||
4973 lhsType->IsUnlimitedPolymorphic()) &&
4974 Fortran::lower::isWholeAllocatable(assign.lhs))
4975 fir::runtime::genAssignPolymorphic(*builder, loc, lhs, rhs);
4976 else
4977 fir::runtime::genAssign(*builder, loc, lhs, rhs);
Valentin Clementf8ea3492022-12-02 15:51:01 +01004978 return;
4979 }
Valentin Clementfe252f82022-03-22 15:40:32 +01004980
4981 // Note: No ad-hoc handling for pointers is required here. The
4982 // target will be assigned as per 2018 10.2.1.3 p2. genExprAddr
4983 // on a pointer returns the target address and not the address of
4984 // the pointer variable.
4985
4986 if (assign.lhs.Rank() > 0 || explicitIterationSpace()) {
Valentin Clement97492fd1a2023-01-31 13:46:12 +01004987 if (isDerivedCategory(lhsType->category()) &&
4988 Fortran::semantics::IsFinalizable(
4989 lhsType->GetDerivedTypeSpec()))
4990 TODO(loc, "derived-type finalization with array assignment");
Valentin Clementfe252f82022-03-22 15:40:32 +01004991 // Array assignment
4992 // See Fortran 2018 10.2.1.3 p5, p6, and p7
4993 genArrayAssignment(assign, stmtCtx);
4994 return;
4995 }
4996
4997 // Scalar assignment
4998 const bool isNumericScalar =
4999 isNumericScalarCategory(lhsType->category());
Kelvin Lief934172023-05-23 19:02:49 -04005000 const bool isVector =
5001 isDerivedCategory(lhsType->category()) &&
5002 lhsType->GetDerivedTypeSpec().IsVectorType();
5003 fir::ExtendedValue rhs = (isNumericScalar || isVector)
Valentin Clementfe252f82022-03-22 15:40:32 +01005004 ? genExprValue(assign.rhs, stmtCtx)
5005 : genExprAddr(assign.rhs, stmtCtx);
Eric Schweitz1bffc752022-04-22 13:59:17 -07005006 const bool lhsIsWholeAllocatable =
5007 Fortran::lower::isWholeAllocatable(assign.lhs);
Kazu Hiratac0921582023-01-07 22:26:48 -08005008 std::optional<fir::factory::MutableBoxReallocation> lhsRealloc;
5009 std::optional<fir::MutableBoxValue> lhsMutableBox;
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005010
Valentin Clement7f0074a2023-02-03 12:21:59 +01005011 // Set flag to know if the LHS needs finalization. Polymorphic,
5012 // unlimited polymorphic assignment will be done with genAssign.
5013 // Assign runtime function performs the finalization.
5014 bool needFinalization = !lhsType->IsPolymorphic() &&
5015 !lhsType->IsUnlimitedPolymorphic() &&
5016 (isDerivedCategory(lhsType->category()) &&
5017 Fortran::semantics::IsFinalizable(
5018 lhsType->GetDerivedTypeSpec()));
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005019
Valentin Clementfe252f82022-03-22 15:40:32 +01005020 auto lhs = [&]() -> fir::ExtendedValue {
5021 if (lhsIsWholeAllocatable) {
5022 lhsMutableBox = genExprMutableBox(loc, assign.lhs);
Valentin Clement7f0074a2023-02-03 12:21:59 +01005023 // Finalize if needed.
5024 if (needFinalization) {
5025 mlir::Value isAllocated =
5026 fir::factory::genIsAllocatedOrAssociatedTest(
5027 *builder, loc, *lhsMutableBox);
5028 builder->genIfThen(loc, isAllocated)
5029 .genThen([&]() {
5030 fir::runtime::genDerivedTypeDestroy(
5031 *builder, loc, fir::getBase(*lhsMutableBox));
5032 })
5033 .end();
5034 needFinalization = false;
5035 }
5036
Valentin Clementfe252f82022-03-22 15:40:32 +01005037 llvm::SmallVector<mlir::Value> lengthParams;
5038 if (const fir::CharBoxValue *charBox = rhs.getCharBox())
5039 lengthParams.push_back(charBox->getLen());
Eric Schweitz1bffc752022-04-22 13:59:17 -07005040 else if (fir::isDerivedWithLenParameters(rhs))
Valentin Clementfe252f82022-03-22 15:40:32 +01005041 TODO(loc, "assignment to derived type allocatable with "
Valentin Clement0dd4fb02022-07-01 10:36:45 +02005042 "LEN parameters");
Valentin Clementfe252f82022-03-22 15:40:32 +01005043 lhsRealloc = fir::factory::genReallocIfNeeded(
5044 *builder, loc, *lhsMutableBox,
Kazu Hirata9a417392022-12-03 12:14:21 -08005045 /*shape=*/std::nullopt, lengthParams);
Valentin Clementfe252f82022-03-22 15:40:32 +01005046 return lhsRealloc->newValue;
5047 }
5048 return genExprAddr(assign.lhs, stmtCtx);
5049 }();
5050
Kelvin Lief934172023-05-23 19:02:49 -04005051 if (isNumericScalar || isVector) {
Valentin Clementfe252f82022-03-22 15:40:32 +01005052 // Fortran 2018 10.2.1.3 p8 and p9
5053 // Conversions should have been inserted by semantic analysis,
5054 // but they can be incorrect between the rhs and lhs. Correct
5055 // that here.
5056 mlir::Value addr = fir::getBase(lhs);
5057 mlir::Value val = fir::getBase(rhs);
5058 // A function with multiple entry points returning different
5059 // types tags all result variables with one of the largest
V Donaldson2c143342023-02-27 14:05:53 -08005060 // types to allow them to share the same storage. Assignment
Valentin Clementfe252f82022-03-22 15:40:32 +01005061 // to a result variable of one of the other types requires
5062 // conversion to the actual type.
5063 mlir::Type toTy = genType(assign.lhs);
Mark Daniala1c736e2023-08-22 12:10:08 -04005064
5065 // If Cray pointee, need to handle the address
5066 // Array is handled in genCoordinateOp.
5067 if (sym->test(Fortran::semantics::Symbol::Flag::CrayPointee) &&
5068 sym->Rank() == 0) {
5069 // get the corresponding Cray pointer
5070
jeanPerierde7a50f2024-03-22 11:13:04 +01005071 const Fortran::semantics::Symbol &ptrSym =
5072 Fortran::semantics::GetCrayPointer(*sym);
Mark Daniala1c736e2023-08-22 12:10:08 -04005073 fir::ExtendedValue ptr =
5074 getSymbolExtendedValue(ptrSym, nullptr);
5075 mlir::Value ptrVal = fir::getBase(ptr);
jeanPerierde7a50f2024-03-22 11:13:04 +01005076 mlir::Type ptrTy = genType(ptrSym);
Mark Daniala1c736e2023-08-22 12:10:08 -04005077
5078 fir::ExtendedValue pte =
5079 getSymbolExtendedValue(*sym, nullptr);
5080 mlir::Value pteVal = fir::getBase(pte);
5081 mlir::Value cnvrt = Fortran::lower::addCrayPointerInst(
5082 loc, *builder, ptrVal, ptrTy, pteVal.getType());
5083 addr = builder->create<fir::LoadOp>(loc, cnvrt);
5084 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005085 mlir::Value cast =
Kelvin Lief934172023-05-23 19:02:49 -04005086 isVector ? val
5087 : builder->convertWithSemantics(loc, toTy, val);
Valentin Clementfe252f82022-03-22 15:40:32 +01005088 if (fir::dyn_cast_ptrEleTy(addr.getType()) != toTy) {
5089 assert(isFuncResultDesignator(assign.lhs) && "type mismatch");
5090 addr = builder->createConvert(
5091 toLocation(), builder->getRefType(toTy), addr);
5092 }
5093 builder->create<fir::StoreOp>(loc, cast, addr);
5094 } else if (isCharacterCategory(lhsType->category())) {
5095 // Fortran 2018 10.2.1.3 p10 and p11
5096 fir::factory::CharacterExprHelper{*builder, loc}.createAssign(
5097 lhs, rhs);
5098 } else if (isDerivedCategory(lhsType->category())) {
Valentin Clement6472a2e2023-03-14 16:01:36 +01005099 // Handle parent component.
5100 if (Fortran::lower::isParentComponent(assign.lhs)) {
Christian Siggfac349a2024-04-28 22:01:42 +02005101 if (!mlir::isa<fir::BaseBoxType>(fir::getBase(lhs).getType()))
Valentin Clement6472a2e2023-03-14 16:01:36 +01005102 lhs = fir::getBase(builder->createBox(loc, lhs));
5103 lhs = Fortran::lower::updateBoxForParentComponent(*this, lhs,
5104 assign.lhs);
5105 }
5106
Valentin Clementfe252f82022-03-22 15:40:32 +01005107 // Fortran 2018 10.2.1.3 p13 and p14
5108 // Recursively gen an assignment on each element pair.
Valentin Clement7f0074a2023-02-03 12:21:59 +01005109 fir::factory::genRecordAssignment(*builder, loc, lhs, rhs,
5110 needFinalization);
Valentin Clementfe252f82022-03-22 15:40:32 +01005111 } else {
5112 llvm_unreachable("unknown category");
5113 }
Peter Klauslera8234192022-12-19 12:41:25 -08005114 if (lhsIsWholeAllocatable) {
5115 assert(lhsRealloc.has_value());
Fangrui Song15a9a722022-12-17 22:22:47 +00005116 fir::factory::finalizeRealloc(*builder, loc, *lhsMutableBox,
5117 /*lbounds=*/std::nullopt,
5118 /*takeLboundsIfRealloc=*/false,
5119 *lhsRealloc);
Peter Klauslera8234192022-12-19 12:41:25 -08005120 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005121 },
5122
5123 // [2] User defined assignment. If the context is a scalar
5124 // expression then call the procedure.
5125 [&](const Fortran::evaluate::ProcedureRef &procRef) {
5126 Fortran::lower::StatementContext &ctx =
5127 explicitIterationSpace() ? explicitIterSpace.stmtContext()
5128 : stmtCtx;
5129 Fortran::lower::createSubroutineCall(
5130 *this, procRef, explicitIterSpace, implicitIterSpace,
5131 localSymbols, ctx, /*isUserDefAssignment=*/true);
5132 },
5133
Valentin Clementfe252f82022-03-22 15:40:32 +01005134 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
Jean Perier7531c872023-01-20 14:05:42 +01005135 return genPointerAssignment(loc, assign, lbExprs);
Valentin Clementfe252f82022-03-22 15:40:32 +01005136 },
Valentin Clementfe252f82022-03-22 15:40:32 +01005137 [&](const Fortran::evaluate::Assignment::BoundsRemapping
5138 &boundExprs) {
Jean Perier7531c872023-01-20 14:05:42 +01005139 return genPointerAssignment(loc, assign, boundExprs);
Valentin Clementfe252f82022-03-22 15:40:32 +01005140 },
5141 },
5142 assign.u);
5143 if (explicitIterationSpace())
5144 Fortran::lower::createArrayMergeStores(*this, explicitIterSpace);
5145 }
5146
Jean Perier54c88fc2023-05-09 09:21:09 +02005147 // Is the insertion point of the builder directly or indirectly set
5148 // inside any operation of type "Op"?
5149 template <typename... Op>
5150 bool isInsideOp() const {
Jean Perierb87e6552023-05-09 09:18:53 +02005151 mlir::Block *block = builder->getInsertionBlock();
5152 mlir::Operation *op = block ? block->getParentOp() : nullptr;
5153 while (op) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005154 if (mlir::isa<Op...>(op))
Jean Perierb87e6552023-05-09 09:18:53 +02005155 return true;
5156 op = op->getParentOp();
5157 }
5158 return false;
5159 }
Jean Perier54c88fc2023-05-09 09:21:09 +02005160 bool isInsideHlfirForallOrWhere() const {
5161 return isInsideOp<hlfir::ForallOp, hlfir::WhereOp>();
5162 }
5163 bool isInsideHlfirWhere() const { return isInsideOp<hlfir::WhereOp>(); }
Jean Perierb87e6552023-05-09 09:18:53 +02005164
Valentin Clement99075912022-02-01 13:49:49 +01005165 void genFIR(const Fortran::parser::WhereConstruct &c) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005166 mlir::Location loc = getCurrentLocation();
5167 hlfir::WhereOp whereOp;
5168
5169 if (!lowerToHighLevelFIR()) {
5170 implicitIterSpace.growStack();
5171 } else {
5172 whereOp = builder->create<hlfir::WhereOp>(loc);
5173 builder->createBlock(&whereOp.getMaskRegion());
5174 }
5175
5176 // Lower the where mask. For HLFIR, this is done in the hlfir.where mask
5177 // region.
Valentin Clement7a6a1652022-03-10 18:43:40 +01005178 genNestedStatement(
5179 std::get<
5180 Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
5181 c.t));
Jean Perier54c88fc2023-05-09 09:21:09 +02005182
5183 // Lower WHERE body. For HLFIR, this is done in the hlfir.where body
5184 // region.
5185 if (whereOp)
5186 builder->createBlock(&whereOp.getBody());
5187
Valentin Clement7a6a1652022-03-10 18:43:40 +01005188 for (const auto &body :
5189 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
5190 genFIR(body);
5191 for (const auto &e :
5192 std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
5193 c.t))
5194 genFIR(e);
5195 if (const auto &e =
5196 std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
5197 c.t);
5198 e.has_value())
5199 genFIR(*e);
5200 genNestedStatement(
5201 std::get<Fortran::parser::Statement<Fortran::parser::EndWhereStmt>>(
5202 c.t));
Jean Perier54c88fc2023-05-09 09:21:09 +02005203
5204 if (whereOp) {
5205 // For HLFIR, create fir.end terminator in the last hlfir.elsewhere, or
5206 // in the hlfir.where if it had no elsewhere.
5207 builder->create<fir::FirEndOp>(loc);
5208 builder->setInsertionPointAfter(whereOp);
5209 }
Valentin Clement99075912022-02-01 13:49:49 +01005210 }
Valentin Clement99075912022-02-01 13:49:49 +01005211 void genFIR(const Fortran::parser::WhereBodyConstruct &body) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07005212 Fortran::common::visit(
Valentin Clement7a6a1652022-03-10 18:43:40 +01005213 Fortran::common::visitors{
5214 [&](const Fortran::parser::Statement<
5215 Fortran::parser::AssignmentStmt> &stmt) {
5216 genNestedStatement(stmt);
5217 },
5218 [&](const Fortran::parser::Statement<Fortran::parser::WhereStmt>
5219 &stmt) { genNestedStatement(stmt); },
5220 [&](const Fortran::common::Indirection<
5221 Fortran::parser::WhereConstruct> &c) { genFIR(c.value()); },
5222 },
5223 body.u);
Valentin Clement99075912022-02-01 13:49:49 +01005224 }
Jean Perier54c88fc2023-05-09 09:21:09 +02005225
5226 /// Lower a Where or Elsewhere mask into an hlfir mask region.
5227 void lowerWhereMaskToHlfir(mlir::Location loc,
5228 const Fortran::semantics::SomeExpr *maskExpr) {
5229 assert(maskExpr && "mask semantic analysis failed");
5230 Fortran::lower::StatementContext maskContext;
5231 hlfir::Entity mask = Fortran::lower::convertExprToHLFIR(
5232 loc, *this, *maskExpr, localSymbols, maskContext);
5233 mask = hlfir::loadTrivialScalar(loc, *builder, mask);
5234 auto yieldOp = builder->create<hlfir::YieldOp>(loc, mask);
jeanPerierc7c56662024-05-14 13:34:46 +02005235 Fortran::lower::genCleanUpInRegionIfAny(loc, *builder, yieldOp.getCleanup(),
5236 maskContext);
Jean Perier54c88fc2023-05-09 09:21:09 +02005237 }
Valentin Clement99075912022-02-01 13:49:49 +01005238 void genFIR(const Fortran::parser::WhereConstructStmt &stmt) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005239 const Fortran::semantics::SomeExpr *maskExpr = Fortran::semantics::GetExpr(
5240 std::get<Fortran::parser::LogicalExpr>(stmt.t));
5241 if (lowerToHighLevelFIR())
5242 lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr);
5243 else
5244 implicitIterSpace.append(maskExpr);
Valentin Clement99075912022-02-01 13:49:49 +01005245 }
Valentin Clement99075912022-02-01 13:49:49 +01005246 void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005247 mlir::Location loc = getCurrentLocation();
5248 hlfir::ElseWhereOp elsewhereOp;
5249 if (lowerToHighLevelFIR()) {
5250 elsewhereOp = builder->create<hlfir::ElseWhereOp>(loc);
5251 // Lower mask in the mask region.
5252 builder->createBlock(&elsewhereOp.getMaskRegion());
5253 }
Valentin Clement7a6a1652022-03-10 18:43:40 +01005254 genNestedStatement(
5255 std::get<
5256 Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
5257 ew.t));
Jean Perier54c88fc2023-05-09 09:21:09 +02005258
5259 // For HLFIR, lower the body in the hlfir.elsewhere body region.
5260 if (elsewhereOp)
5261 builder->createBlock(&elsewhereOp.getBody());
5262
Valentin Clement7a6a1652022-03-10 18:43:40 +01005263 for (const auto &body :
5264 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
5265 genFIR(body);
Valentin Clement99075912022-02-01 13:49:49 +01005266 }
Valentin Clement99075912022-02-01 13:49:49 +01005267 void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005268 const auto *maskExpr = Fortran::semantics::GetExpr(
5269 std::get<Fortran::parser::LogicalExpr>(stmt.t));
5270 if (lowerToHighLevelFIR())
5271 lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr);
5272 else
5273 implicitIterSpace.append(maskExpr);
Valentin Clement99075912022-02-01 13:49:49 +01005274 }
Valentin Clement99075912022-02-01 13:49:49 +01005275 void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005276 if (lowerToHighLevelFIR()) {
5277 auto elsewhereOp =
5278 builder->create<hlfir::ElseWhereOp>(getCurrentLocation());
5279 builder->createBlock(&elsewhereOp.getBody());
5280 }
Valentin Clement7a6a1652022-03-10 18:43:40 +01005281 genNestedStatement(
5282 std::get<Fortran::parser::Statement<Fortran::parser::ElsewhereStmt>>(
5283 ew.t));
5284 for (const auto &body :
5285 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
5286 genFIR(body);
Valentin Clement99075912022-02-01 13:49:49 +01005287 }
Valentin Clement99075912022-02-01 13:49:49 +01005288 void genFIR(const Fortran::parser::ElsewhereStmt &stmt) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005289 if (!lowerToHighLevelFIR())
5290 implicitIterSpace.append(nullptr);
Valentin Clement99075912022-02-01 13:49:49 +01005291 }
Valentin Clement99075912022-02-01 13:49:49 +01005292 void genFIR(const Fortran::parser::EndWhereStmt &) {
Jean Perier54c88fc2023-05-09 09:21:09 +02005293 if (!lowerToHighLevelFIR())
5294 implicitIterSpace.shrinkStack();
Valentin Clement99075912022-02-01 13:49:49 +01005295 }
5296
5297 void genFIR(const Fortran::parser::WhereStmt &stmt) {
Valentin Clement7a6a1652022-03-10 18:43:40 +01005298 Fortran::lower::StatementContext stmtCtx;
5299 const auto &assign = std::get<Fortran::parser::AssignmentStmt>(stmt.t);
Jean Perier54c88fc2023-05-09 09:21:09 +02005300 const auto *mask = Fortran::semantics::GetExpr(
5301 std::get<Fortran::parser::LogicalExpr>(stmt.t));
5302 if (lowerToHighLevelFIR()) {
5303 mlir::Location loc = getCurrentLocation();
5304 auto whereOp = builder->create<hlfir::WhereOp>(loc);
5305 builder->createBlock(&whereOp.getMaskRegion());
5306 lowerWhereMaskToHlfir(loc, mask);
5307 builder->createBlock(&whereOp.getBody());
5308 genAssignment(*assign.typedAssignment->v);
5309 builder->create<fir::FirEndOp>(loc);
5310 builder->setInsertionPointAfter(whereOp);
5311 return;
5312 }
Valentin Clement7a6a1652022-03-10 18:43:40 +01005313 implicitIterSpace.growStack();
Jean Perier54c88fc2023-05-09 09:21:09 +02005314 implicitIterSpace.append(mask);
Valentin Clement7a6a1652022-03-10 18:43:40 +01005315 genAssignment(*assign.typedAssignment->v);
5316 implicitIterSpace.shrinkStack();
Valentin Clement99075912022-02-01 13:49:49 +01005317 }
5318
5319 void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) {
Valentin Clement72276bd2022-03-10 20:19:57 +01005320 genAssignment(*stmt.typedAssignment->v);
Valentin Clement99075912022-02-01 13:49:49 +01005321 }
5322
5323 void genFIR(const Fortran::parser::AssignmentStmt &stmt) {
Valentin Clemente641c292022-02-17 18:23:22 +01005324 genAssignment(*stmt.typedAssignment->v);
Valentin Clement99075912022-02-01 13:49:49 +01005325 }
5326
5327 void genFIR(const Fortran::parser::SyncAllStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02005328 genSyncAllStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005329 }
5330
5331 void genFIR(const Fortran::parser::SyncImagesStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02005332 genSyncImagesStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005333 }
5334
5335 void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02005336 genSyncMemoryStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005337 }
5338
5339 void genFIR(const Fortran::parser::SyncTeamStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02005340 genSyncTeamStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005341 }
5342
5343 void genFIR(const Fortran::parser::UnlockStmt &stmt) {
Valentin Clement534b2282022-03-28 13:36:10 +02005344 genUnlockStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005345 }
5346
5347 void genFIR(const Fortran::parser::AssignStmt &stmt) {
Valentin Clement78a127a2022-03-08 20:17:48 +01005348 const Fortran::semantics::Symbol &symbol =
5349 *std::get<Fortran::parser::Name>(stmt.t).symbol;
5350 mlir::Location loc = toLocation();
5351 mlir::Value labelValue = builder->createIntegerConstant(
5352 loc, genType(symbol), std::get<Fortran::parser::Label>(stmt.t));
5353 builder->create<fir::StoreOp>(loc, labelValue, getSymbolAddress(symbol));
Valentin Clement99075912022-02-01 13:49:49 +01005354 }
5355
5356 void genFIR(const Fortran::parser::FormatStmt &) {
Valentin Clementd8222d92022-03-14 18:15:16 +01005357 // do nothing.
5358
5359 // FORMAT statements have no semantics. They may be lowered if used by a
5360 // data transfer statement.
Valentin Clement99075912022-02-01 13:49:49 +01005361 }
5362
5363 void genFIR(const Fortran::parser::PauseStmt &stmt) {
Valentin Clementdb01b122022-02-02 08:15:26 +01005364 genPauseStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005365 }
5366
Valentin Clementfe252f82022-03-22 15:40:32 +01005367 // call FAIL IMAGE in runtime
Valentin Clement99075912022-02-01 13:49:49 +01005368 void genFIR(const Fortran::parser::FailImageStmt &stmt) {
Kiran Chandramohanacd754402022-04-27 12:19:54 +00005369 genFailImageStatement(*this);
Valentin Clement99075912022-02-01 13:49:49 +01005370 }
5371
Valentin Clementaab42632022-02-01 20:53:00 +01005372 // call STOP, ERROR STOP in runtime
Valentin Clement99075912022-02-01 13:49:49 +01005373 void genFIR(const Fortran::parser::StopStmt &stmt) {
Valentin Clementaab42632022-02-01 20:53:00 +01005374 genStopStatement(*this, stmt);
Valentin Clement99075912022-02-01 13:49:49 +01005375 }
5376
5377 void genFIR(const Fortran::parser::ReturnStmt &stmt) {
Valentin Clement85b89ed2022-02-10 18:35:16 +01005378 Fortran::lower::pft::FunctionLikeUnit *funit =
5379 getEval().getOwningProcedure();
5380 assert(funit && "not inside main program, function or subroutine");
V Donaldson2c143342023-02-27 14:05:53 -08005381 for (auto it = activeConstructStack.rbegin(),
5382 rend = activeConstructStack.rend();
5383 it != rend; ++it) {
5384 it->stmtCtx.finalizeAndKeep();
5385 }
Valentin Clement85b89ed2022-02-10 18:35:16 +01005386 if (funit->isMainProgram()) {
khaki3ff7fca72024-11-15 08:44:42 -08005387 genExitRoutine(true);
Valentin Clement85b89ed2022-02-10 18:35:16 +01005388 return;
5389 }
5390 mlir::Location loc = toLocation();
5391 if (stmt.v) {
Valentin Clement8b503532022-03-15 22:03:14 +01005392 // Alternate return statement - If this is a subroutine where some
5393 // alternate entries have alternate returns, but the active entry point
V Donaldson2c143342023-02-27 14:05:53 -08005394 // does not, ignore the alternate return value. Otherwise, assign it
Valentin Clement8b503532022-03-15 22:03:14 +01005395 // to the compiler-generated result variable.
5396 const Fortran::semantics::Symbol &symbol = funit->getSubprogramSymbol();
5397 if (Fortran::semantics::HasAlternateReturns(symbol)) {
5398 Fortran::lower::StatementContext stmtCtx;
5399 const Fortran::lower::SomeExpr *expr =
5400 Fortran::semantics::GetExpr(*stmt.v);
5401 assert(expr && "missing alternate return expression");
5402 mlir::Value altReturnIndex = builder->createConvert(
5403 loc, builder->getIndexType(), createFIRExpr(loc, expr, stmtCtx));
5404 builder->create<fir::StoreOp>(loc, altReturnIndex,
5405 getAltReturnResult(symbol));
5406 }
Valentin Clement85b89ed2022-02-10 18:35:16 +01005407 }
5408 // Branch to the last block of the SUBROUTINE, which has the actual return.
5409 if (!funit->finalBlock) {
5410 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
Valentin Clement (バレンタイン クレメン)a9a5af82023-11-30 14:25:03 -08005411 Fortran::lower::setInsertionPointAfterOpenACCLoopIfInside(*builder);
Valentin Clement85b89ed2022-02-10 18:35:16 +01005412 funit->finalBlock = builder->createBlock(&builder->getRegion());
5413 builder->restoreInsertionPoint(insPt);
5414 }
Valentin Clement (バレンタイン クレメン)a9a5af82023-11-30 14:25:03 -08005415
5416 if (Fortran::lower::isInOpenACCLoop(*builder))
5417 Fortran::lower::genEarlyReturnInOpenACCLoop(*builder, loc);
5418 else
5419 builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock);
Valentin Clement99075912022-02-01 13:49:49 +01005420 }
5421
5422 void genFIR(const Fortran::parser::CycleStmt &) {
V Donaldson2c143342023-02-27 14:05:53 -08005423 genConstructExitBranch(*getEval().controlSuccessor);
Valentin Clement99075912022-02-01 13:49:49 +01005424 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005425 void genFIR(const Fortran::parser::ExitStmt &) {
V Donaldson2c143342023-02-27 14:05:53 -08005426 genConstructExitBranch(*getEval().controlSuccessor);
Valentin Clement99075912022-02-01 13:49:49 +01005427 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005428 void genFIR(const Fortran::parser::GotoStmt &) {
V Donaldson2c143342023-02-27 14:05:53 -08005429 genConstructExitBranch(*getEval().controlSuccessor);
Valentin Clement99075912022-02-01 13:49:49 +01005430 }
5431
Valentin Clement89275302022-02-01 15:26:47 +01005432 // Nop statements - No code, or code is generated at the construct level.
V Donaldson609b7892023-01-03 10:31:30 -08005433 // But note that the genFIR call immediately below that wraps one of these
5434 // calls does block management, possibly starting a new block, and possibly
5435 // generating a branch to end a block. So these calls may still be required
5436 // for that functionality.
Valentin Clementfe252f82022-03-22 15:40:32 +01005437 void genFIR(const Fortran::parser::AssociateStmt &) {} // nop
V Donaldson2c143342023-02-27 14:05:53 -08005438 void genFIR(const Fortran::parser::BlockStmt &) {} // nop
Valentin Clementfe252f82022-03-22 15:40:32 +01005439 void genFIR(const Fortran::parser::CaseStmt &) {} // nop
5440 void genFIR(const Fortran::parser::ContinueStmt &) {} // nop
5441 void genFIR(const Fortran::parser::ElseIfStmt &) {} // nop
5442 void genFIR(const Fortran::parser::ElseStmt &) {} // nop
5443 void genFIR(const Fortran::parser::EndAssociateStmt &) {} // nop
V Donaldson2c143342023-02-27 14:05:53 -08005444 void genFIR(const Fortran::parser::EndBlockStmt &) {} // nop
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00005445 void genFIR(const Fortran::parser::EndDoStmt &) {} // nop
Valentin Clementfe252f82022-03-22 15:40:32 +01005446 void genFIR(const Fortran::parser::EndFunctionStmt &) {} // nop
5447 void genFIR(const Fortran::parser::EndIfStmt &) {} // nop
5448 void genFIR(const Fortran::parser::EndMpSubprogramStmt &) {} // nop
Valentin Clement591e3e62023-02-01 15:53:52 +01005449 void genFIR(const Fortran::parser::EndProgramStmt &) {} // nop
Valentin Clementfe252f82022-03-22 15:40:32 +01005450 void genFIR(const Fortran::parser::EndSelectStmt &) {} // nop
5451 void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop
5452 void genFIR(const Fortran::parser::EntryStmt &) {} // nop
5453 void genFIR(const Fortran::parser::IfStmt &) {} // nop
5454 void genFIR(const Fortran::parser::IfThenStmt &) {} // nop
Kiran Chandramohanb5b3e502022-04-28 12:20:11 +00005455 void genFIR(const Fortran::parser::NonLabelDoStmt &) {} // nop
Kiran Chandramohanb85c39d2022-05-06 11:45:18 +00005456 void genFIR(const Fortran::parser::OmpEndLoopDirective &) {} // nop
Valentin Clementf677c5e2022-11-14 10:46:53 +01005457 void genFIR(const Fortran::parser::SelectTypeStmt &) {} // nop
5458 void genFIR(const Fortran::parser::TypeGuardStmt &) {} // nop
Valentin Clement99075912022-02-01 13:49:49 +01005459
V Donaldson609b7892023-01-03 10:31:30 -08005460 /// Generate FIR for Evaluation \p eval.
Valentin Clement99075912022-02-01 13:49:49 +01005461 void genFIR(Fortran::lower::pft::Evaluation &eval,
5462 bool unstructuredContext = true) {
V Donaldson609b7892023-01-03 10:31:30 -08005463 // Start a new unstructured block when applicable. When transitioning
5464 // from unstructured to structured code, unstructuredContext is true,
5465 // which accounts for the possibility that the structured code could be
5466 // a target that starts a new block.
5467 if (unstructuredContext)
Kiran Chandramohanae37bb92022-02-08 23:01:39 +00005468 maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured()
5469 ? eval.getFirstNestedEvaluation().block
5470 : eval.block);
Kiran Chandramohanae37bb92022-02-08 23:01:39 +00005471
V Donaldson609b7892023-01-03 10:31:30 -08005472 // Generate evaluation specific code. Even nop calls should usually reach
5473 // here in case they start a new block or require generation of a generic
5474 // end-of-block branch. An alternative is to add special case code
5475 // elsewhere, such as in the genFIR code for a parent construct.
Valentin Clement99075912022-02-01 13:49:49 +01005476 setCurrentEval(eval);
5477 setCurrentPosition(eval.position);
5478 eval.visit([&](const auto &stmt) { genFIR(stmt); });
Valentin Clement99075912022-02-01 13:49:49 +01005479 }
5480
Valentin Clementfe252f82022-03-22 15:40:32 +01005481 /// Map mlir function block arguments to the corresponding Fortran dummy
5482 /// variables. When the result is passed as a hidden argument, the Fortran
5483 /// result is also mapped. The symbol map is used to hold this mapping.
5484 void mapDummiesAndResults(Fortran::lower::pft::FunctionLikeUnit &funit,
5485 const Fortran::lower::CalleeInterface &callee) {
5486 assert(builder && "require a builder object at this point");
5487 using PassBy = Fortran::lower::CalleeInterface::PassEntityBy;
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005488 auto mapPassedEntity = [&](const auto arg, bool isResult = false) {
Valentin Clementfe252f82022-03-22 15:40:32 +01005489 if (arg.passBy == PassBy::AddressAndLength) {
Valentin Clementde3efd12022-09-24 08:58:50 +02005490 if (callee.characterize().IsBindC())
5491 return;
Valentin Clementfe252f82022-03-22 15:40:32 +01005492 // TODO: now that fir call has some attributes regarding character
5493 // return, PassBy::AddressAndLength should be retired.
5494 mlir::Location loc = toLocation();
5495 fir::factory::CharacterExprHelper charHelp{*builder, loc};
5496 mlir::Value box =
5497 charHelp.createEmboxChar(arg.firArgument, arg.firLength);
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005498 mapBlockArgToDummyOrResult(arg.entity->get(), box, isResult);
Valentin Clementfe252f82022-03-22 15:40:32 +01005499 } else {
5500 if (arg.entity.has_value()) {
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005501 mapBlockArgToDummyOrResult(arg.entity->get(), arg.firArgument,
5502 isResult);
Valentin Clementfe252f82022-03-22 15:40:32 +01005503 } else {
Jean Perier93129ca2022-12-20 13:49:38 +01005504 assert(funit.parentHasTupleHostAssoc() && "expect tuple argument");
Valentin Clementfe252f82022-03-22 15:40:32 +01005505 }
5506 }
5507 };
5508 for (const Fortran::lower::CalleeInterface::PassedEntity &arg :
5509 callee.getPassedArguments())
5510 mapPassedEntity(arg);
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005511 if (lowerToHighLevelFIR() && !callee.getPassedArguments().empty()) {
5512 mlir::Value scopeOp = builder->create<fir::DummyScopeOp>(toLocation());
5513 setDummyArgsScope(scopeOp);
5514 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005515 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5516 passedResult = callee.getPassedResult()) {
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005517 mapPassedEntity(*passedResult, /*isResult=*/true);
Valentin Clementfe252f82022-03-22 15:40:32 +01005518 // FIXME: need to make sure things are OK here. addSymbol may not be OK
5519 if (funit.primaryResult &&
5520 passedResult->entity->get() != *funit.primaryResult)
Jean Perierab9c4e92023-02-07 09:22:47 +01005521 mapBlockArgToDummyOrResult(
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005522 *funit.primaryResult, getSymbolAddress(passedResult->entity->get()),
5523 /*isResult=*/true);
Valentin Clementfe252f82022-03-22 15:40:32 +01005524 }
5525 }
5526
5527 /// Instantiate variable \p var and add it to the symbol map.
5528 /// See ConvertVariable.cpp.
5529 void instantiateVar(const Fortran::lower::pft::Variable &var,
5530 Fortran::lower::AggregateStoreMap &storeMap) {
5531 Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
Krzysztof Parzyszek82e91b92023-12-15 09:32:57 -06005532 if (var.hasSymbol())
5533 genOpenMPSymbolProperties(*this, var);
Valentin Clementfe252f82022-03-22 15:40:32 +01005534 }
5535
vdonaldson6003be72024-12-04 16:21:11 -05005536 /// Where applicable, save the exception state and halting, rounding, and
5537 /// underflow modes at function entry, and restore them at function exits.
vdonaldson3aba9262023-12-04 09:55:54 -08005538 void manageFPEnvironment(Fortran::lower::pft::FunctionLikeUnit &funit) {
5539 mlir::Location loc = toLocation();
5540 mlir::Location endLoc =
5541 toLocation(Fortran::lower::pft::stmtSourceLoc(funit.endStmt));
5542 if (funit.hasIeeeAccess) {
5543 // Subject to F18 Clause 17.1p3, 17.3p3 states: If a flag is signaling
5544 // on entry to a procedure [...], the processor will set it to quiet
5545 // on entry and restore it to signaling on return. If a flag signals
5546 // during execution of a procedure, the processor shall not set it to
5547 // quiet on return.
5548 mlir::func::FuncOp testExcept = fir::factory::getFetestexcept(*builder);
5549 mlir::func::FuncOp clearExcept = fir::factory::getFeclearexcept(*builder);
5550 mlir::func::FuncOp raiseExcept = fir::factory::getFeraiseexcept(*builder);
5551 mlir::Value ones = builder->createIntegerConstant(
5552 loc, testExcept.getFunctionType().getInput(0), -1);
5553 mlir::Value exceptSet =
5554 builder->create<fir::CallOp>(loc, testExcept, ones).getResult(0);
5555 builder->create<fir::CallOp>(loc, clearExcept, exceptSet);
5556 bridge.fctCtx().attachCleanup([=]() {
5557 builder->create<fir::CallOp>(endLoc, raiseExcept, exceptSet);
5558 });
5559 }
5560 if (funit.mayModifyHaltingMode) {
5561 // F18 Clause 17.6p1: In a procedure [...], the processor shall not
5562 // change the halting mode on entry, and on return shall ensure that
5563 // the halting mode is the same as it was on entry.
5564 mlir::func::FuncOp getExcept = fir::factory::getFegetexcept(*builder);
5565 mlir::func::FuncOp disableExcept =
5566 fir::factory::getFedisableexcept(*builder);
5567 mlir::func::FuncOp enableExcept =
5568 fir::factory::getFeenableexcept(*builder);
5569 mlir::Value exceptSet =
5570 builder->create<fir::CallOp>(loc, getExcept).getResult(0);
5571 mlir::Value ones = builder->createIntegerConstant(
5572 loc, disableExcept.getFunctionType().getInput(0), -1);
5573 bridge.fctCtx().attachCleanup([=]() {
5574 builder->create<fir::CallOp>(endLoc, disableExcept, ones);
5575 builder->create<fir::CallOp>(endLoc, enableExcept, exceptSet);
5576 });
5577 }
5578 if (funit.mayModifyRoundingMode) {
vdonaldson6003be72024-12-04 16:21:11 -05005579 // F18 Clause 17.4p5: In a procedure [...], the processor shall not
vdonaldson3aba9262023-12-04 09:55:54 -08005580 // change the rounding modes on entry, and on return shall ensure that
5581 // the rounding modes are the same as they were on entry.
5582 mlir::func::FuncOp getRounding =
5583 fir::factory::getLlvmGetRounding(*builder);
5584 mlir::func::FuncOp setRounding =
5585 fir::factory::getLlvmSetRounding(*builder);
5586 mlir::Value roundingMode =
5587 builder->create<fir::CallOp>(loc, getRounding).getResult(0);
5588 bridge.fctCtx().attachCleanup([=]() {
5589 builder->create<fir::CallOp>(endLoc, setRounding, roundingMode);
5590 });
5591 }
vdonaldson6003be72024-12-04 16:21:11 -05005592 if ((funit.mayModifyUnderflowMode) &&
5593 (bridge.getTargetCharacteristics().hasSubnormalFlushingControl(
5594 /*any=*/true))) {
5595 // F18 Clause 17.5p2: In a procedure [...], the processor shall not
5596 // change the underflow mode on entry, and on return shall ensure that
5597 // the underflow mode is the same as it was on entry.
5598 mlir::Value underflowMode =
5599 fir::runtime::genGetUnderflowMode(*builder, loc);
5600 bridge.fctCtx().attachCleanup([=]() {
5601 fir::runtime::genSetUnderflowMode(*builder, loc, {underflowMode});
5602 });
5603 }
vdonaldson3aba9262023-12-04 09:55:54 -08005604 }
5605
V Donaldson518e6f12022-12-12 14:20:06 -08005606 /// Start translation of a function.
Valentin Clementfe252f82022-03-22 15:40:32 +01005607 void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
5608 assert(!builder && "expected nullptr");
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005609 bridge.fctCtx().pushScope();
Valentin Clement (バレンタイン クレメン)a3700cc2023-11-14 14:42:11 -08005610 bridge.openAccCtx().pushScope();
V Donaldson518e6f12022-12-12 14:20:06 -08005611 const Fortran::semantics::Scope &scope = funit.getScope();
5612 LLVM_DEBUG(llvm::dbgs() << "\n[bridge - startNewFunction]";
5613 if (auto *sym = scope.symbol()) llvm::dbgs() << " " << *sym;
5614 llvm::dbgs() << "\n");
Valentin Clementfe252f82022-03-22 15:40:32 +01005615 Fortran::lower::CalleeInterface callee(funit, *this);
River Riddle58ceae92022-04-18 11:53:47 -07005616 mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments();
jeanPeriera4798bb2024-04-02 14:29:29 +02005617 builder =
5618 new fir::FirOpBuilder(func, bridge.getKindMap(), &mlirSymbolTable);
Valentin Clementfe252f82022-03-22 15:40:32 +01005619 assert(builder && "FirOpBuilder did not instantiate");
Slava Zakharin8f3f15c2022-11-07 09:05:27 -08005620 builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
Valentin Clementfe252f82022-03-22 15:40:32 +01005621 builder->setInsertionPointToStart(&func.front());
jeanPerier06f775a2024-02-28 14:30:29 +01005622 if (funit.parent.isA<Fortran::lower::pft::FunctionLikeUnit>()) {
5623 // Give internal linkage to internal functions. There are no name clash
5624 // risks, but giving global linkage to internal procedure will break the
5625 // static link register in shared libraries because of the system calls.
5626 // Also, it should be possible to eliminate the procedure code if all the
5627 // uses have been inlined.
5628 fir::factory::setInternalLinkage(func);
5629 } else {
5630 func.setVisibility(mlir::SymbolTable::Visibility::Public);
5631 }
V Donaldson2c143342023-02-27 14:05:53 -08005632 assert(blockId == 0 && "invalid blockId");
5633 assert(activeConstructStack.empty() && "invalid construct stack state");
Valentin Clementfe252f82022-03-22 15:40:32 +01005634
vdonaldson3aba9262023-12-04 09:55:54 -08005635 // Manage floating point exception, halting mode, and rounding mode
5636 // settings at function entry and exit.
5637 if (!funit.isMainProgram())
5638 manageFPEnvironment(funit);
V Donaldson09ea6922023-06-29 11:32:56 -07005639
Valentin Clementfe252f82022-03-22 15:40:32 +01005640 mapDummiesAndResults(funit, callee);
5641
Jean Perier93129ca2022-12-20 13:49:38 +01005642 // Map host associated symbols from parent procedure if any.
5643 if (funit.parentHasHostAssoc())
5644 funit.parentHostAssoc().internalProcedureBindings(*this, localSymbols);
5645
V Donaldson518e6f12022-12-12 14:20:06 -08005646 // Non-primary results of a function with multiple entry points.
5647 // These result values share storage with the primary result.
Valentin Clementfe252f82022-03-22 15:40:32 +01005648 llvm::SmallVector<Fortran::lower::pft::Variable> deferredFuncResultList;
5649
V Donaldson518e6f12022-12-12 14:20:06 -08005650 // Backup actual argument for entry character results with different
5651 // lengths. It needs to be added to the non-primary results symbol before
5652 // mapSymbolAttributes is called.
Valentin Clementfe252f82022-03-22 15:40:32 +01005653 Fortran::lower::SymbolBox resultArg;
5654 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5655 passedResult = callee.getPassedResult())
5656 resultArg = lookupSymbol(passedResult->entity->get());
5657
5658 Fortran::lower::AggregateStoreMap storeMap;
Valentin Clementfe252f82022-03-22 15:40:32 +01005659
V Donaldson518e6f12022-12-12 14:20:06 -08005660 // Map all containing submodule and module equivalences and variables, in
5661 // case they are referenced. It might be better to limit this to variables
5662 // that are actually referenced, although that is more complicated when
5663 // there are equivalenced variables.
5664 auto &scopeVariableListMap =
5665 Fortran::lower::pft::getScopeVariableListMap(funit);
5666 for (auto *scp = &scope.parent(); !scp->IsGlobal(); scp = &scp->parent())
5667 if (scp->kind() == Fortran::semantics::Scope::Kind::Module)
5668 for (const auto &var : Fortran::lower::pft::getScopeVariableList(
5669 *scp, scopeVariableListMap))
jeanPerier0a45d172024-02-05 10:12:33 +01005670 if (!var.isRuntimeTypeInfoData())
5671 instantiateVar(var, storeMap);
V Donaldson518e6f12022-12-12 14:20:06 -08005672
5673 // Map function equivalences and variables.
Valentin Clementfe252f82022-03-22 15:40:32 +01005674 mlir::Value primaryFuncResultStorage;
5675 for (const Fortran::lower::pft::Variable &var :
V Donaldson518e6f12022-12-12 14:20:06 -08005676 Fortran::lower::pft::getScopeVariableList(scope)) {
Valentin Clementfe252f82022-03-22 15:40:32 +01005677 // Always instantiate aggregate storage blocks.
5678 if (var.isAggregateStore()) {
5679 instantiateVar(var, storeMap);
5680 continue;
5681 }
5682 const Fortran::semantics::Symbol &sym = var.getSymbol();
5683 if (funit.parentHasHostAssoc()) {
V Donaldson518e6f12022-12-12 14:20:06 -08005684 // Never instantiate host associated variables, as they are already
5685 // instantiated from an argument tuple. Instead, just bind the symbol
5686 // to the host variable, which must be in the map.
Valentin Clementfe252f82022-03-22 15:40:32 +01005687 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
5688 if (funit.parentHostAssoc().isAssociated(ultimate)) {
Jean Perier93129ca2022-12-20 13:49:38 +01005689 copySymbolBinding(ultimate, sym);
Valentin Clementfe252f82022-03-22 15:40:32 +01005690 continue;
5691 }
5692 }
5693 if (!sym.IsFuncResult() || !funit.primaryResult) {
5694 instantiateVar(var, storeMap);
5695 } else if (&sym == funit.primaryResult) {
5696 instantiateVar(var, storeMap);
5697 primaryFuncResultStorage = getSymbolAddress(sym);
5698 } else {
5699 deferredFuncResultList.push_back(var);
5700 }
5701 }
5702
V Donaldson1e1f60c2022-05-24 10:06:24 -07005703 // TODO: should use same mechanism as equivalence?
5704 // One blocking point is character entry returns that need special handling
5705 // since they are not locally allocated but come as argument. CHARACTER(*)
5706 // is not something that fits well with equivalence lowering.
Valentin Clementfe252f82022-03-22 15:40:32 +01005707 for (const Fortran::lower::pft::Variable &altResult :
5708 deferredFuncResultList) {
Valentin Clementfe252f82022-03-22 15:40:32 +01005709 Fortran::lower::StatementContext stmtCtx;
Jean Perier9e373012022-10-18 11:07:47 +02005710 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5711 passedResult = callee.getPassedResult()) {
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005712 mapBlockArgToDummyOrResult(altResult.getSymbol(), resultArg.getAddr(),
5713 /*isResult=*/true);
Jean Perier9e373012022-10-18 11:07:47 +02005714 Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols,
5715 stmtCtx);
5716 } else {
Tom Eccles569716f2023-06-14 13:23:00 +00005717 // catch cases where the allocation for the function result storage type
5718 // doesn't match the type of this symbol
5719 mlir::Value preAlloc = primaryFuncResultStorage;
5720 mlir::Type resTy = primaryFuncResultStorage.getType();
5721 mlir::Type symTy = genType(altResult);
5722 mlir::Type wrappedSymTy = fir::ReferenceType::get(symTy);
5723 if (resTy != wrappedSymTy) {
5724 // check size of the pointed to type so we can't overflow by writing
5725 // double precision to a single precision allocation, etc
5726 LLVM_ATTRIBUTE_UNUSED auto getBitWidth = [this](mlir::Type ty) {
5727 // 15.6.2.6.3: differering result types should be integer, real,
5728 // complex or logical
jeanPerierc4204c02024-10-03 17:10:57 +02005729 if (auto cmplx = mlir::dyn_cast_or_null<mlir::ComplexType>(ty))
5730 return 2 * cmplx.getElementType().getIntOrFloatBitWidth();
Tom Eccles569716f2023-06-14 13:23:00 +00005731 if (auto logical = mlir::dyn_cast_or_null<fir::LogicalType>(ty)) {
5732 fir::KindTy kind = logical.getFKind();
5733 return builder->getKindMap().getLogicalBitsize(kind);
5734 }
5735 return ty.getIntOrFloatBitWidth();
5736 };
5737 assert(getBitWidth(fir::unwrapRefType(resTy)) >= getBitWidth(symTy));
5738
5739 // convert the storage to the symbol type so that the hlfir.declare
5740 // gets the correct type for this symbol
5741 preAlloc = builder->create<fir::ConvertOp>(getCurrentLocation(),
5742 wrappedSymTy, preAlloc);
5743 }
5744
Jean Perier9e373012022-10-18 11:07:47 +02005745 Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols,
Tom Eccles569716f2023-06-14 13:23:00 +00005746 stmtCtx, preAlloc);
Jean Perier9e373012022-10-18 11:07:47 +02005747 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005748 }
5749
V Donaldson1e1f60c2022-05-24 10:06:24 -07005750 // If this is a host procedure with host associations, then create the tuple
5751 // of pointers for passing to the internal procedures.
5752 if (!funit.getHostAssoc().empty())
5753 funit.getHostAssoc().hostProcedureBindings(*this, localSymbols);
5754
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005755 // Unregister all dummy symbols, so that their cloning (e.g. for OpenMP
5756 // privatization) does not create the cloned hlfir.declare operations
5757 // with dummy_scope operands.
5758 resetRegisteredDummySymbols();
5759
Valentin Clementfe252f82022-03-22 15:40:32 +01005760 // Create most function blocks in advance.
5761 createEmptyBlocks(funit.evaluationList);
5762
5763 // Reinstate entry block as the current insertion point.
5764 builder->setInsertionPointToEnd(&func.front());
5765
5766 if (callee.hasAlternateReturns()) {
5767 // Create a local temp to hold the alternate return index.
5768 // Give it an integer index type and the subroutine name (for dumps).
5769 // Attach it to the subroutine symbol in the localSymbols map.
5770 // Initialize it to zero, the "fallthrough" alternate return value.
5771 const Fortran::semantics::Symbol &symbol = funit.getSubprogramSymbol();
5772 mlir::Location loc = toLocation();
5773 mlir::Type idxTy = builder->getIndexType();
5774 mlir::Value altResult =
5775 builder->createTemporary(loc, idxTy, toStringRef(symbol.name()));
5776 addSymbol(symbol, altResult);
5777 mlir::Value zero = builder->createIntegerConstant(loc, idxTy, 0);
5778 builder->create<fir::StoreOp>(loc, zero, altResult);
5779 }
5780
5781 if (Fortran::lower::pft::Evaluation *alternateEntryEval =
5782 funit.getEntryEval())
V Donaldson2c143342023-02-27 14:05:53 -08005783 genBranch(alternateEntryEval->lexicalSuccessor->block);
Valentin Clementfe252f82022-03-22 15:40:32 +01005784 }
5785
V Donaldson2c143342023-02-27 14:05:53 -08005786 /// Create global blocks for the current function. This eliminates the
Valentin Clementfe252f82022-03-22 15:40:32 +01005787 /// distinction between forward and backward targets when generating
V Donaldson2c143342023-02-27 14:05:53 -08005788 /// branches. A block is "global" if it can be the target of a GOTO or
5789 /// other source code branch. A block that can only be targeted by a
5790 /// compiler generated branch is "local". For example, a DO loop preheader
5791 /// block containing loop initialization code is global. A loop header
5792 /// block, which is the target of the loop back edge, is local. Blocks
5793 /// belong to a region. Any block within a nested region must be replaced
5794 /// with a block belonging to that region. Branches may not cross region
Valentin Clementfe252f82022-03-22 15:40:32 +01005795 /// boundaries.
5796 void createEmptyBlocks(
5797 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
5798 mlir::Region *region = &builder->getRegion();
5799 for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
5800 if (eval.isNewBlock)
5801 eval.block = builder->createBlock(region);
5802 if (eval.isConstruct() || eval.isDirective()) {
5803 if (eval.lowerAsUnstructured()) {
5804 createEmptyBlocks(eval.getNestedEvaluations());
5805 } else if (eval.hasNestedEvaluations()) {
5806 // A structured construct that is a target starts a new block.
5807 Fortran::lower::pft::Evaluation &constructStmt =
5808 eval.getFirstNestedEvaluation();
5809 if (constructStmt.isNewBlock)
5810 constructStmt.block = builder->createBlock(region);
5811 }
5812 }
5813 }
5814 }
5815
5816 /// Return the predicate: "current block does not have a terminator branch".
5817 bool blockIsUnterminated() {
5818 mlir::Block *currentBlock = builder->getBlock();
5819 return currentBlock->empty() ||
5820 !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>();
5821 }
5822
5823 /// Unconditionally switch code insertion to a new block.
5824 void startBlock(mlir::Block *newBlock) {
5825 assert(newBlock && "missing block");
5826 // Default termination for the current block is a fallthrough branch to
5827 // the new block.
5828 if (blockIsUnterminated())
V Donaldson2c143342023-02-27 14:05:53 -08005829 genBranch(newBlock);
Valentin Clementfe252f82022-03-22 15:40:32 +01005830 // Some blocks may be re/started more than once, and might not be empty.
5831 // If the new block already has (only) a terminator, set the insertion
V Donaldson2c143342023-02-27 14:05:53 -08005832 // point to the start of the block. Otherwise set it to the end.
Valentin Clementfe252f82022-03-22 15:40:32 +01005833 builder->setInsertionPointToStart(newBlock);
5834 if (blockIsUnterminated())
5835 builder->setInsertionPointToEnd(newBlock);
5836 }
5837
5838 /// Conditionally switch code insertion to a new block.
5839 void maybeStartBlock(mlir::Block *newBlock) {
5840 if (newBlock)
5841 startBlock(newBlock);
5842 }
5843
Jean Perier23fbe522023-06-28 08:27:16 +02005844 void eraseDeadCodeAndBlocks(mlir::RewriterBase &rewriter,
5845 llvm::MutableArrayRef<mlir::Region> regions) {
Jan Sjodin45a96042023-07-10 10:55:47 -04005846 // WARNING: Do not add passes that can do folding or code motion here
5847 // because they might cross omp.target region boundaries, which can result
5848 // in incorrect code. Optimization passes like these must be added after
5849 // OMP early outlining has been done.
Jean Perier23fbe522023-06-28 08:27:16 +02005850 (void)mlir::eraseUnreachableBlocks(rewriter, regions);
5851 (void)mlir::runRegionDCE(rewriter, regions);
5852 }
5853
V Donaldson518e6f12022-12-12 14:20:06 -08005854 /// Finish translation of a function.
Valentin Clementfe252f82022-03-22 15:40:32 +01005855 void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
5856 setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt));
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005857 if (funit.isMainProgram()) {
khaki3ff7fca72024-11-15 08:44:42 -08005858 genExitRoutine(false);
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005859 } else {
Valentin Clementfe252f82022-03-22 15:40:32 +01005860 genFIRProcedureExit(funit, funit.getSubprogramSymbol());
Valentin Clement97492fd1a2023-01-31 13:46:12 +01005861 }
Valentin Clementfe252f82022-03-22 15:40:32 +01005862 funit.finalBlock = nullptr;
V Donaldson518e6f12022-12-12 14:20:06 -08005863 LLVM_DEBUG(llvm::dbgs() << "\n[bridge - endNewFunction";
5864 if (auto *sym = funit.scope->symbol()) llvm::dbgs()
5865 << " " << sym->name();
5866 llvm::dbgs() << "] generated IR:\n\n"
Valentin Clementfe252f82022-03-22 15:40:32 +01005867 << *builder->getFunction() << '\n');
V Donaldson518e6f12022-12-12 14:20:06 -08005868 // Eliminate dead code as a prerequisite to calling other IR passes.
5869 // FIXME: This simplification should happen in a normal pass, not here.
Valentin Clementfe252f82022-03-22 15:40:32 +01005870 mlir::IRRewriter rewriter(*builder);
Jean Perier23fbe522023-06-28 08:27:16 +02005871 (void)eraseDeadCodeAndBlocks(rewriter, {builder->getRegion()});
Valentin Clementfe252f82022-03-22 15:40:32 +01005872 delete builder;
5873 builder = nullptr;
5874 hostAssocTuple = mlir::Value{};
5875 localSymbols.clear();
V Donaldson2c143342023-02-27 14:05:53 -08005876 blockId = 0;
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005877 dummyArgsScope = mlir::Value{};
5878 resetRegisteredDummySymbols();
Valentin Clementfe252f82022-03-22 15:40:32 +01005879 }
5880
5881 /// Helper to generate GlobalOps when the builder is not positioned in any
5882 /// region block. This is required because the FirOpBuilder assumes it is
5883 /// always positioned inside a region block when creating globals, the easiest
5884 /// way comply is to create a dummy function and to throw it afterwards.
5885 void createGlobalOutsideOfFunctionLowering(
5886 const std::function<void()> &createGlobals) {
5887 // FIXME: get rid of the bogus function context and instantiate the
5888 // globals directly into the module.
5889 mlir::MLIRContext *context = &getMLIRContext();
jeanPeriera4798bb2024-04-02 14:29:29 +02005890 mlir::SymbolTable *symbolTable = getMLIRSymbolTable();
River Riddle58ceae92022-04-18 11:53:47 -07005891 mlir::func::FuncOp func = fir::FirOpBuilder::createFunction(
Valentin Clementfe252f82022-03-22 15:40:32 +01005892 mlir::UnknownLoc::get(context), getModuleOp(),
5893 fir::NameUniquer::doGenerated("Sham"),
jeanPeriera4798bb2024-04-02 14:29:29 +02005894 mlir::FunctionType::get(context, std::nullopt, std::nullopt),
5895 symbolTable);
Valentin Clementfe252f82022-03-22 15:40:32 +01005896 func.addEntryBlock();
jeanPeriera4798bb2024-04-02 14:29:29 +02005897 builder = new fir::FirOpBuilder(func, bridge.getKindMap(), symbolTable);
Slava Zakharin8f3f15c2022-11-07 09:05:27 -08005898 assert(builder && "FirOpBuilder did not instantiate");
5899 builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
Valentin Clementfe252f82022-03-22 15:40:32 +01005900 createGlobals();
5901 if (mlir::Region *region = func.getCallableRegion())
5902 region->dropAllReferences();
5903 func.erase();
5904 delete builder;
5905 builder = nullptr;
5906 localSymbols.clear();
Slava Zakharin1710c8c2024-05-08 16:48:14 -07005907 resetRegisteredDummySymbols();
Valentin Clementfe252f82022-03-22 15:40:32 +01005908 }
vdonaldson3aba9262023-12-04 09:55:54 -08005909
Valentin Clementfe252f82022-03-22 15:40:32 +01005910 /// Instantiate the data from a BLOCK DATA unit.
5911 void lowerBlockData(Fortran::lower::pft::BlockDataUnit &bdunit) {
5912 createGlobalOutsideOfFunctionLowering([&]() {
5913 Fortran::lower::AggregateStoreMap fakeMap;
5914 for (const auto &[_, sym] : bdunit.symTab) {
5915 if (sym->has<Fortran::semantics::ObjectEntityDetails>()) {
5916 Fortran::lower::pft::Variable var(*sym, true);
5917 instantiateVar(var, fakeMap);
5918 }
5919 }
5920 });
5921 }
5922
Jean Perier2c8cb9a2022-04-29 14:52:27 +02005923 /// Create fir::Global for all the common blocks that appear in the program.
5924 void
5925 lowerCommonBlocks(const Fortran::semantics::CommonBlockList &commonBlocks) {
5926 createGlobalOutsideOfFunctionLowering(
5927 [&]() { Fortran::lower::defineCommonBlocks(*this, commonBlocks); });
5928 }
5929
vdonaldson3aba9262023-12-04 09:55:54 -08005930 /// Create intrinsic module array constant definitions.
5931 void createIntrinsicModuleDefinitions(Fortran::lower::pft::Program &pft) {
5932 // The intrinsic module scope, if present, is the first scope.
5933 const Fortran::semantics::Scope *intrinsicModuleScope = nullptr;
5934 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07005935 Fortran::common::visit(
5936 Fortran::common::visitors{
5937 [&](Fortran::lower::pft::FunctionLikeUnit &f) {
5938 intrinsicModuleScope = &f.getScope().parent();
5939 },
5940 [&](Fortran::lower::pft::ModuleLikeUnit &m) {
5941 intrinsicModuleScope = &m.getScope().parent();
5942 },
5943 [&](Fortran::lower::pft::BlockDataUnit &b) {},
5944 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
5945 [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
5946 },
5947 u);
vdonaldson3aba9262023-12-04 09:55:54 -08005948 if (intrinsicModuleScope) {
5949 while (!intrinsicModuleScope->IsGlobal())
5950 intrinsicModuleScope = &intrinsicModuleScope->parent();
5951 intrinsicModuleScope = &intrinsicModuleScope->children().front();
5952 break;
5953 }
5954 }
5955 if (!intrinsicModuleScope || !intrinsicModuleScope->IsIntrinsicModules())
5956 return;
5957 for (const auto &scope : intrinsicModuleScope->children()) {
5958 llvm::StringRef modName = toStringRef(scope.symbol()->name());
5959 if (modName != "__fortran_ieee_exceptions")
5960 continue;
5961 for (auto &var : Fortran::lower::pft::getScopeVariableList(scope)) {
5962 const Fortran::semantics::Symbol &sym = var.getSymbol();
5963 if (sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
5964 continue;
5965 const auto *object =
5966 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
5967 if (object && object->IsArray() && object->init())
5968 Fortran::lower::createIntrinsicModuleGlobal(*this, var);
5969 }
5970 }
5971 }
5972
Valentin Clementfe252f82022-03-22 15:40:32 +01005973 /// Lower a procedure (nest).
5974 void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) {
Valentin Clementfe252f82022-03-22 15:40:32 +01005975 setCurrentPosition(funit.getStartingSourceLoc());
jeanPerierbb8bf852024-11-26 09:21:13 +01005976 setCurrentFunctionUnit(&funit);
Valentin Clementfe252f82022-03-22 15:40:32 +01005977 for (int entryIndex = 0, last = funit.entryPointList.size();
5978 entryIndex < last; ++entryIndex) {
5979 funit.setActiveEntry(entryIndex);
5980 startNewFunction(funit); // the entry point for lowering this procedure
5981 for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList)
5982 genFIR(eval);
5983 endNewFunction(funit);
5984 }
5985 funit.setActiveEntry(0);
jeanPerierbb8bf852024-11-26 09:21:13 +01005986 setCurrentFunctionUnit(nullptr);
vdonaldson87374a82024-06-12 09:35:14 -04005987 for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
5988 if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
5989 lowerFunc(*f); // internal procedure
Valentin Clementfe252f82022-03-22 15:40:32 +01005990 }
5991
5992 /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC
5993 /// declarative construct.
5994 void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) {
5995 setCurrentPosition(mod.getStartingSourceLoc());
5996 createGlobalOutsideOfFunctionLowering([&]() {
V Donaldson518e6f12022-12-12 14:20:06 -08005997 auto &scopeVariableListMap =
5998 Fortran::lower::pft::getScopeVariableListMap(mod);
5999 for (const auto &var : Fortran::lower::pft::getScopeVariableList(
6000 mod.getScope(), scopeVariableListMap)) {
Michael Kruse123eb752025-03-21 12:32:54 +01006001
Valentin Clementfe252f82022-03-22 15:40:32 +01006002 // Only define the variables owned by this module.
6003 const Fortran::semantics::Scope *owningScope = var.getOwningScope();
Michael Kruse123eb752025-03-21 12:32:54 +01006004 if (owningScope && mod.getScope() != *owningScope)
6005 continue;
6006
6007 // Very special case: The value of numeric_storage_size depends on
6008 // compilation options and therefore its value is not yet known when
6009 // building the builtins runtime. Instead, the parameter is folding a
6010 // __numeric_storage_size() expression which is loaded into the user
6011 // program. For the iso_fortran_env object file, omit the symbol as it
6012 // is never used.
6013 if (var.hasSymbol()) {
6014 const Fortran::semantics::Symbol &sym = var.getSymbol();
6015 const Fortran::semantics::Scope &owner = sym.owner();
6016 if (sym.name() == "numeric_storage_size" && owner.IsModule() &&
6017 DEREF(owner.symbol()).name() == "iso_fortran_env")
6018 continue;
6019 }
6020
6021 Fortran::lower::defineModuleVariable(*this, var);
Valentin Clementfe252f82022-03-22 15:40:32 +01006022 }
6023 for (auto &eval : mod.evaluationList)
6024 genFIR(eval);
6025 });
6026 }
6027
6028 /// Lower functions contained in a module.
6029 void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) {
vdonaldson87374a82024-06-12 09:35:14 -04006030 for (Fortran::lower::pft::ContainedUnit &unit : mod.containedUnitList)
6031 if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
6032 lowerFunc(*f);
Valentin Clementfe252f82022-03-22 15:40:32 +01006033 }
6034
6035 void setCurrentPosition(const Fortran::parser::CharBlock &position) {
6036 if (position != Fortran::parser::CharBlock{})
6037 currentPosition = position;
6038 }
6039
6040 /// Set current position at the location of \p parseTreeNode. Note that the
6041 /// position is updated automatically when visiting statements, but not when
6042 /// entering higher level nodes like constructs or procedures. This helper is
6043 /// intended to cover the latter cases.
6044 template <typename A>
6045 void setCurrentPositionAt(const A &parseTreeNode) {
6046 setCurrentPosition(Fortran::parser::FindSourceLocation(parseTreeNode));
6047 }
6048
6049 //===--------------------------------------------------------------------===//
6050 // Utility methods
6051 //===--------------------------------------------------------------------===//
6052
6053 /// Convert a parser CharBlock to a Location
6054 mlir::Location toLocation(const Fortran::parser::CharBlock &cb) {
6055 return genLocation(cb);
6056 }
6057
6058 mlir::Location toLocation() { return toLocation(currentPosition); }
6059 void setCurrentEval(Fortran::lower::pft::Evaluation &eval) {
6060 evalPtr = &eval;
6061 }
6062 Fortran::lower::pft::Evaluation &getEval() {
6063 assert(evalPtr);
6064 return *evalPtr;
6065 }
6066
6067 std::optional<Fortran::evaluate::Shape>
6068 getShape(const Fortran::lower::SomeExpr &expr) {
6069 return Fortran::evaluate::GetShape(foldingContext, expr);
6070 }
6071
Valentin Clemente1a12762022-01-28 22:39:44 +01006072 //===--------------------------------------------------------------------===//
Valentin Clement88ae0d62022-03-10 19:43:11 +01006073 // Analysis on a nested explicit iteration space.
6074 //===--------------------------------------------------------------------===//
6075
6076 void analyzeExplicitSpace(const Fortran::parser::ConcurrentHeader &header) {
6077 explicitIterSpace.pushLevel();
6078 for (const Fortran::parser::ConcurrentControl &ctrl :
6079 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
6080 const Fortran::semantics::Symbol *ctrlVar =
6081 std::get<Fortran::parser::Name>(ctrl.t).symbol;
6082 explicitIterSpace.addSymbol(ctrlVar);
6083 }
6084 if (const auto &mask =
6085 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
6086 header.t);
6087 mask.has_value())
6088 analyzeExplicitSpace(*Fortran::semantics::GetExpr(*mask));
6089 }
6090 template <bool LHS = false, typename A>
6091 void analyzeExplicitSpace(const Fortran::evaluate::Expr<A> &e) {
6092 explicitIterSpace.exprBase(&e, LHS);
6093 }
6094 void analyzeExplicitSpace(const Fortran::evaluate::Assignment *assign) {
6095 auto analyzeAssign = [&](const Fortran::lower::SomeExpr &lhs,
6096 const Fortran::lower::SomeExpr &rhs) {
6097 analyzeExplicitSpace</*LHS=*/true>(lhs);
6098 analyzeExplicitSpace(rhs);
6099 };
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006100 Fortran::common::visit(
Valentin Clement88ae0d62022-03-10 19:43:11 +01006101 Fortran::common::visitors{
6102 [&](const Fortran::evaluate::ProcedureRef &procRef) {
6103 // Ensure the procRef expressions are the one being visited.
6104 assert(procRef.arguments().size() == 2);
6105 const Fortran::lower::SomeExpr *lhs =
6106 procRef.arguments()[0].value().UnwrapExpr();
6107 const Fortran::lower::SomeExpr *rhs =
6108 procRef.arguments()[1].value().UnwrapExpr();
6109 assert(lhs && rhs &&
6110 "user defined assignment arguments must be expressions");
6111 analyzeAssign(*lhs, *rhs);
6112 },
6113 [&](const auto &) { analyzeAssign(assign->lhs, assign->rhs); }},
6114 assign->u);
6115 explicitIterSpace.endAssign();
6116 }
6117 void analyzeExplicitSpace(const Fortran::parser::ForallAssignmentStmt &stmt) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006118 Fortran::common::visit([&](const auto &s) { analyzeExplicitSpace(s); },
6119 stmt.u);
Valentin Clement88ae0d62022-03-10 19:43:11 +01006120 }
6121 void analyzeExplicitSpace(const Fortran::parser::AssignmentStmt &s) {
6122 analyzeExplicitSpace(s.typedAssignment->v.operator->());
6123 }
6124 void analyzeExplicitSpace(const Fortran::parser::PointerAssignmentStmt &s) {
6125 analyzeExplicitSpace(s.typedAssignment->v.operator->());
6126 }
6127 void analyzeExplicitSpace(const Fortran::parser::WhereConstruct &c) {
6128 analyzeExplicitSpace(
6129 std::get<
6130 Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
6131 c.t)
6132 .statement);
6133 for (const Fortran::parser::WhereBodyConstruct &body :
6134 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
6135 analyzeExplicitSpace(body);
6136 for (const Fortran::parser::WhereConstruct::MaskedElsewhere &e :
6137 std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
6138 c.t))
6139 analyzeExplicitSpace(e);
6140 if (const auto &e =
6141 std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
6142 c.t);
6143 e.has_value())
6144 analyzeExplicitSpace(e.operator->());
6145 }
6146 void analyzeExplicitSpace(const Fortran::parser::WhereConstructStmt &ws) {
6147 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
6148 std::get<Fortran::parser::LogicalExpr>(ws.t));
6149 addMaskVariable(exp);
6150 analyzeExplicitSpace(*exp);
6151 }
6152 void analyzeExplicitSpace(
6153 const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
6154 analyzeExplicitSpace(
6155 std::get<
6156 Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
6157 ew.t)
6158 .statement);
6159 for (const Fortran::parser::WhereBodyConstruct &e :
6160 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
6161 analyzeExplicitSpace(e);
6162 }
6163 void analyzeExplicitSpace(const Fortran::parser::WhereBodyConstruct &body) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006164 Fortran::common::visit(
6165 Fortran::common::visitors{
6166 [&](const Fortran::common::Indirection<
6167 Fortran::parser::WhereConstruct> &wc) {
6168 analyzeExplicitSpace(wc.value());
6169 },
6170 [&](const auto &s) { analyzeExplicitSpace(s.statement); }},
6171 body.u);
Valentin Clement88ae0d62022-03-10 19:43:11 +01006172 }
6173 void analyzeExplicitSpace(const Fortran::parser::MaskedElsewhereStmt &stmt) {
6174 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
6175 std::get<Fortran::parser::LogicalExpr>(stmt.t));
6176 addMaskVariable(exp);
6177 analyzeExplicitSpace(*exp);
6178 }
6179 void
6180 analyzeExplicitSpace(const Fortran::parser::WhereConstruct::Elsewhere *ew) {
6181 for (const Fortran::parser::WhereBodyConstruct &e :
6182 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew->t))
6183 analyzeExplicitSpace(e);
6184 }
6185 void analyzeExplicitSpace(const Fortran::parser::WhereStmt &stmt) {
6186 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
6187 std::get<Fortran::parser::LogicalExpr>(stmt.t));
6188 addMaskVariable(exp);
6189 analyzeExplicitSpace(*exp);
6190 const std::optional<Fortran::evaluate::Assignment> &assign =
6191 std::get<Fortran::parser::AssignmentStmt>(stmt.t).typedAssignment->v;
6192 assert(assign.has_value() && "WHERE has no statement");
6193 analyzeExplicitSpace(assign.operator->());
6194 }
6195 void analyzeExplicitSpace(const Fortran::parser::ForallStmt &forall) {
6196 analyzeExplicitSpace(
6197 std::get<
6198 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
6199 forall.t)
6200 .value());
6201 analyzeExplicitSpace(std::get<Fortran::parser::UnlabeledStatement<
6202 Fortran::parser::ForallAssignmentStmt>>(forall.t)
6203 .statement);
6204 analyzeExplicitSpacePop();
6205 }
6206 void
6207 analyzeExplicitSpace(const Fortran::parser::ForallConstructStmt &forall) {
6208 analyzeExplicitSpace(
6209 std::get<
6210 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
6211 forall.t)
6212 .value());
6213 }
6214 void analyzeExplicitSpace(const Fortran::parser::ForallConstruct &forall) {
6215 analyzeExplicitSpace(
6216 std::get<
6217 Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
6218 forall.t)
6219 .statement);
6220 for (const Fortran::parser::ForallBodyConstruct &s :
6221 std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006222 Fortran::common::visit(
6223 Fortran::common::visitors{
6224 [&](const Fortran::common::Indirection<
6225 Fortran::parser::ForallConstruct> &b) {
6226 analyzeExplicitSpace(b.value());
6227 },
6228 [&](const Fortran::parser::WhereConstruct &w) {
6229 analyzeExplicitSpace(w);
6230 },
6231 [&](const auto &b) { analyzeExplicitSpace(b.statement); }},
6232 s.u);
Valentin Clement88ae0d62022-03-10 19:43:11 +01006233 }
6234 analyzeExplicitSpacePop();
6235 }
6236
6237 void analyzeExplicitSpacePop() { explicitIterSpace.popLevel(); }
6238
6239 void addMaskVariable(Fortran::lower::FrontEndExpr exp) {
6240 // Note: use i8 to store bool values. This avoids round-down behavior found
6241 // with sequences of i1. That is, an array of i1 will be truncated in size
6242 // and be too small. For example, a buffer of type fir.array<7xi1> will have
6243 // 0 size.
6244 mlir::Type i64Ty = builder->getIntegerType(64);
6245 mlir::TupleType ty = fir::factory::getRaggedArrayHeaderType(*builder);
6246 mlir::Type buffTy = ty.getType(1);
6247 mlir::Type shTy = ty.getType(2);
6248 mlir::Location loc = toLocation();
6249 mlir::Value hdr = builder->createTemporary(loc, ty);
6250 // FIXME: Is there a way to create a `zeroinitializer` in LLVM-IR dialect?
6251 // For now, explicitly set lazy ragged header to all zeros.
6252 // auto nilTup = builder->createNullConstant(loc, ty);
6253 // builder->create<fir::StoreOp>(loc, nilTup, hdr);
6254 mlir::Type i32Ty = builder->getIntegerType(32);
6255 mlir::Value zero = builder->createIntegerConstant(loc, i32Ty, 0);
6256 mlir::Value zero64 = builder->createIntegerConstant(loc, i64Ty, 0);
6257 mlir::Value flags = builder->create<fir::CoordinateOp>(
6258 loc, builder->getRefType(i64Ty), hdr, zero);
6259 builder->create<fir::StoreOp>(loc, zero64, flags);
6260 mlir::Value one = builder->createIntegerConstant(loc, i32Ty, 1);
6261 mlir::Value nullPtr1 = builder->createNullConstant(loc, buffTy);
6262 mlir::Value var = builder->create<fir::CoordinateOp>(
6263 loc, builder->getRefType(buffTy), hdr, one);
6264 builder->create<fir::StoreOp>(loc, nullPtr1, var);
6265 mlir::Value two = builder->createIntegerConstant(loc, i32Ty, 2);
6266 mlir::Value nullPtr2 = builder->createNullConstant(loc, shTy);
6267 mlir::Value shape = builder->create<fir::CoordinateOp>(
6268 loc, builder->getRefType(shTy), hdr, two);
6269 builder->create<fir::StoreOp>(loc, nullPtr2, shape);
6270 implicitIterSpace.addMaskVariable(exp, var, shape, hdr);
6271 explicitIterSpace.outermostContext().attachCleanup(
6272 [builder = this->builder, hdr, loc]() {
6273 fir::runtime::genRaggedArrayDeallocate(loc, *builder, hdr);
6274 });
6275 }
6276
Valentin Clementfe252f82022-03-22 15:40:32 +01006277 void createRuntimeTypeInfoGlobals() {}
6278
Jean Perier7531c872023-01-20 14:05:42 +01006279 bool lowerToHighLevelFIR() const {
6280 return bridge.getLoweringOptions().getLowerToHighLevelFIR();
6281 }
6282
Slava Zakharinbe5747e2023-05-09 19:50:48 -07006283 // Returns the mangling prefix for the given constant expression.
6284 std::string getConstantExprManglePrefix(mlir::Location loc,
6285 const Fortran::lower::SomeExpr &expr,
6286 mlir::Type eleTy) {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006287 return Fortran::common::visit(
Slava Zakharinbe5747e2023-05-09 19:50:48 -07006288 [&](const auto &x) -> std::string {
6289 using T = std::decay_t<decltype(x)>;
6290 if constexpr (Fortran::common::HasMember<
6291 T, Fortran::lower::CategoryExpression>) {
6292 if constexpr (T::Result::category ==
6293 Fortran::common::TypeCategory::Derived) {
6294 if (const auto *constant =
6295 std::get_if<Fortran::evaluate::Constant<
6296 Fortran::evaluate::SomeDerived>>(&x.u))
6297 return Fortran::lower::mangle::mangleArrayLiteral(eleTy,
6298 *constant);
6299 fir::emitFatalError(loc,
6300 "non a constant derived type expression");
6301 } else {
Alexander Shaposhnikov77d8cfb2024-06-17 12:59:04 -07006302 return Fortran::common::visit(
Slava Zakharinbe5747e2023-05-09 19:50:48 -07006303 [&](const auto &someKind) -> std::string {
6304 using T = std::decay_t<decltype(someKind)>;
6305 using TK = Fortran::evaluate::Type<T::Result::category,
6306 T::Result::kind>;
6307 if (const auto *constant =
6308 std::get_if<Fortran::evaluate::Constant<TK>>(
6309 &someKind.u)) {
6310 return Fortran::lower::mangle::mangleArrayLiteral(
6311 nullptr, *constant);
6312 }
6313 fir::emitFatalError(
6314 loc, "not a Fortran::evaluate::Constant<T> expression");
6315 return {};
6316 },
6317 x.u);
6318 }
6319 } else {
6320 fir::emitFatalError(loc, "unexpected expression");
6321 }
6322 },
6323 expr.u);
6324 }
6325
Valentin Clement69a6bd52023-08-17 14:25:05 -07006326 /// Performing OpenACC lowering action that were deferred to the end of
6327 /// lowering.
6328 void finalizeOpenACCLowering() {
6329 Fortran::lower::finalizeOpenACCRoutineAttachment(getModuleOp(),
6330 accRoutineInfos);
6331 }
6332
Sergio Afonso29aa7492023-03-29 18:13:48 +01006333 /// Performing OpenMP lowering actions that were deferred to the end of
6334 /// lowering.
6335 void finalizeOpenMPLowering(
6336 const Fortran::semantics::Symbol *globalOmpRequiresSymbol) {
agozillonafb05cd2024-03-05 17:27:16 +01006337 if (!ompDeferredDeclareTarget.empty()) {
6338 bool deferredDeviceFuncFound =
6339 Fortran::lower::markOpenMPDeferredDeclareTargetFunctions(
6340 getModuleOp().getOperation(), ompDeferredDeclareTarget, *this);
6341 ompDeviceCodeFound = ompDeviceCodeFound || deferredDeviceFuncFound;
6342 }
6343
Sergio Afonso29aa7492023-03-29 18:13:48 +01006344 // Set the module attribute related to OpenMP requires directives
6345 if (ompDeviceCodeFound)
6346 Fortran::lower::genOpenMPRequires(getModuleOp().getOperation(),
6347 globalOmpRequiresSymbol);
6348 }
6349
Slava Zakharin1710c8c2024-05-08 16:48:14 -07006350 /// Record fir.dummy_scope operation for this function.
6351 /// It will be used to set dummy_scope operand of the hlfir.declare
6352 /// operations.
6353 void setDummyArgsScope(mlir::Value val) {
6354 assert(!dummyArgsScope && val);
6355 dummyArgsScope = val;
6356 }
6357
6358 /// Record the given symbol as a dummy argument of this function.
6359 void registerDummySymbol(Fortran::semantics::SymbolRef symRef) {
6360 auto *sym = &*symRef;
6361 registeredDummySymbols.insert(sym);
6362 }
6363
6364 /// Reset all registered dummy symbols.
6365 void resetRegisteredDummySymbols() { registeredDummySymbols.clear(); }
6366
jeanPerierbb8bf852024-11-26 09:21:13 +01006367 void setCurrentFunctionUnit(Fortran::lower::pft::FunctionLikeUnit *unit) {
6368 currentFunctionUnit = unit;
6369 }
6370
Valentin Clement88ae0d62022-03-10 19:43:11 +01006371 //===--------------------------------------------------------------------===//
Valentin Clemente1a12762022-01-28 22:39:44 +01006372
6373 Fortran::lower::LoweringBridge &bridge;
6374 Fortran::evaluate::FoldingContext foldingContext;
6375 fir::FirOpBuilder *builder = nullptr;
6376 Fortran::lower::pft::Evaluation *evalPtr = nullptr;
jeanPerierbb8bf852024-11-26 09:21:13 +01006377 Fortran::lower::pft::FunctionLikeUnit *currentFunctionUnit = nullptr;
Valentin Clemente1a12762022-01-28 22:39:44 +01006378 Fortran::lower::SymMap localSymbols;
6379 Fortran::parser::CharBlock currentPosition;
jeanPerier4ccd57d2023-10-06 09:29:57 +02006380 TypeInfoConverter typeInfoConverter;
Valentin Clementd0b70a02022-02-23 19:48:07 +01006381
V Donaldson2c143342023-02-27 14:05:53 -08006382 // Stack to manage object deallocation and finalization at construct exits.
6383 llvm::SmallVector<ConstructContext> activeConstructStack;
Valentin Clementfe252f82022-03-22 15:40:32 +01006384
V Donaldson2c143342023-02-27 14:05:53 -08006385 /// BLOCK name mangling component map
6386 int blockId = 0;
6387 Fortran::lower::mangle::ScopeBlockIdMap scopeBlockIdMap;
6388
6389 /// FORALL statement/construct context
Valentin Clementfe252f82022-03-22 15:40:32 +01006390 Fortran::lower::ExplicitIterSpace explicitIterSpace;
6391
V Donaldson2c143342023-02-27 14:05:53 -08006392 /// WHERE statement/construct mask expression stack
6393 Fortran::lower::ImplicitIterSpace implicitIterSpace;
6394
6395 /// Tuple of host associated variables
Valentin Clementd0b70a02022-02-23 19:48:07 +01006396 mlir::Value hostAssocTuple;
Slava Zakharinbe5747e2023-05-09 19:50:48 -07006397
Slava Zakharin1710c8c2024-05-08 16:48:14 -07006398 /// Value of fir.dummy_scope operation for this function.
6399 mlir::Value dummyArgsScope;
6400
6401 /// A set of dummy argument symbols for this function.
6402 /// The set is only preserved during the instatiation
6403 /// of variables for this function.
6404 llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 16>
6405 registeredDummySymbols;
6406
Slava Zakharinbe5747e2023-05-09 19:50:48 -07006407 /// A map of unique names for constant expressions.
6408 /// The names are used for representing the constant expressions
6409 /// with global constant initialized objects.
6410 /// The names are usually prefixed by a mangling string based
6411 /// on the element type of the constant expression, but the element
6412 /// type is not used as a key into the map (so the assumption is that
6413 /// the equivalent constant expressions are prefixed using the same
6414 /// element type).
6415 llvm::DenseMap<const Fortran::lower::SomeExpr *, std::string> literalNamesMap;
6416
6417 /// Storage for Constant expressions used as keys for literalNamesMap.
6418 llvm::SmallVector<std::unique_ptr<Fortran::lower::SomeExpr>>
6419 literalExprsStorage;
6420
6421 /// A counter for uniquing names in `literalNamesMap`.
6422 std::uint64_t uniqueLitId = 0;
Valentin Clement69a6bd52023-08-17 14:25:05 -07006423
6424 /// Deferred OpenACC routine attachment.
6425 Fortran::lower::AccRoutineInfoMappingList accRoutineInfos;
Sergio Afonso29aa7492023-03-29 18:13:48 +01006426
6427 /// Whether an OpenMP target region or declare target function/subroutine
6428 /// intended for device offloading has been detected
6429 bool ompDeviceCodeFound = false;
jeanPerierb6b07562023-10-25 09:22:23 +02006430
agozillonafb05cd2024-03-05 17:27:16 +01006431 /// Keeps track of symbols defined as declare target that could not be
6432 /// processed at the time of lowering the declare target construct, such
6433 /// as certain cases where interfaces are declared but not defined within
6434 /// a module.
6435 llvm::SmallVector<Fortran::lower::OMPDeferredDeclareTargetInfo>
6436 ompDeferredDeclareTarget;
6437
jeanPerierb6b07562023-10-25 09:22:23 +02006438 const Fortran::lower::ExprToValueMap *exprValueOverrides{nullptr};
jeanPerierc373f582023-12-19 17:17:09 +01006439
6440 /// Stack of derived type under construction to avoid infinite loops when
6441 /// dealing with recursive derived types. This is held in the bridge because
6442 /// the state needs to be maintained between data and function type lowering
6443 /// utilities to deal with procedure pointer components whose arguments have
6444 /// the type of the containing derived type.
6445 Fortran::lower::TypeConstructionStack typeConstructionStack;
jeanPeriera4798bb2024-04-02 14:29:29 +02006446 /// MLIR symbol table of the fir.global/func.func operations. Note that it is
6447 /// not guaranteed to contain all operations of the ModuleOp with Symbol
6448 /// attribute since mlirSymbolTable must pro-actively be maintained when
6449 /// new Symbol operations are created.
6450 mlir::SymbolTable mlirSymbolTable;
Valentin Clemente1a12762022-01-28 22:39:44 +01006451};
6452
6453} // namespace
6454
6455Fortran::evaluate::FoldingContext
jeanPerier181eab22024-01-29 18:28:56 +01006456Fortran::lower::LoweringBridge::createFoldingContext() {
Peter Klausler1c91d9b2023-11-13 16:13:50 -08006457 return {getDefaultKinds(), getIntrinsicTable(), getTargetCharacteristics(),
jeanPerier181eab22024-01-29 18:28:56 +01006458 getLanguageFeatures(), tempNames};
Valentin Clemente1a12762022-01-28 22:39:44 +01006459}
6460
6461void Fortran::lower::LoweringBridge::lower(
6462 const Fortran::parser::Program &prg,
6463 const Fortran::semantics::SemanticsContext &semanticsContext) {
6464 std::unique_ptr<Fortran::lower::pft::Program> pft =
6465 Fortran::lower::createPFT(prg, semanticsContext);
6466 if (dumpBeforeFir)
6467 Fortran::lower::dumpPFT(llvm::errs(), *pft);
6468 FirConverter converter{*this};
6469 converter.run(*pft);
6470}
6471
Valentin Clementfe252f82022-03-22 15:40:32 +01006472void Fortran::lower::LoweringBridge::parseSourceFile(llvm::SourceMgr &srcMgr) {
Matthias Springerc8706322024-12-25 09:42:03 +01006473 module = mlir::parseSourceFile<mlir::ModuleOp>(srcMgr, &context);
Valentin Clementfe252f82022-03-22 15:40:32 +01006474}
6475
Valentin Clemente1a12762022-01-28 22:39:44 +01006476Fortran::lower::LoweringBridge::LoweringBridge(
6477 mlir::MLIRContext &context,
Valentin Clement8fc00242022-08-12 21:22:30 +02006478 Fortran::semantics::SemanticsContext &semanticsContext,
Valentin Clemente1a12762022-01-28 22:39:44 +01006479 const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
6480 const Fortran::evaluate::IntrinsicProcTable &intrinsics,
Peter Klausler23c2bed2022-07-01 11:40:44 -07006481 const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
Valentin Clemente1a12762022-01-28 22:39:44 +01006482 const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
Slava Zakharinf1eb9452022-07-19 20:39:58 -07006483 fir::KindMapping &kindMap,
Jonathon Penix0ec3ac92022-07-19 11:47:25 -07006484 const Fortran::lower::LoweringOptions &loweringOptions,
Peter Klausler1c91d9b2023-11-13 16:13:50 -08006485 const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
jeanPeriere59e8482023-12-06 14:20:06 +01006486 const Fortran::common::LanguageFeatureControl &languageFeatures,
Tarun Prabhu839344f2024-10-14 08:44:24 -06006487 const llvm::TargetMachine &targetMachine,
6488 const Fortran::frontend::TargetOptions &targetOpts,
6489 const Fortran::frontend::CodeGenOptions &cgOpts)
Valentin Clement8fc00242022-08-12 21:22:30 +02006490 : semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
6491 intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
6492 cooked{&cooked}, context{context}, kindMap{kindMap},
Peter Klausler1c91d9b2023-11-13 16:13:50 -08006493 loweringOptions{loweringOptions}, envDefaults{envDefaults},
6494 languageFeatures{languageFeatures} {
Valentin Clemente1a12762022-01-28 22:39:44 +01006495 // Register the diagnostic handler.
6496 context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) {
6497 llvm::raw_ostream &os = llvm::errs();
6498 switch (diag.getSeverity()) {
6499 case mlir::DiagnosticSeverity::Error:
6500 os << "error: ";
6501 break;
6502 case mlir::DiagnosticSeverity::Remark:
6503 os << "info: ";
6504 break;
6505 case mlir::DiagnosticSeverity::Warning:
6506 os << "warning: ";
6507 break;
6508 default:
6509 break;
6510 }
Christian Siggfac349a2024-04-28 22:01:42 +02006511 if (!mlir::isa<mlir::UnknownLoc>(diag.getLocation()))
Valentin Clemente1a12762022-01-28 22:39:44 +01006512 os << diag.getLocation() << ": ";
6513 os << diag << '\n';
6514 os.flush();
6515 return mlir::success();
6516 });
6517
Kiran Chandramohaneef02102023-01-19 16:49:26 +00006518 auto getPathLocation = [&semanticsContext, &context]() -> mlir::Location {
6519 std::optional<std::string> path;
6520 const auto &allSources{semanticsContext.allCookedSources().allSources()};
6521 if (auto initial{allSources.GetFirstFileProvenance()};
6522 initial && !initial->empty()) {
6523 if (const auto *sourceFile{allSources.GetSourceFile(initial->start())}) {
6524 path = sourceFile->path();
6525 }
6526 }
6527
6528 if (path.has_value()) {
6529 llvm::SmallString<256> curPath(*path);
6530 llvm::sys::fs::make_absolute(curPath);
6531 llvm::sys::path::remove_dots(curPath);
6532 return mlir::FileLineColLoc::get(&context, curPath.str(), /*line=*/0,
6533 /*col=*/0);
6534 } else {
6535 return mlir::UnknownLoc::get(&context);
6536 }
6537 };
6538
Valentin Clemente1a12762022-01-28 22:39:44 +01006539 // Create the module and attach the attributes.
Matthias Springerc8706322024-12-25 09:42:03 +01006540 module = mlir::OwningOpRef<mlir::ModuleOp>(
Kiran Chandramohaneef02102023-01-19 16:49:26 +00006541 mlir::ModuleOp::create(getPathLocation()));
Matthias Springerc8706322024-12-25 09:42:03 +01006542 assert(*module && "module was not created");
6543 fir::setTargetTriple(*module, triple);
6544 fir::setKindMapping(*module, kindMap);
6545 fir::setTargetCPU(*module, targetMachine.getTargetCPU());
6546 fir::setTuneCPU(*module, targetOpts.cpuToTuneFor);
6547 fir::setTargetFeatures(*module, targetMachine.getTargetFeatureString());
6548 fir::support::setMLIRDataLayout(*module, targetMachine.createDataLayout());
6549 fir::setIdent(*module, Fortran::common::getFlangFullVersion());
Tarun Prabhu839344f2024-10-14 08:44:24 -06006550 if (cgOpts.RecordCommandLine)
Matthias Springerc8706322024-12-25 09:42:03 +01006551 fir::setCommandline(*module, *cgOpts.RecordCommandLine);
Valentin Clemente1a12762022-01-28 22:39:44 +01006552}
jeanPerierc7c56662024-05-14 13:34:46 +02006553
6554void Fortran::lower::genCleanUpInRegionIfAny(
6555 mlir::Location loc, fir::FirOpBuilder &builder, mlir::Region &region,
6556 Fortran::lower::StatementContext &context) {
6557 if (!context.hasCode())
6558 return;
6559 mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint();
6560 if (region.empty())
6561 builder.createBlock(&region);
6562 else
6563 builder.setInsertionPointToEnd(&region.front());
6564 context.finalizeAndPop();
6565 hlfir::YieldOp::ensureTerminator(region, builder, loc);
6566 builder.restoreInsertionPoint(insertPt);
6567}