[flang-commits] [flang] 0aa80b4 - [flang][hlfir] Add hlfir.forall_index operation

Jean Perier via flang-commits flang-commits at lists.llvm.org
Fri May 5 00:19:40 PDT 2023


Author: Jean Perier
Date: 2023-05-05T09:17:50+02:00
New Revision: 0aa80b42ac975a10087c4356b475a188ef1f5afa

URL: https://github.com/llvm/llvm-project/commit/0aa80b42ac975a10087c4356b475a188ef1f5afa
DIFF: https://github.com/llvm/llvm-project/commit/0aa80b42ac975a10087c4356b475a188ef1f5afa.diff

LOG: [flang][hlfir] Add hlfir.forall_index operation

This is the last piece required to lower Forall (except pointer
assignments, where an operation may be needed to deal with bounds
remapping).

Lowering requires symbols to be mapped to memory SSA values produced
by a fir_FortranVariableOpInterface operation. This applies to
forall index-values, that are symbols.

fir.alloca/fir.store/hlfir.declare are not allowed inside the body of
an hlfir.forall that only accept operations with the
hlfir_OrderedAssignmentTreeOpInterface so that the forall structure is
well defined and easy to transform.
Allowing such operations in the forall body would open the doors to
generating ill-formed programs where such operation would be used for
non index-values.

Instead, add an hlfir.forall_index with both required interface to
produce a memory address for a forall index.

As a bonus, since forall index-value are by nature read-only, the
loads of hlfir.forall_index can be canonicalized, which will help
simplifying the hlfir.forall nested code (it is unclear we will be
able to tell MLIR enough about hlfir.forall and hlfir.where structure
so that it could safely do a generic mem-to-reg inside it, and getting
rid of read-effect operations will benefit the forall rewrite pass).

Differential Revision: https://reviews.llvm.org/D149836

Added: 
    flang/test/HLFIR/forall-index.fir

Modified: 
    flang/include/flang/Optimizer/HLFIR/HLFIROps.td
    flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 12f9a8b98fcec..87136197851a0 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -1258,4 +1258,49 @@ def hlfir_ElseWhereOp : hlfir_Op<"elsewhere", [Terminator,
   let hasVerifier = 1;
 }
 
+def hlfir_ForallIndexOp : hlfir_Op<"forall_index", [fir_FortranVariableOpInterface,
+    hlfir_OrderedAssignmentTreeOpInterface, Pure]> {
+  let summary = "represent a Fortran forall index declaration";
+  let description = [{
+    This operation allows placing an hlfir.forall index in memory with
+    the related Fortran index-value name and type.
+
+    So far, lowering needs to manipulate symbols as memory entities.
+    This operation allows fulfilling this requirements without allowing
+    bare alloca/declare/store inside the body of hlfir.forall, which would
+    make their analysis more complex.
+
+    Given Forall index-value cannot be modified it also allows defining
+    a canonicalization of all its loads into a fir.convert of the
+    hlfir.forall index, which helps simplifying the data dependency analysis
+    of hlfir.forall.
+  }];
+
+  let arguments = (ins AnyIntegerType:$index,
+                       Builtin_StringAttr:$name);
+
+  let results = (outs AnyFortranVariable);
+
+  let assemblyFormat = [{
+    $name $index attr-dict `:` functional-type(operands, results)
+  }];
+
+  let extraClassDeclaration = [{
+    /// Implement FortranVariableInterface interface.
+    std::optional<fir::FortranVariableFlagsEnum> getFortranAttrs() const {
+      return std::nullopt;
+    }
+    mlir::Value getShape() const {return mlir::Value{};}
+    mlir::OperandRange getExplicitTypeParams() const {
+      // Return an empty range.
+      return {(*this)->getOperands().begin(), (*this)->getOperands().begin()};
+    }
+    /// Implement OrderedAssignmentTreeOpInterface interface.
+    void getLeafRegions(llvm::SmallVectorImpl<mlir::Region*>& regions) {}
+    mlir::Region* getSubTreeRegion() { return nullptr; }
+  }];
+
+  let hasCanonicalizeMethod = 1;
+}
+
 #endif // FORTRAN_DIALECT_HLFIR_OPS

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index ed6e473b1b907..7599b8d2756e0 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -1244,6 +1244,28 @@ mlir::LogicalResult hlfir::ElseWhereOp::verify() {
   return verifyWhereAndElseWhereBody(*this);
 }
 
