[flang-commits] [flang] 275c272 - [flang][hlfir] add allocatable assignment semantic to hlfir.assign

Jean Perier via flang-commits flang-commits at lists.llvm.org
Mon Feb 27 00:04:00 PST 2023


Author: Jean Perier
Date: 2023-02-27T09:03:34+01:00
New Revision: 275c272c39a26af90c5a371a2eb27b4549c21bc7

URL: https://github.com/llvm/llvm-project/commit/275c272c39a26af90c5a371a2eb27b4549c21bc7
DIFF: https://github.com/llvm/llvm-project/commit/275c272c39a26af90c5a371a2eb27b4549c21bc7.diff

LOG: [flang][hlfir] add allocatable assignment semantic to hlfir.assign

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

Added: 
    

Modified: 
    flang/include/flang/Optimizer/HLFIR/HLFIROps.td
    flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
    flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
    flang/test/HLFIR/assign-codegen.fir
    flang/test/HLFIR/assign.fir
    flang/test/HLFIR/invalid.fir

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index ef0d1d1f0462f..241412304a5f6 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -125,14 +125,48 @@ def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> {
     Assign rhs to lhs following Fortran intrinsic assignments rules.
     The operation deals with inserting a temporary if the lhs and rhs
     may overlap.
+    The optional "realloc" flag allows indicating that this assignment
+    has the Fortran 95 semantics for assignments to a whole allocatable.
+    In such case, the left hand side must be an allocatable that may be
+    unallocated or allocated with a 
diff erent type and shape than the right
+    hand side. It will be allocated or re-allocated as needed during the
+    assignment.
+    When "realloc" is set and this is a character assignment, the optional
+    flag "keep_lhs_length_if_realloc" indicates that the character
+    left hand side should retain its length after the assignment. If the
+    right hand side has a 
diff erent length, truncation and padding will
+    occur. This covers the case of explicit and assumed length character
+    allocatables.
+    Otherwise, the left hand side will be allocated or reallocated to match the
+    right hand side length if they 
diff er. This covers the case of deferred
+    length character allocatables.
   }];
 
   let arguments = (ins AnyFortranEntity:$rhs,
-                   Arg<AnyFortranVariable, "", [MemWrite]>:$lhs);
+                   Arg<AnyFortranVariable, "", [MemWrite]>:$lhs,
+                   UnitAttr:$realloc,
+                   UnitAttr:$keep_lhs_length_if_realloc);
 
   let assemblyFormat = [{
-    $rhs `to` $lhs attr-dict `:` type(operands)
+    $rhs `to` $lhs (`realloc` $realloc^)?
+    (`keep_lhs_len` $keep_lhs_length_if_realloc^)?
+    attr-dict `:` type(operands)
   }];
