[flang-commits] [flang] Reland "[Flang]Add support for inlining hlfir.assign operation where both LHS and RHS are slices of the same array #204532" (PR #208159)

via flang-commits flang-commits at lists.llvm.org
Wed Jul 8 00:29:17 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Kaviya Rajendiran (kaviya2510)

<details>
<summary>Changes</summary>

Added support for inlining hlfir.assign when both LHS and RHS are slices of the same array. When overlap between the slices cannot be determined, the pass introduces a disjointness check:

- genIndexBasedDisjointnessCheck(..) is used when both sides are sections of the same array.
- genAddressBasedDisjointnessCheck(..) used as a fallback for more complex cases.

At runtime:

- If the slices are disjoint, a direct element-wise copy is performed without allocating a temporary buffer.
- If overlap is possible, a temporary buffer is allocated, the RHS is first copied into it and then the data is copied from the temporary buffer to the LHS.

Fixes https://github.com/llvm/llvm-project/issues/203228

----

This patch also fixes the regression in fujistu testsuite. 

**Issue 1:**

-  The previous implementation handled potential aliasing by creating an `hlfir.as_expr` temporary for the RHS. This works fine, but causes problems in the forall case.
-  `LowerHLFIROrderedAssignments` pass introduces additional `hlfir.assign` operations, which are carried through `BufferizeHLFIR` pass. When `InlineHLFIRAssign`  runs again, it revisits these assignments and attempts to create a new `hlfir.as_expr` from an already bufferized RHS. Since hlfir.as_expr is illegal after bufferization, this results in: 
```fortran
 error: failed to legalize operation 'hlfir.as_expr' that was explicitly marked illegal:
```

Fix:

-  Replaced the `hlfir.as_expr` based approach with an explicit temporary created via `createTempFromMold(..)` .This avoids introducing operations that are illegal after bufferization.

----

**Issue 2:**

- When either side of an assignment is a pointer, alias analysis returns `mayAlias`, causing `genAddressBasedDisjointnessCheck()` to create a temporary copy. After `BufferizeHLFIR` pass , InlineHLFIRAssign processes the resulting `hlfir.assign` again. Because alias analysis still returns mayAlias for the assignment involving the temporary and the original RHS, a second unnecessary temporary is created.

Fix:

- Skipped the alias-disjointness check for assignments with `assign.getTemporaryLhs()`, since the LHS is already a compiler-generated temporary created to resolve the aliasing concern.


---

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


10 Files Affected:

- (modified) flang/include/flang/Optimizer/Analysis/ArraySectionAnalyzer.h (+1-1) 
- (modified) flang/include/flang/Optimizer/Builder/FIRBuilder.h (+10) 
- (modified) flang/lib/Optimizer/Builder/FIRBuilder.cpp (+137) 
- (modified) flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp (+65-13) 
- (added) flang/test/HLFIR/inline-hlfir-assign-pointer-overlap.fir (+140) 
- (added) flang/test/HLFIR/inline-hlfir-assign-scalar-index.fir (+106) 
- (added) flang/test/HLFIR/inline-hlfir-assign-self-copy-runtime-stride.fir (+149) 
- (added) flang/test/HLFIR/inline-hlfir-assign-self-copy.fir (+190) 
- (added) flang/test/Lower/inline-hlfir-assign-forall-threadprivate.f90 (+119) 
- (added) flang/test/Lower/inline-hlfir-assign-pointer-omp.f90 (+125) 


``````````diff
diff --git a/flang/include/flang/Optimizer/Analysis/ArraySectionAnalyzer.h b/flang/include/flang/Optimizer/Analysis/ArraySectionAnalyzer.h
index e87e37c3c5590..aae9cbde2d7be 100644
--- a/flang/include/flang/Optimizer/Analysis/ArraySectionAnalyzer.h
+++ b/flang/include/flang/Optimizer/Analysis/ArraySectionAnalyzer.h
@@ -65,7 +65,6 @@ class ArraySectionAnalyzer {
   static bool isDesignatingArrayInOrder(hlfir::DesignateOp designate,
                                         hlfir::ElementalOpInterface elemental);
 
-private:
   struct SectionDesc {
     // An array section is described by <lb, ub, stride> tuple.
     // If the designator's subscript is not a triple, then
@@ -103,6 +102,7 @@ class ArraySectionAnalyzer {
   static std::pair<mlir::Value, mlir::Value>
   getOrderedBounds(const SectionDesc &desc);
 
+private:
   // Given two array sections <lb1, ub1, stride1> and
   // <lb2, ub2, stride2>, return true only if the sections
   // are known to be disjoint.
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 3622351c1ef64..f88c19049f42d 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -990,6 +990,16 @@ mlir::Value getDescriptorWithNewBaseAddress(fir::FirOpBuilder &builder,
                                             mlir::Location loc, mlir::Value box,
                                             mlir::Value newAddr);
 
+/// Generate a index-based disjointness check.
+std::optional<mlir::Value>
+genIndexBasedDisjointnessCheck(mlir::Location loc, fir::FirOpBuilder &builder,
+                               mlir::Value lhsRef, mlir::Value rhsRef);
+
+/// Generate a address-based disjointness check.
+std::optional<mlir::Value>
+genAddressBasedDisjointnessCheck(mlir::Location loc, fir::FirOpBuilder &builder,
+                                 mlir::Value lhsRef, mlir::Value rhsRef);
+
 } // namespace fir::factory
 
 #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index d97b56af570b4..33360d891c3fa 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -8,6 +8,7 @@
 
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Analysis/AliasAnalysis.h"
+#include "flang/Optimizer/Analysis/ArraySectionAnalyzer.h"
 #include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/Complex.h"
@@ -21,10 +22,12 @@
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
 #include "flang/Optimizer/Support/DataLayout.h"
 #include "flang/Optimizer/Support/FatalError.h"
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Optimizer/Support/Utils.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
@@ -2007,3 +2010,137 @@ mlir::Value fir::factory::getDescriptorWithNewBaseAddress(
   return builder.createBox(loc, boxType, newAddr, shape, /*slice=*/{},
                            fir::getTypeParams(openedInput), typeMold);
 }
+
+std::optional<mlir::Value> fir::factory::genIndexBasedDisjointnessCheck(
+    mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value lhsRef,
+    mlir::Value rhsRef) {
+  auto des1 = lhsRef.getDefiningOp<hlfir::DesignateOp>();
+  auto des2 = rhsRef.getDefiningOp<hlfir::DesignateOp>();
+  if (!des1 || !des2)
+    return std::nullopt;
+
+  if (des1.getMemref() != des2.getMemref())
+    return std::nullopt;
+
+  if (des1.getComponent() != des2.getComponent() ||
+      des1.getComponentShape() != des2.getComponentShape() ||
+      des1.getSubstring() != des2.getSubstring() ||
+      des1.getComplexPart() != des2.getComplexPart() ||
+      des1.getTypeparams() != des2.getTypeparams())
+    return std::nullopt;
+
+  if (des1.getIsTriplet().empty() ||
+      !llvm::equal(des1.getIsTriplet(), des2.getIsTriplet()))
+    return std::nullopt;
+
+  using Analyzer = fir::ArraySectionAnalyzer;
+  mlir::Type idxTy = builder.getIndexType();
+  auto toIdx = [&](mlir::Value v) -> mlir::Value {
+    return fir::ConvertOp::create(builder, loc, idxTy, v);
+  };
+
+  mlir::Value disjoint;
+  auto des1It = des1.getIndices().begin();
+  auto des2It = des2.getIndices().begin();
+  for (bool isTriplet : des1.getIsTriplet()) {
+    Analyzer::SectionDesc desc1 = Analyzer::readSectionDesc(des1It, isTriplet);
+    Analyzer::SectionDesc desc2 = Analyzer::readSectionDesc(des2It, isTriplet);
+    auto [lb1, ub1] = Analyzer::getOrderedBounds(desc1);
+    auto [lb2, ub2] = Analyzer::getOrderedBounds(desc2);
+    if (!lb1 || !lb2)
+      continue;
+
+    mlir::Value c1 = mlir::arith::CmpIOp::create(
+        builder, loc, mlir::arith::CmpIPredicate::slt, toIdx(ub1), toIdx(lb2));
+    mlir::Value c2 = mlir::arith::CmpIOp::create(
+        builder, loc, mlir::arith::CmpIPredicate::slt, toIdx(ub2), toIdx(lb1));
+    mlir::Value c1Orc2 = mlir::arith::OrIOp::create(builder, loc, c1, c2);
+    disjoint = disjoint
+                   ? mlir::arith::OrIOp::create(builder, loc, disjoint, c1Orc2)
+                   : c1Orc2;
+  }
+  if (!disjoint)
+    return std::nullopt;
+  return disjoint;
+}
+
+std::optional<mlir::Value> fir::factory::genAddressBasedDisjointnessCheck(
+    mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value lhsRef,
+    mlir::Value rhsRef) {
+  if (!mlir::isa<fir::BaseBoxType>(lhsRef.getType()) ||
+      !mlir::isa<fir::BaseBoxType>(rhsRef.getType()))
+    return std::nullopt;
+
+  mlir::Type idxTy = builder.getIndexType();
+  mlir::Type intPtrTy = builder.getIntPtrType();
+
+  //   Disjoint if: xEnd < yStart || yEnd < xStart.
+  auto computeRange =
+      [&](mlir::Value box) -> std::pair<mlir::Value, mlir::Value> {
+    mlir::Value baseAddr = fir::BoxAddrOp::create(builder, loc, box);
+    mlir::Value baseInt =
+        fir::ConvertOp::create(builder, loc, intPtrTy, baseAddr);
+
+    mlir::Value eleSize = fir::BoxEleSizeOp::create(builder, loc, idxTy, box);
+    mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+    mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
+
+    mlir::Value least = zero;
+    mlir::Value most = zero;
+
+    auto boxTy = mlir::cast<fir::BaseBoxType>(box.getType());
+    unsigned rank = 0;
+    if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(
+            fir::unwrapRefType(boxTy.getEleTy())))
+      rank = seqTy.getShape().size();
+
+    if (rank == 0)
+      return {nullptr, nullptr};
+
+    for (unsigned dim = 0; dim < rank; ++dim) {
+      mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim);
+      auto dims = fir::BoxDimsOp::create(builder, loc, idxTy, idxTy, idxTy, box,
+                                         dimVal);
+      mlir::Value extent = dims.getExtent();
+      mlir::Value stride = dims.getByteStride();
+
+      mlir::Value extentM1 =
+          mlir::arith::SubIOp::create(builder, loc, extent, one);
+      mlir::Value dimOffset =
+          mlir::arith::MulIOp::create(builder, loc, extentM1, stride);
+
+      mlir::Value isStrideNeg = mlir::arith::CmpIOp::create(
+          builder, loc, mlir::arith::CmpIPredicate::slt, stride, zero);
+      mlir::Value addToLeast = mlir::arith::SelectOp::create(
+          builder, loc, isStrideNeg, dimOffset, zero);
+      mlir::Value addToMost = mlir::arith::SelectOp::create(
+          builder, loc, isStrideNeg, zero, dimOffset);
+      least = mlir::arith::AddIOp::create(builder, loc, least, addToLeast);
+      most = mlir::arith::AddIOp::create(builder, loc, most, addToMost);
+    }
+
+    mlir::Value eleSizeM1 =
+        mlir::arith::SubIOp::create(builder, loc, eleSize, one);
+    most = mlir::arith::AddIOp::create(builder, loc, most, eleSizeM1);
+
+    mlir::Value leastInt =
+        fir::ConvertOp::create(builder, loc, intPtrTy, least);
+    mlir::Value mostInt = fir::ConvertOp::create(builder, loc, intPtrTy, most);
+    mlir::Value rangeStart =
+        mlir::arith::AddIOp::create(builder, loc, baseInt, leastInt);
+    mlir::Value rangeEnd =
+        mlir::arith::AddIOp::create(builder, loc, baseInt, mostInt);
+    return {rangeStart, rangeEnd};
+  };
+
+  auto [lhsStart, lhsEnd] = computeRange(lhsRef);
+  auto [rhsStart, rhsEnd] = computeRange(rhsRef);
+  if (!lhsStart || !rhsStart)
+    return std::nullopt;
+
+  mlir::Value cond1 = mlir::arith::CmpIOp::create(
+      builder, loc, mlir::arith::CmpIPredicate::ult, lhsEnd, rhsStart);
+  mlir::Value cond2 = mlir::arith::CmpIOp::create(
+      builder, loc, mlir::arith::CmpIPredicate::ult, rhsEnd, lhsStart);
+  return mlir::arith::OrIOp::create(builder, loc, cond1, cond2);
+}
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
index 281c6f4d14ed0..44affd514f613 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
@@ -102,11 +102,9 @@ class InlineHLFIRAssignConversion
       return rewriter.notifyMatchFailure(assign,
                                          "RHS/LHS element types mismatch");
 
-    if (rhs.isArray() && !mlir::isa<hlfir::ExprType>(rhs.getType())) {
-      // If RHS is not an hlfir.expr, then we should prove that
-      // LHS and RHS do not alias.
-      // TODO: if they may alias, we can insert hlfir.as_expr for RHS,
-      // and proceed with the inlining.
+    bool rhsNeedsTemporary = false;
+    if (rhs.isArray() && !mlir::isa<hlfir::ExprType>(rhs.getType()) &&
+        !assign.getTemporaryLhs()) {
       fir::AliasAnalysis aliasAnalysis;
       mlir::AliasResult aliasRes = aliasAnalysis.alias(lhs, rhs);
       if (!aliasRes.isNo()) {
@@ -120,7 +118,14 @@ class InlineHLFIRAssignConversion
                                   << "\tLHS: " << lhs << "\n"
                                   << "\tRHS: " << rhs << "\n"
                                   << "\tALIAS: " << aliasRes << "\n");
-          return rewriter.notifyMatchFailure(assign, "RHS/LHS may alias");
+          // Overlap is Unknown: unsafe to read RHS while writing LHS
+          // without a temp. Call genIndexBasedDisjointnessCheck(..) or
+          // genAddressBasedDisjointnessCheck(..) to check if the slices are
+          // disjoint.
+          // 1. If disjoint -> direct element-wise copy (no temp).
+          // 2. If not disjoint -> allocate a temporary and copy RHS into it,
+          // then copy the temporary to LHS..
+          rhsNeedsTemporary = true;
         }
       }
     }
