2727#include " mlir/Transforms/RegionUtils.h"
2828#include " llvm/Frontend/OpenMP/OMPConstants.h"
2929
30- #include < algorithm>
3130#include < memory>
3231#include < utility>
3332
@@ -239,94 +238,6 @@ struct InductionVariableInfo {
239238using LoopNestToIndVarMap =
240239 llvm::MapVector<fir::DoLoopOp, InductionVariableInfo>;
241240
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-
330241// / Collect the list of values used inside the loop but defined outside of it.
331242void collectLoopLiveIns (fir::DoLoopOp doLoop,
332243 llvm::SmallVectorImpl<mlir::Value> &liveIns) {
@@ -347,92 +258,6 @@ void collectLoopLiveIns(fir::DoLoopOp doLoop,
347258 });
348259}
349260
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-
436261// / Loop \p innerLoop is considered perfectly-nested inside \p outerLoop iff
437262// / there are no operations in \p outerloop's body other than:
438263// /
0 commit comments