[llvm-branch-commits] [flang] [flang] - Call _FortranAAssignSimple instead of _FortranAAssign for intrinsic-type array assignments (PR #213705)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Aug 3 08:56:34 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-openmp

Author: Pranav Bhandarkar (bhandarkar-pranav)

<details>
<summary>Changes</summary>

This patch adds support for calling _FortranAAssignSimple, a faster-path for array assignments. `_FortranAAssignSimple` is called when ALL the following conditions are true:
1. Intrinsic element type (not derived type)
2. Matching ranks (no scalar-to-array broadcasting)
3. Non-volatile
4. Not polymorphic
5. Not explicit-length character
6. Not temporary LHS

Otherwise, uses `_FortranAAssign` (or specialized variants like `_FortranAAssignPolymorphic`, `_FortranAAssignExplicitLengthCharacter`).

This is the final part of the fix for https://github.com/llvm/llvm-project/issues/203915

---

Patch is 28.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213705.diff


8 Files Affected:

- (modified) flang/include/flang/Optimizer/Builder/Runtime/Assign.h (+12) 
- (modified) flang/lib/Optimizer/Builder/Runtime/Assign.cpp (+13) 
- (modified) flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp (+46-4) 
- (modified) flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp (+19-13) 
- (modified) flang/test/HLFIR/assign-codegen.fir (+2-2) 
- (added) flang/test/HLFIR/assign-simple-routing.fir (+287) 
- (modified) flang/test/HLFIR/fir-local-alloca-block.fir (+1-1) 
- (modified) flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90 (+1-1) 


``````````diff
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Assign.h b/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
index 52a6a1d8e5a02..fda941c3261e5 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
@@ -63,5 +63,17 @@ void genCopyInAssign(fir::FirOpBuilder &builder, mlir::Location loc,
 void genCopyOutAssign(fir::FirOpBuilder &builder, mlir::Location loc,
                       mlir::Value varBoxAddr, mlir::Value tempBoxAddr);
 
+/// Generate runtime call to AssignSimple (fast path for intrinsic types).
+/// \p destBox must be a fir.ref<fir.box<T>> and \p sourceBox a fir.box<T>.
+/// Preconditions enforced at call site:
+///   - Intrinsic element type (integer, real, complex, logical)
+///   - Matching ranks (no scalar-to-array broadcasting)
+///   - Same element byte size
+///   - Non-volatile
+/// Runtime handles: contiguous and non-contiguous layouts, aliasing detection,
+/// allocatable reallocation.
+void genAssignSimple(fir::FirOpBuilder &builder, mlir::Location loc,
+                     mlir::Value destBox, mlir::Value sourceBox);
+
 } // namespace fir::runtime
 #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ASSIGN_H
diff --git a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
index 336dbdc89c04a..fc9c6b0eb51e3 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
@@ -95,3 +95,16 @@ void fir::runtime::genCopyOutAssign(fir::FirOpBuilder &builder,
                                             sourceBox, sourceFile, sourceLine);
   fir::CallOp::create(builder, loc, func, args);
 }
+
+void fir::runtime::genAssignSimple(fir::FirOpBuilder &builder,
+                                   mlir::Location loc, mlir::Value destBox,
+                                   mlir::Value sourceBox) {
+  auto func = fir::runtime::getRuntimeFunc<mkRTKey(AssignSimple)>(loc, builder);
+  auto fTy = func.getFunctionType();
+  auto sourceFile = fir::factory::locationToFilename(builder, loc);
+  auto sourceLine =
+      fir::factory::locationToLineNo(builder, loc, fTy.getInput(3));
+  auto args = fir::runtime::createArguments(builder, loc, fTy, destBox,
+                                            sourceBox, sourceFile, sourceLine);
+  fir::CallOp::create(builder, loc, func, args);
+}
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 29c209f4c338e..19142a77d0b5b 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -29,6 +29,10 @@ namespace hlfir {
 #define GEN_PASS_DEF_CONVERTHLFIRTOFIR
 #include "flang/Optimizer/HLFIR/Passes.h.inc"
 } // namespace hlfir
+static llvm::cl::opt<bool> useFortranAssignOnly(
+    "use-fortran-assign-only",
+    llvm::cl::desc("Do not use _FortranAAssignSimple. Only _FortranAAssign"),
+    llvm::cl::init(false));
 
 using namespace mlir;
 
