27
27
#include " mlir/Transforms/RegionUtils.h"
28
28
#include " llvm/Frontend/OpenMP/OMPConstants.h"
29
29
30
- #include < algorithm>
31
30
#include < memory>
32
31
#include < utility>
33
32
@@ -239,94 +238,6 @@ struct InductionVariableInfo {
239
238
using LoopNestToIndVarMap =
240
239
llvm::MapVector<fir::DoLoopOp, InductionVariableInfo>;
241
240
242
- // / For the \p doLoop parameter, find the operation that declares its iteration
243
- // / variable or allocates memory for it.
244
- // /
245
- // / For example, give the following loop:
246
- // / ```
247
- // / ...
248
- // / %i:2 = hlfir.declare %0 {uniq_name = "_QFEi"} : ...
249
- // / ...
250
- // / fir.do_loop %ind_var = %lb to %ub step %s unordered {
251
- // / %ind_var_conv = fir.convert %ind_var : (index) -> i32
252
- // / fir.store %ind_var_conv to %i#1 : !fir.ref<i32>
253
- // / ...
254
- // / }
255
- // / ```
256
- // /
257
- // / This function returns the `hlfir.declare` op for `%i`.
258
- // /
259
- // / Note: The current implementation is dependent on how flang emits loop
260
- // / bodies; which is sufficient for the current simple test/use cases. If this
261
- // / proves to be insufficient, this should be made more generic.
262
- mlir::Operation *findLoopIterationVarMemDecl (fir::DoLoopOp doLoop) {
263
- mlir::Value result = nullptr ;
264
-
265
- // Checks if a StoreOp is updating the memref of the loop's iteration
266
- // variable.
267
- auto isStoringIV = [&](fir::StoreOp storeOp) {
268
- // Direct store into the IV memref.
269
- if (storeOp.getValue () == doLoop.getInductionVar ())
270
- return true ;
271
-
272
- // Indirect store into the IV memref.
273
- if (auto convertOp = mlir::dyn_cast<fir::ConvertOp>(
274
- storeOp.getValue ().getDefiningOp ())) {
275
- if (convertOp.getOperand () == doLoop.getInductionVar ())
276
- return true ;
277
- }
278
-
279
- return false ;
280
- };
281
-
282
- for (mlir::Operation &op : doLoop) {
283
- if (auto storeOp = mlir::dyn_cast<fir::StoreOp>(op))
284
- if (isStoringIV (storeOp)) {
285
- result = storeOp.getMemref ();
286
- break ;
287
- }
288
- }
289
-
290
- assert (result != nullptr && result.getDefiningOp () != nullptr );
291
- return result.getDefiningOp ();
292
- }
293
-
294
- // / Given an operation `op`, this returns true if `op`'s operand is ultimately
295
- // / the loop's induction variable. Detecting this helps finding the live-in
296
- // / value corresponding to the induction variable in case the induction variable
297
- // / is indirectly used in the loop (e.g. throught a cast op).
298
- bool isIndVarUltimateOperand (mlir::Operation *op, fir::DoLoopOp doLoop) {
299
- while (op != nullptr && op->getNumOperands () > 0 ) {
300
- auto ivIt = llvm::find_if (op->getOperands (), [&](mlir::Value operand) {
301
- return operand == doLoop.getInductionVar ();
302
- });
303
-
304
- if (ivIt != op->getOperands ().end ())
305
- return true ;
306
-
307
- op = op->getOperand (0 ).getDefiningOp ();
308
- }
309
-
310
- return false ;
311
- }
312
-
313
- // / For the \p doLoop parameter, find the operations that declares its induction
314
- // / variable or allocates memory for it.
315
- mlir::Operation *findLoopIndVarMemDecl (fir::DoLoopOp doLoop) {
316
- mlir::Value result = nullptr ;
317
- mlir::visitUsedValuesDefinedAbove (
318
- doLoop.getRegion (), [&](mlir::OpOperand *operand) {
319
- if (isIndVarUltimateOperand (operand->getOwner (), doLoop)) {
320
- assert (result == nullptr &&
321
- " loop can have only one induction variable" );
322
- result = operand->get ();
323
- }
324
- });
325
-
326
- assert (result != nullptr && result.getDefiningOp () != nullptr );
327
- return result.getDefiningOp ();
328
- }
329
-
330
241
// / Collect the list of values used inside the loop but defined outside of it.
331
242
void collectLoopLiveIns (fir::DoLoopOp doLoop,
332
243
llvm::SmallVectorImpl<mlir::Value> &liveIns) {
@@ -347,92 +258,6 @@ void collectLoopLiveIns(fir::DoLoopOp doLoop,
347
258
});
348
259
}
349
260
350
- // / Collects the op(s) responsible for updating a loop's iteration variable with
351
- // / the current iteration number. For example, for the input IR:
352
- // / ```
353
- // / %i = fir.alloca i32 {bindc_name = "i"}
354
- // / %i_decl:2 = hlfir.declare %i ...
355
- // / ...
356
- // / fir.do_loop %i_iv = %lb to %ub step %step unordered {
357
- // / %1 = fir.convert %i_iv : (index) -> i32
358
- // / fir.store %1 to %i_decl#1 : !fir.ref<i32>
359
- // / ...
360
- // / }
361
- // / ```
362
- // / this function would return the first 2 ops in the `fir.do_loop`'s region.
363
- llvm::SetVector<mlir::Operation *>
364
- extractIndVarUpdateOps (fir::DoLoopOp doLoop) {
365
- mlir::Value indVar = doLoop.getInductionVar ();
366
- llvm::SetVector<mlir::Operation *> indVarUpdateOps;
367
-
368
- llvm::SmallVector<mlir::Value> toProcess;
369
- toProcess.push_back (indVar);
370
-
371
- llvm::DenseSet<mlir::Value> done;
372
-
373
- while (!toProcess.empty ()) {
374
- mlir::Value val = toProcess.back ();
375
- toProcess.pop_back ();
376
-
377
- if (!done.insert (val).second )
378
- continue ;
379
-
380
- for (mlir::Operation *user : val.getUsers ()) {
381
- indVarUpdateOps.insert (user);
382
-
383
- for (mlir::Value result : user->getResults ())
384
- toProcess.push_back (result);
385
- }
386
- }
387
-
388
- return std::move (indVarUpdateOps);
389
- }
390
-
391
- // / Starting with a value at the end of a definition/conversion chain, walk the
392
- // / chain backwards and collect all the visited ops along the way. This is the
393
- // / same as the "backward slice" of the use-def chain of \p link.
394
- // /
395
- // / If the root of the chain/slice is a constant op (where convert operations
396
- // / on constant count as constants as well), then populate \p opChain with the
397
- // / extracted chain/slice. If not, then \p opChain will contains a single value:
398
- // / \p link.
399
- // /
400
- // / The purpose of this function is that we pull in the chain of
401
- // / constant+conversion ops inside the parallel region if possible; which
402
- // / prevents creating an unnecessary shared/mapped value that crosses the OpenMP
403
- // / region.
404
- // /
405
- // / For example, given this IR:
406
- // / ```
407
- // / %c10 = arith.constant 10 : i32
408
- // / %10 = fir.convert %c10 : (i32) -> index
409
- // / ```
410
- // / and giving `%10` as the starting input: `link`, `defChain` would contain
411
- // / both of the above ops.
412
- void collectIndirectConstOpChain (mlir::Operation *link,
413
- llvm::SetVector<mlir::Operation *> &opChain) {
414
- mlir::BackwardSliceOptions options;
415
- options.inclusive = true ;
416
- mlir::getBackwardSlice (link, &opChain, options);
417
-
418
- assert (!opChain.empty ());
419
-
420
- bool isConstantChain = [&]() {
421
- if (!mlir::isa_and_present<mlir::arith::ConstantOp>(opChain.front ()))
422
- return false ;
423
-
424
- return llvm::all_of (llvm::drop_begin (opChain), [](mlir::Operation *op) {
425
- return mlir::isa_and_present<fir::ConvertOp>(op);
426
- });
427
- }();
428
-
429
- if (isConstantChain)
430
- return ;
431
-
432
- opChain.clear ();
433
- opChain.insert (link);
434
- }
435
-
436
261
// / Loop \p innerLoop is considered perfectly-nested inside \p outerLoop iff
437
262
// / there are no operations in \p outerloop's body other than:
438
263
// /
0 commit comments