+//===----------------------------------------------------------------------===//
+// ForallIndexOp
+//===----------------------------------------------------------------------===//
+
+mlir::LogicalResult
+hlfir::ForallIndexOp::canonicalize(hlfir::ForallIndexOp indexOp,
+                                   mlir::PatternRewriter &rewriter) {
+  auto insertPt = rewriter.saveInsertionPoint();
+  for (mlir::Operation *user : indexOp->getResult(0).getUsers())
+    if (auto loadOp = mlir::dyn_cast_or_null<fir::LoadOp>(user)) {
+      rewriter.setInsertionPoint(loadOp);
+      rewriter.replaceOpWithNewOp<fir::ConvertOp>(
+          user, loadOp.getResult().getType(), indexOp.getIndex());
+    }
+  rewriter.restoreInsertionPoint(insertPt);
+  if (indexOp.use_empty()) {
+    rewriter.eraseOp(indexOp);
+    return mlir::success();
+  }
+  return mlir::failure();
+}
+
 #include "flang/Optimizer/HLFIR/HLFIROpInterfaces.cpp.inc"
 #define GET_OP_CLASSES
 #include "flang/Optimizer/HLFIR/HLFIROps.cpp.inc"

diff  --git a/flang/test/HLFIR/forall-index.fir b/flang/test/HLFIR/forall-index.fir
new file mode 100644
index 0000000000000..02c5f412ebd3a
--- /dev/null
+++ b/flang/test/HLFIR/forall-index.fir
@@ -0,0 +1,44 @@
+// Test hlfir.forall_index operation parse, verify (no errors), unparse,
+// and canonicalization.
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+// RUN: fir-opt -canonicalize %s | FileCheck %s --check-prefix=CANONICALIZATION
+
+func.func @forall_index(%x: !fir.ref<!fir.array<10xf32>>, %y: !fir.ref<!fir.array<10xf32>>) {
+  %c1 = arith.constant 1 : index
+  %c10 = arith.constant 10 : index
+  hlfir.forall lb {
+    hlfir.yield %c1 : index
+  } ub {
+    hlfir.yield %c10 : index
+  } (%arg0: i64) {
+    %i = hlfir.forall_index "i" %arg0 : (i64) -> !fir.ref<i64>
+    hlfir.region_assign {
+      %ival = fir.load %i : !fir.ref<i64>
+      %yi = hlfir.designate %y(%ival) : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
+      hlfir.yield %yi : !fir.ref<f32>
+    } to {
+      %ival = fir.load %i : !fir.ref<i64>
+      %xi = hlfir.designate %x(%ival) : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
+      hlfir.yield %xi : !fir.ref<f32>
+    }
+    hlfir.region_assign {
+      %res = fir.call @taking_address(%i) : (!fir.ref<i64>) -> f32
+      hlfir.yield %res : f32
+    } to {
+      %ival = fir.load %i : !fir.ref<i64>
+      %xi = hlfir.designate %x(%ival) : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
+      hlfir.yield %xi : !fir.ref<f32>
+    }
+  }
+  return
+}
+// CHECK:           hlfir.forall lb {
+// CHECK:           } ub {
+// CHECK:           }  (%[[VAL_4:.*]]: i64) {
+// CHECK:             hlfir.forall_index "i" %[[VAL_4]] : (i64) -> !fir.ref<i64>
+
+// CANONICALIZATION:  %[[VAL_5:.*]] = hlfir.forall_index "i" %[[VAL_4:.*]] : (i64) -> !fir.ref<i64>
+// CANONICALIZATION:  hlfir.designate %{{.*}} (%[[VAL_4]])  : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
+// CANONICALIZATION:  hlfir.designate %{{.*}} (%[[VAL_4]])  : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
+// CANONICALIZATION:  fir.call @taking_address(%[[VAL_5]]) : (!fir.ref<i64>) -> f32
+// CANONICALIZATION:  hlfir.designate %{{.*}} (%[[VAL_4]])  : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>


        


More information about the flang-commits mailing list