@@ -129,6 +134,58 @@ class InlineHLFIRAssignConversion
     fir::FirOpBuilder builder(rewriter, assign.getOperation());
     builder.setInsertionPoint(assign);
 
+    const bool useWorkshare = flangomp::shouldUseWorkshareLowering(assign);
+    mlir::ArrayAttr accessGroups;
+    if (auto attrs = assign.getOperation()->getAttrOfType<mlir::ArrayAttr>(
+            fir::getAccessGroupsAttrName()))
+      accessGroups = attrs;
+
+    auto emitAssignFrom = [&](hlfir::Entity rhsEntity) {
+      hlfir::genNoAliasArrayAssignment(
+          loc, builder, rhsEntity, lhs, useWorkshare,
+          /*temporaryLHS=*/false, nullptr, accessGroups);
+    };
+
+    if (rhsNeedsTemporary) {
+      std::optional<mlir::Value> disjoint =
+          fir::factory::genIndexBasedDisjointnessCheck(loc, builder, lhs, rhs);
+      if (!disjoint) {
+        disjoint = fir::factory::genAddressBasedDisjointnessCheck(loc, builder,
+                                                                  lhs, rhs);
+      }
+      if (!disjoint)
+        return rewriter.notifyMatchFailure(
+            assign, "Failed to generate runtime disjointness check,"
+                    "deferring to runtime assignment implementation");
+
+      builder.genIfThenElse(loc, *disjoint)
+          .genThen([&]() { emitAssignFrom(rhs); })
+          .genElse([&]() {
+            auto [temp, isHeapAlloc] =
+                hlfir::createTempFromMold(loc, builder, lhs);
+            hlfir::genNoAliasArrayAssignment(
+                loc, builder, rhs, temp, useWorkshare,
+                /*temporaryLHS=*/true, nullptr, accessGroups);
+            emitAssignFrom(temp);
+            if (isHeapAlloc) {
+              auto seqTy = mlir::cast<fir::SequenceType>(
+                  hlfir::getFortranElementOrSequenceType(lhs.getType()));
+              auto heapTy = fir::HeapType::get(seqTy);
+              mlir::Value heapAddr;
+              if (mlir::isa<fir::BaseBoxType>(temp.getType())) {
+                mlir::Value addr = fir::BoxAddrOp::create(builder, loc, temp);
+                heapAddr = fir::ConvertOp::create(builder, loc, heapTy, addr);
+              } else {
+                heapAddr = fir::ConvertOp::create(builder, loc, heapTy, temp);
+              }
+              fir::FreeMemOp::create(builder, loc, heapAddr);
+            }
+          })
+          .end();
+      rewriter.eraseOp(assign);
+      return mlir::success();
+    }
+
     // Materialize scalar RHS before the assignment loop. Fortran 10.2.1.3
     // requires that the RHS expression is fully evaluated before any part
     // of the LHS variable is defined. When the scalar RHS is a reference