@@ -145,7 +149,26 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
           // type after the assignment.
           fir::runtime::genAssignPolymorphic(builder, loc, to, from);
         } else {
-          fir::runtime::genAssign(builder, loc, to, from);
+          // Use simple path for allocatable with trivial types (scalars and
+          // arrays) Only use Simple path when ranks match. Only use Simple path
+          // for non-volatile - volatile needs memory ordering NOTE: For
+          // allocatables, we assume contiguity - allocatable whole-array
+          // assignments
+          //       are always contiguous. Strided sections of allocatables go
+          //       through different path.
+          if (!lhs.isPolymorphic() &&
+              fir::isa_trivial(lhs.getFortranElementType()) &&
+              lhs.getRank() == rhs.getRank() &&
+              !fir::isa_volatile_type(lhs.getType()) &&
+              !cuf::getDataAttr(lhs.getDefiningOp())) {
+            // Simple intrinsic type allocatable with matching ranks,
+            // non-volatile, non-polymorphic.
+            fir::runtime::genAssignSimple(builder, loc, to, from);
+          } else {
+            // Complex: derived types, polymorphic, rank mismatch
+            // (scalar-to-array), volatile, etc.
+            fir::runtime::genAssign(builder, loc, to, from);
+          }
         }
       }
     } else if (lhs.isArray() ||
@@ -169,10 +192,29 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
       // reference.
       auto toMutableBox = builder.createTemporary(loc, to.getType());
       fir::StoreOp::create(builder, loc, to, toMutableBox);
-      if (assignOp.isTemporaryLHS())
+      if (assignOp.isTemporaryLHS()) {
         fir::runtime::genAssignTemporary(builder, loc, toMutableBox, from);
-      else
-        fir::runtime::genAssign(builder, loc, toMutableBox, from);
+      } else {
+        // Use simple path for non-allocatable arrays with trivial types
+        // CRITICAL: Only use Simple path when ranks match - scalar-to-array
+        // requires broadcasting CRITICAL: Only use Simple path for non-volatile
+        // - volatile needs memory ordering NOTE: Contiguity is now handled at
+        // runtime in AssignSimple
+        if (!useFortranAssignOnly && !lhs.isPolymorphic() &&
+            fir::isa_trivial(lhs.getFortranElementType()) &&
+            lhs.getRank() == rhs.getRank() &&
+            !fir::isa_volatile_type(lhs.getType()) &&
+            !cuf::getDataAttr(lhs.getDefiningOp())) {
+          // Simple intrinsic type array with matching ranks, non-volatile,
+          // non-polymorphic. AssignSimple handles both contiguous (fast
+          // memmove) and non-contiguous (element-wise)
+          fir::runtime::genAssignSimple(builder, loc, toMutableBox, from);
+        } else {
+          // Complex: polymorphic, derived type, rank mismatch
+          // (scalar-to-array), volatile
+          fir::runtime::genAssign(builder, loc, toMutableBox, from);
+        }
+      }
     } else {
       // TODO: use the type specification to see if IsFinalizable is set,
       // or propagate IsFinalizable attribute from lowering.
diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
index 3242863cd4023..fb927786e0cff 100644
--- a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
+++ b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
@@ -57,6 +57,14 @@ namespace {
 
 /// This string is used to identify the Fortran-specific runtime FortranAAssign.
 static constexpr llvm::StringRef FortranAssignStr = "_FortranAAssign";
+static constexpr llvm::StringRef FortranAssignSimpleStr =
+    "_FortranAAssignSimple";
+
+/// Check if the function name is any variant of Fortran assignment runtime
+/// call.
+static bool isFortranAssignCall(llvm::StringRef funcName) {
+  return funcName == FortranAssignStr || funcName == FortranAssignSimpleStr;
+}
 
 /// The isRuntimeCall function is a utility designed to determine
 /// if a given operation is a call to a Fortran-specific runtime function.
@@ -76,11 +84,11 @@ static bool isRuntimeCall(Operation *op) {
 /// operation nested in an omp.workdistribute region.
 /// Parallelize here refers to dividing into units of work.
 static bool shouldParallelize(Operation *op) {
-  // True if the op is a runtime call to Assign
+  // True if the op is a runtime call to Assign (any variant)
   if (isRuntimeCall(op)) {
     fir::CallOp runtimeCall = cast<fir::CallOp>(op);
     auto funcName = runtimeCall.getCallee()->getRootReference().getValue();
-    if (funcName == FortranAssignStr) {
+    if (isFortranAssignCall(funcName)) {
       return true;
     }
   }
@@ -167,15 +175,13 @@ verifyTargetTeamsWorkdistribute(omp::WorkdistributeOp workdistribute) {
     if (auto callOp = dyn_cast<fir::CallOp>(op)) {
       if (isRuntimeCall(&op)) {
         auto funcName = (*callOp.getCallee()).getRootReference().getValue();
-        // _FortranAAssign is handled. Other runtime calls are not supported
-        // in omp.workdistribute yet.
-        if (funcName == FortranAssignStr)
+        // _FortranAAssign and _FortranAAssignSimple are handled.
+        // Other runtime calls are not supported in omp.workdistribute yet.
+        if (isFortranAssignCall(funcName))
           continue;
-        else {
-          emitError(loc, "Runtime call " + funcName +
-                             " lowering not supported for workdistribute yet.");
-          return failure();
-        }
+        emitError(loc, "Runtime call " + funcName +
+                           " lowering not supported for workdistribute yet.");
+        return failure();
       }
     }
   }
@@ -620,7 +626,7 @@ workdistributeRuntimeCallLower(omp::WorkdistributeOp workdistribute,
       rewriter.setInsertionPoint(&op);
       fir::CallOp runtimeCall = cast<fir::CallOp>(op);
       auto funcName = runtimeCall.getCallee()->getRootReference().getValue();
-      if (funcName == FortranAssignStr) {
+      if (isFortranAssignCall(funcName)) {
         if (isFortranAssignSrcScalarAndDestArray(runtimeCall) && targetOp) {
           // Record the target ops to process later
           targetOpsToProcess.insert(targetOp);
@@ -1341,7 +1347,7 @@ static LogicalResult moveToHost(omp::TargetOp targetOp, RewriterBase &rewriter,
     if (isRuntimeCall(clonedOp)) {
       fir::CallOp runtimeCall = cast<fir::CallOp>(op);
       auto funcName = runtimeCall.getCallee()->getRootReference().getValue();
-      if (funcName == FortranAssignStr) {
+      if (isFortranAssignCall(funcName)) {
         opsToReplace.push_back(clonedOp);
       } else {
         emitError(runtimeCall->getLoc(), "Unhandled runtime call hoisting.");
@@ -1391,7 +1397,7 @@ static LogicalResult moveToHost(omp::TargetOp targetOp, RewriterBase &rewriter,
     else if (isRuntimeCall(op)) {
       fir::CallOp runtimeCall = cast<fir::CallOp>(op);
       auto funcName = runtimeCall.getCallee()->getRootReference().getValue();
-      if (funcName == FortranAssignStr) {
+      if (isFortranAssignCall(funcName)) {
         rewriter.setInsertionPoint(op);
         fir::FirOpBuilder builder{rewriter, op};
 
diff --git a/flang/test/HLFIR/assign-codegen.fir b/flang/test/HLFIR/assign-codegen.fir
index cabe18ef98799..67be391327bdf 100644
--- a/flang/test/HLFIR/assign-codegen.fir
+++ b/flang/test/HLFIR/assign-codegen.fir
@@ -141,7 +141,7 @@ func.func @array(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.ref<!fir.array<
 // CHECK:  fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
 // CHECK:  %[[VAL_26:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<none>>
 // CHECK:  %[[VAL_27:.*]] = fir.convert %[[VAL_10]] : (!fir.box<!fir.array<100xi32>>) -> !fir.box<none>
-// CHECK:  fir.call @_FortranAAssign(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+// CHECK:  fir.call @_FortranAAssignSimple(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
 
 
 func.func @array_temp(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.ref<!fir.array<100xi32>>) {
@@ -206,7 +206,7 @@ func.func @alloc_assign(%arg0: !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) -> ()
+// CHECK:  fir.call @_FortranAAssignSimple(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
 
 func.func @alloc_assign_temp(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.box<!fir.array<?xi32>>) {
   hlfir.assign %arg1 to %arg0 realloc temporary_lhs : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
diff --git a/flang/test/HLFIR/assign-simple-routing.fir b/flang/test/HLFIR/assign-simple-routing.fir
new file mode 100644
index 0000000000000..963f54cd61e0f
--- /dev/null
+++ b/flang/test/HLFIR/assign-simple-routing.fir
@@ -0,0 +1,287 @@
+// Test routing decisions for _FortranAAssignSimple vs _FortranAAssign in
+// hlfir.assign lowering to FIR. The routing logic lives in ConvertToFIR.cpp
+// and has two main decision points:
+//
+//   1. Allocatable path (isAllocatableAssignment): routes to AssignSimple when
+//      isa_trivial(elementType) && ranksMatch && !volatile
+//
+//   2. Non-allocatable array path (lhs.isArray()): routes to AssignSimple when
+//      !polymorphic && isa_trivial(elementType) && ranksMatch && !volatile
+//
+// This file verifies every boundary condition of those routing decisions.
+
+// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s
+
+// ---------------------------------------------------------------------------
+// POSITIVE CASES: should route to _FortranAAssignSimple
+// ---------------------------------------------------------------------------
+
+// Allocatable rank-1 i32 array: trivial integer type, ranks match (1==1),
+// non-volatile.  This is the canonical "simple allocatable" case.
+func.func @alloc_i32_array(%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_i32_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Allocatable rank-1 f64 array: trivial real type, ranks match (1==1),
+// non-volatile.  Verifies that real (double-precision) types are routed simply.
+func.func @alloc_f64_array(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>,
+                            %arg1: !fir.box<!fir.array<?xf64>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?xf64>>,
+      !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>
+  return
+}
+// CHECK-LABEL: func.func @alloc_f64_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Allocatable rank-1 complex<f32> array: trivial complex type, ranks match,
+// non-volatile.  Verifies complex intrinsic types (MLIR ComplexType) are
+// routed simply — isa_complex() checks mlir::ComplexType with float element.
+func.func @alloc_complex_array(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xcomplex<f32>>>>>,
+                                %arg1: !fir.box<!fir.array<?xcomplex<f32>>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?xcomplex<f32>>>,
+      !fir.ref<!fir.box<!fir.heap<!fir.array<?xcomplex<f32>>>>>
+  return
+}
+// CHECK-LABEL: func.func @alloc_complex_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Allocatable rank-1 logical<4> array: trivial logical type, ranks match,
+// non-volatile.  Verifies logical intrinsic types are routed simply.
+func.func @alloc_logical_array(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>,
+                                %arg1: !fir.box<!fir.array<?x!fir.logical<4>>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?x!fir.logical<4>>>,
+      !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+  return
+}
+// CHECK-LABEL: func.func @alloc_logical_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Allocatable rank-2 i32 array: trivial integer type, ranks match (2==2),
+// non-volatile.  Verifies that the rank-match check works for rank-2.
+func.func @alloc_i32_2d(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>,
+                         %arg1: !fir.box<!fir.array<?x?xi32>>) {
+  hlfir.assign %arg1 to %arg0 realloc : !fir.box<!fir.array<?x?xi32>>,
+      !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>
+  return
+}
+// CHECK-LABEL: func.func @alloc_i32_2d(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Non-allocatable rank-1 i32 array: non-polymorphic, trivial integer, ranks
+// match (1==1), non-volatile.  Canonical "simple non-allocatable array" case.
+func.func @nonalloc_i32_array(%arg0: !fir.box<!fir.array<?xi32>>,
+                               %arg1: !fir.ref<!fir.array<100xi32>>) {
+  %c100 = arith.constant 100 : index
+  %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %arg1(%1) {uniq_name = "y"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
+  hlfir.assign %2#0 to %0#0 : !fir.ref<!fir.array<100xi32>>, !fir.box<!fir.array<?xi32>>
+  return
+}
+// CHECK-LABEL: func.func @nonalloc_i32_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Non-allocatable rank-1 f32 array: non-polymorphic, trivial real, ranks
+// match (1==1), non-volatile.  Verifies f32 (single-precision) is routed simply.
+func.func @nonalloc_f32_array(%arg0: !fir.box<!fir.array<?xf32>>,
+                               %arg1: !fir.ref<!fir.array<100xf32>>) {
+  %c100 = arith.constant 100 : index
+  %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %arg1(%1) {uniq_name = "y"} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
+  hlfir.assign %2#0 to %0#0 : !fir.ref<!fir.array<100xf32>>, !fir.box<!fir.array<?xf32>>
+  return
+}
+// CHECK-LABEL: func.func @nonalloc_f32_array(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+
+// Non-allocatable rank-1 logical<4> array: non-polymorphic, trivial logical,
+// ranks match (1==1), non-volatile.  Verifies logical types in the non-alloc path.
+func.func @nonalloc_logical(%arg0: !fir.box<!fir.array<?x!fir.logical<4>>>,
+                             %arg1: !fir.ref<!fir.array<100x!fir.logical<4>>>) {
+  %c100 = arith.constant 100 : index
+  %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> (!fir.box<!fir.array<?x!fir.logical<4>>>, !fir.box<!fir.array<?x!fir.logical<4>>>)
+  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %arg1(%1) {uniq_name = "y"} : (!fir.ref<!fir.array<100x!fir.logical<4>>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100x!fir.logical<4>>>, !fir.ref<!fir.array<100x!fir.logical<4>>>)
+  hlfir.assign %2#0 to %0#0 : !fir.ref<!fir.array<100x!fir.logical<4>>>, !fir.box<!fir.array<?x!fir.logical<4>>>
+  return
+}
+// CHECK-LABEL: func.func @nonalloc_logical(
+// CHECK:       fir.call @_FortranAAssignSimple(
+// CHECK-NOT:   fir.call @_FortranAAssign(
+
+// ---------------------------------------------------------------------------
+// NEGATIVE CASES: should NOT use AssignSimple, route to _FortranAAssign
+// ---------------------------------------------------------------------------
+
+// Allocatable derived type array: !isa_trivial(elementType).  Derived types
+// may need finalization/copy semantics so they cannot use the simple path.
+func.func @alloc_derived(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.arr...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/213705


More information about the llvm-branch-commits mailing list