+
+  let extraClassDeclaration = [{
+    /// Does this assignment have the Fortran 95 semantics of assignments
+    /// to a whole allocatable?
+    bool isAllocatableAssignment() {
+      return getRealloc();
+    }
+    /// Is the assignment left hand side a whole allocatable character
+    /// that should retain its length after the assignment?
+    bool mustKeepLhsLengthInAllocatableAssignment() {
+      return getKeepLhsLengthIfRealloc();
+    }
+  }];
+
+  let hasVerifier = 1;
 }
 
 def hlfir_DesignateOp : hlfir_Op<"designate", [AttrSizedOperandSegments,

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index fed7e837a34dc..6d747615b4362 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -27,6 +27,29 @@
 // DeclareOp
 //===----------------------------------------------------------------------===//
 
+/// Is this a fir.[ref/ptr/heap]<fir.[box/class]<fir.heap<T>>> type?
+static bool isAllocatableBoxRef(mlir::Type type) {
+  fir::BaseBoxType boxType =
+      fir::dyn_cast_ptrEleTy(type).dyn_cast_or_null<fir::BaseBoxType>();
+  return boxType && boxType.getEleTy().isa<fir::HeapType>();
+}
+
+mlir::LogicalResult hlfir::AssignOp::verify() {
+  mlir::Type lhsType = getLhs().getType();
+  if (isAllocatableAssignment() && !isAllocatableBoxRef(lhsType))
+    return emitOpError("lhs must be an allocatable when `realloc` is set");
+  if (mustKeepLhsLengthInAllocatableAssignment() &&
+      !(isAllocatableAssignment() &&
+        hlfir::getFortranElementType(lhsType).isa<fir::CharacterType>()))
+    return emitOpError("`realloc` must be set and lhs must be a character "
+                       "allocatable when `keep_lhs_length_if_realloc` is set");
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
+// DeclareOp
+//===----------------------------------------------------------------------===//
+
 /// Given a FIR memory type, and information about non default lower bounds, get
 /// the related HLFIR variable type.
 mlir::Type hlfir::DeclareOp::getHLFIRVariableType(mlir::Type inputType,

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 181bc2f87b232..fd4a85c8a2496 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -82,7 +82,7 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
     assert(!lhsCleanUp && !rhsCleanUp &&
            "variable to fir::ExtendedValue must not require cleanup");
 
-    if (lhs.isArray()) {
+    auto emboxRHS = [&](fir::ExtendedValue &rhsExv) -> mlir::Value {
       // There may be overlap between lhs and rhs. The runtime is able to detect
       // and to make a copy of the rhs before modifying the lhs if needed.
       // The code below relies on this and does not do any compile time alias
@@ -100,16 +100,35 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
         builder.create<fir::StoreOp>(loc, rhsVal, temp);
         rhsExv = temp;
       }
-
+      return fir::getBase(builder.createBox(loc, rhsExv));
+    };
+
+    if (assignOp.isAllocatableAssignment()) {
+      // Whole allocatable assignment: use the runtime to deal with the
+      // reallocation.
+      mlir::Value from = emboxRHS(rhsExv);
+      mlir::Value to = fir::getBase(lhsExv);
+      if (assignOp.mustKeepLhsLengthInAllocatableAssignment()) {
+        // Indicate the runtime that it should not reallocate in case of length
+        // mismatch, and that it should use the LHS explicit/assumed length if
+        // allocating/reallocation the LHS.
+        TODO(loc, "assignment to explicit length whole allocatable");
+      } else if (lhs.isPolymorphic()) {
+        // Indicate the runtime that the LHS must have the RHS dynamic type
+        // after the assignment.
+        TODO(loc, "assignment to whole polymorphic entity");
+      } else {
+        fir::runtime::genAssign(builder, loc, to, from);
+      }
+    } else if (lhs.isArray()) {
       // Use the runtime for simplicity. An optimization pass will be added to
       // inline array assignment when profitable.
-      auto to = fir::getBase(builder.createBox(loc, lhsExv));
-      auto from = fir::getBase(builder.createBox(loc, rhsExv));
-
+      mlir::Value from = emboxRHS(rhsExv);
+      mlir::Value to = fir::getBase(builder.createBox(loc, lhsExv));
+      // This is not a whole allocatable assignment: the runtime will not
+      // reallocate and modify "toMutableBox" even if it is taking it by
+      // reference.
       auto toMutableBox = builder.createTemporary(loc, to.getType());
-      // As per 10.2.1.2 point 1 (1) polymorphic variables must be allocatable.
-      // It is assumed here that they have been reallocated with the dynamic
-      // type and that the mutableBox will not be modified.
       builder.create<fir::StoreOp>(loc, to, toMutableBox);
       fir::runtime::genAssign(builder, loc, toMutableBox, from);
     } else {

diff  --git a/flang/test/HLFIR/assign-codegen.fir b/flang/test/HLFIR/assign-codegen.fir
index 5736ca9af98d1..06c4ae1ab18c5 100644
--- a/flang/test/HLFIR/assign-codegen.fir
+++ b/flang/test/HLFIR/assign-codegen.fir
@@ -172,3 +172,14 @@ func.func @test_i1_scalar_to_array(%lhs: !fir.box<!fir.array<?x!fir.logical<4>>>
 // CHECK:  %[[VAL_7:.*]] = fir.embox %[[VAL_6]] : (!fir.ref<!fir.logical<4>>) -> !fir.box<!fir.logical<4>>
 // CHECK:  %[[VAL_12:.*]] = fir.convert %[[VAL_7]] : (!fir.box<!fir.logical<4>>) -> !fir.box<none>
 // CHECK:  %[[VAL_14:.*]] = fir.call @_FortranAAssign(%{{.*}}, %[[VAL_12]]
+
+func.func @alloc_assign(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.box<!fir.array<?xi32>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  return
+}
+// CHECK-LABEL:  func.func @alloc_assign(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
+// CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>) {
+// CHECK:  %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+// CHECK:  %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
+// CHECK:  fir.call @_FortranAAssign(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none

diff  --git a/flang/test/HLFIR/assign.fir b/flang/test/HLFIR/assign.fir
index fed2621da33ac..a416c79d56d69 100644
--- a/flang/test/HLFIR/assign.fir
+++ b/flang/test/HLFIR/assign.fir
@@ -128,3 +128,21 @@ func.func @array_4(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.box<!fir.arra
 // CHECK-SAME:    %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>,
 // CHECK-SAME:    %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>) {
 // CHECK:  hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
+
+func.func @alloc_assign(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.box<!fir.array<?xi32>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  return
+}
+// CHECK-LABEL:   func.func @alloc_assign(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>) {
+// CHECK:  hlfir.assign %[[VAL_1]] to %[[VAL_0]] realloc : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+
+func.func @alloc_assign_keep_lhs_len(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>, %arg1: !fir.box<!fir.array<?x!fir.char<1,?>>>) {
+  hlfir.assign %arg1 to %arg0 realloc keep_lhs_len : !fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>
+  return
+}
+// CHECK-LABEL:   func.func @alloc_assign_keep_lhs_len(
+// CHECK-SAME:    %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>,
+// CHECK-SAME:    %[[VAL_1:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>>) {
+// CHECK:  hlfir.assign %[[VAL_1]] to %[[VAL_0]] realloc keep_lhs_len : !fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>

diff  --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir
index b4afc8fe48a11..91fb7df6a7559 100644
--- a/flang/test/HLFIR/invalid.fir
+++ b/flang/test/HLFIR/invalid.fir
@@ -375,3 +375,17 @@ func.func @bad_matmul8(%arg0: !hlfir.expr<2xi32>, %arg1: !hlfir.expr<2x3xi32>) {
   %0 = hlfir.matmul %arg0 %arg1 : (!hlfir.expr<2xi32>, !hlfir.expr<2x3xi32>) -> !hlfir.expr<1x3xi32>
   return
 }
+
+// -----
+func.func @bad_assign_1(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.box<!fir.array<?xi32>>) {
+  // expected-error at +1 {{'hlfir.assign' op lhs must be an allocatable when `realloc` is set}}
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
+  return
+}
+
+// -----
+func.func @bad_assign_2(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.box<!fir.array<?xi32>>) {
+  // expected-error at +1 {{'hlfir.assign' op `realloc` must be set and lhs must be a character allocatable when `keep_lhs_length_if_realloc` is set}}
+  hlfir.assign %arg1 to %arg0 realloc keep_lhs_len : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  return
+}


        


More information about the flang-commits mailing list