@@ -137,13 +194,8 @@ class InlineHLFIRAssignConversion
     if (!rhs.isArray())
       rhs = hlfir::loadTrivialScalar(loc, builder, rhs);
 
-    mlir::ArrayAttr accessGroups;
-    if (auto attrs = assign.getOperation()->getAttrOfType<mlir::ArrayAttr>(
-            fir::getAccessGroupsAttrName()))
-      accessGroups = attrs;
-    hlfir::genNoAliasArrayAssignment(
-        loc, builder, rhs, lhs, flangomp::shouldUseWorkshareLowering(assign),
-        /*temporaryLHS=*/false, /*combiner=*/nullptr, accessGroups);
+    emitAssignFrom(rhs);
+
     rewriter.eraseOp(assign);
     return mlir::success();
   }
diff --git a/flang/test/HLFIR/inline-hlfir-assign-pointer-overlap.fir b/flang/test/HLFIR/inline-hlfir-assign-pointer-overlap.fir
new file mode 100644
index 0000000000000..1a44713fcb798
--- /dev/null
+++ b/flang/test/HLFIR/inline-hlfir-assign-pointer-overlap.fir
@@ -0,0 +1,140 @@
+// Test inlining of hlfir.assign for pointer-based array assignment
+
+// RUN: fir-opt --inline-hlfir-assign %s | FileCheck %s
+
+// Fortran source code:
+//  subroutine assign_pointers(arr, N, lo1, hi1, lo2, hi2)
+//    integer, intent(in)    :: N, lo1, hi1, lo2, hi2
+//    integer, pointer, intent(inout) :: arr(:)
+//    integer, pointer :: p1(:), p2(:)
+//
+//    p1 => arr(lo1:hi1)
+//    p2 => arr(lo2:hi2)
+//
+//    p1 = p2
+//  end subroutine assign_pointers
+
+// CHECK-LABEL: func.func @_QPassign_pointers
+
+// Address-based runtime disjointness check:
+// CHECK: %[[LHS_ADDR:.*]] = fir.box_addr %{{.*}} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.ptr<!fir.array<?xi32>>
+// CHECK: %[[LHS_BASE:.*]] = fir.convert %[[LHS_ADDR]] : (!fir.ptr<!fir.array<?xi32>>) -> i64
+// CHECK: fir.box_elesize %{{.*}} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> index
+// CHECK: fir.box_dims %{{.*}}, %{{.*}}
+// CHECK: arith.subi %{{.*}}, %{{.*}} : index
+// CHECK: arith.muli %{{.*}}, %{{.*}} : index
+// CHECK: arith.cmpi slt, %{{.*}}, %{{.*}} : index
+// CHECK: arith.select %{{.*}}, %{{.*}}, %{{.*}} : index
+// CHECK: arith.select %{{.*}}, %{{.*}}, %{{.*}} : index
+// CHECK: arith.subi %{{.*}}, %{{.*}} : index
+// CHECK: arith.addi %{{.*}}, %{{.*}} : index
+// CHECK: fir.convert %{{.*}} : (index) -> i64
+// CHECK: fir.convert %{{.*}} : (index) -> i64
+// CHECK: %[[LHS_START:.*]] = arith.addi %[[LHS_BASE]], %{{.*}} : i64
+// CHECK: %[[LHS_END:.*]] = arith.addi %[[LHS_BASE]], %{{.*}} : i64
+// CHECK: %[[RHS_ADDR:.*]] = fir.box_addr %{{.*}} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.ptr<!fir.array<?xi32>>
+// CHECK: %[[RHS_BASE:.*]] = fir.convert %[[RHS_ADDR]] : (!fir.ptr<!fir.array<?xi32>>) -> i64
+// CHECK: fir.box_elesize %{{.*}} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> index
+// CHECK: fir.box_dims %{{.*}}, %{{.*}}
+// CHECK: arith.subi %{{.*}}, %{{.*}} : index
+// CHECK: arith.muli %{{.*}}, %{{.*}} : index
+// CHECK: arith.cmpi slt, %{{.*}}, %{{.*}} : index
+// CHECK: arith.select %{{.*}}, %{{.*}}, %{{.*}} : index
+// CHECK: arith.select %{{.*}}, %{{.*}}, %{{.*}} : index
+// CHECK: arith.subi %{{.*}}, %{{.*}} : index
+// CHECK: arith.addi %{{.*}}, %{{.*}} : index
+// CHECK: fir.convert %{{.*}} : (index) -> i64
+// CHECK: fir.convert %{{.*}} : (index) -> i64
+// CHECK: %[[RHS_START:.*]] = arith.addi %[[RHS_BASE]], %{{.*}} : i64
+// CHECK: %[[RHS_END:.*]] = arith.addi %[[RHS_BASE]], %{{.*}} : i64
+// CHECK: %[[CMP1:.*]] = arith.cmpi ult, %[[LHS_END]], %[[RHS_START]] : i64
+// CHECK: %[[CMP2:.*]] = arith.cmpi ult, %[[RHS_END]], %[[LHS_START]] : i64
+// CHECK: %[[DISJOINT:.*]] = arith.ori %[[CMP1]], %[[CMP2]] : i1
+// CHECK: fir.if %[[DISJOINT]] {
+// CHECK:   fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered {
+// CHECK:     hlfir.designate
+// CHECK:     fir.load
+// CHECK:     hlfir.designate
+// CHECK:     hlfir.assign %{{.*}} to %{{.*}} : i32, !fir.ref<i32>
+// CHECK:   }
+// CHECK: } else {
+// CHECK:   %[[ALLOC:.*]] = fir.allocmem !fir.array<?xi32>, %{{.*}} {bindc_name = ".tmp", uniq_name = ""}
+// CHECK:   %[[TEMP:.*]]:2 = hlfir.declare %[[ALLOC]](%{{.*}}) {uniq_name = ".tmp"}
+// CHECK:   fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered {
+// CHECK:     hlfir.designate
+// CHECK:     fir.load
+// CHECK:     hlfir.designate %[[TEMP]]#0
+// CHECK:     hlfir.assign %{{.*}} to %{{.*}} temporary_lhs : i32, !fir.ref<i32>
+// CHECK:   }
+// CHECK:   fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered {
+// CHECK:     hlfir.designate %[[TEMP]]#0
+// CHECK:     fir.load
+// CHECK:     hlfir.designate
+// CHECK:     hlfir.assign %{{.*}} to %{{.*}} : i32, !fir.ref<i32>
+// CHECK:   }
+// CHECK:   fir.freemem %{{.*}}
+// CHECK: }
+
+func.func @_QPassign_pointers(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> {fir.bindc_name = "arr"}, %arg1: !fir.ref<i32> {fir.bindc_name = "n"}, %arg2: !fir.ref<i32> {fir.bindc_name = "lo1"}, %arg3: !fir.ref<i32> {fir.bindc_name = "hi1"}, %arg4: !fir.ref<i32> {fir.bindc_name = "lo2"}, %arg5: !fir.ref<i32> {fir.bindc_name = "hi2"}) {
+  %0 = fir.dummy_scope : !fir.dscope
+  %1:2 = hlfir.declare %arg0 dummy_scope %0 arg 1 {fortran_attrs = #fir.var_attrs<intent_inout, pointer>, uniq_name = "_QFassign_pointersEarr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %2:2 = hlfir.declare %arg3 dummy_scope %0 arg 4 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFassign_pointersEhi1"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %3:2 = hlfir.declare %arg5 dummy_scope %0 arg 6 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFassign_pointersEhi2"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %4:2 = hlfir.declare %arg2 dummy_scope %0 arg 3 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFassign_pointersElo1"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %5:2 = hlfir.declare %arg4 dummy_scope %0 arg 5 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFassign_pointersElo2"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %6:2 = hlfir.declare %arg1 dummy_scope %0 arg 2 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFassign_pointersEn"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %7 = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "p1", uniq_name = "_QFassign_pointersEp1"}
+  %8 = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+  %c0 = arith.constant 0 : index
+  %9 = fir.shape %c0 : (index) -> !fir.shape<1>
+  %10 = fir.embox %8(%9) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+  fir.store %10 to %7 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %11:2 = hlfir.declare %7 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFassign_pointersEp1"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>...
[truncated]

``````````

</details>


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


More information about the flang-commits mailing list