[flang-commits] [flang] [flang] Decouple HLFIR array expansion from optimization level (PR #233478)

via flang-commits flang-commits at lists.llvm.org
Mon Oct 19 09:54:12 PDT 2026


https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/233478

>From b68fd2b2035853df3c436ef35e128246165df029 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 19 Oct 2026 08:04:29 -0700
Subject: [PATCH 1/2] [flang] Decouple HLFIR array expansion from optimization
 level

Add useArrayRuntime to the pass pipeline configuration, preserving runtime use at O0 by default. Always attempt to inline scalar-to-array assignments, including host code at O0.

Update pipeline expectations and add coverage for broadcasts, array expressions, and reductions.
---
 flang/include/flang/Optimizer/HLFIR/Passes.td |  7 ++-
 flang/include/flang/Tools/CrossToolHelpers.h  |  5 ++
 flang/lib/Optimizer/Passes/Pipelines.cpp      | 32 ++++--------
 flang/test/Driver/array-runtime.f90           | 52 +++++++++++++++++++
 .../test/Driver/mlir-debug-pass-pipeline.f90  |  5 ++
 flang/test/Driver/mlir-omp-pass-pipeline.f90  |  6 +--
 flang/test/Driver/mlir-pass-pipeline.f90      | 10 ++--
 .../CUDA/scalar-to-array-assign-device-O0.cuf |  8 +--
 ...workdistribute-saxpy-and-scalar-assign.f90 | 17 +++---
 .../OpenMP/workdistribute-scalar-assign.f90   | 13 ++---
 10 files changed, 98 insertions(+), 57 deletions(-)
 create mode 100644 flang/test/Driver/array-runtime.f90

diff --git a/flang/include/flang/Optimizer/HLFIR/Passes.td b/flang/include/flang/Optimizer/HLFIR/Passes.td
index 2835b3119fa2f..1f5cb03f03159 100644
--- a/flang/include/flang/Optimizer/HLFIR/Passes.td
+++ b/flang/include/flang/Optimizer/HLFIR/Passes.td
@@ -103,13 +103,12 @@ def InlineHLFIRAssign : Pass<"inline-hlfir-assign"> {
                      /*default=*/"false",
                      "Only inline assignments where RHS is a numeric or "
                      "logical scalar broadcast "
-                     "to an array LHS. Used at O0 to avoid runtime calls in "
-                     "device code without inlining all array assignments.">,
+                     "to an array LHS, even when other array operations "
+                     "are left to the runtime.">,
                  Option<"onlyCUDADeviceContext", "only-cuda-device-context",
                         "bool", /*default=*/"false",
                         "Only inline assignments in CUDA Fortran device "
-                        "code. Used at O0, where a module holds both host "
-                        "and device subprograms, to leave host code alone.">];
+                        "code, leaving host code unchanged.">];
 }
 
 def InlineHLFIRCopy : Pass<"inline-hlfir-copy"> {
diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h
index b9add141663b9..d941aae37d6bd 100644
--- a/flang/include/flang/Tools/CrossToolHelpers.h
+++ b/flang/include/flang/Tools/CrossToolHelpers.h
@@ -114,11 +114,13 @@ class FlangEPCallBacks {
 struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
   explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level) {
     OptLevel = level;
+    useArrayRuntime = level == llvm::OptimizationLevel::O0;
   }
   explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level,
       const Fortran::frontend::CodeGenOptions &opts,
       const Fortran::common::MathOptionsBase &mathOpts) {
     OptLevel = level;
+    useArrayRuntime = level == llvm::OptimizationLevel::O0;
     StackArrays = opts.StackArrays;
     EnableSafeTrampoline = opts.EnableSafeTrampoline;
     Underscoring = opts.Underscoring;
@@ -151,6 +153,9 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
   }
 
   llvm::OptimizationLevel OptLevel; ///< optimisation level
+  /// Prefer runtime calls over inline expansion of HLFIR array operations.
+  /// Scalar-to-array assignments are still inlined when possible.
+  bool useArrayRuntime = true;
   bool StackArrays = false; ///< convert memory allocations to alloca.
   bool EnableSafeTrampoline{false}; ///< Use runtime trampoline pool (W^X).
   bool Underscoring = true; ///< add underscores to function names.
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index 953104d0625b7..3257080575289 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -292,7 +292,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
 
   config.invokeHLFIROptEarlyEPCallbacks(pm, optLevel);
 
-  if (optLevel != llvm::OptimizationLevel::O0) {
+  if (!config.useArrayRuntime) {
     addNestedPassToAllTopLevelOperations<PassConstructor>(
         pm, hlfir::createExpressionSimplification);
     addCanonicalizerPassWithoutRegionSimplification(pm);
@@ -305,7 +305,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
       pm, hlfir::createInlineElementals);
   addNestedPassToAllTopLevelOperations<PassConstructor>(
       pm, hlfir::createSeparateAllocatableAssign);
-  if (optLevel != llvm::OptimizationLevel::O0) {
+  if (!config.useArrayRuntime) {
     addCanonicalizerPassWithoutRegionSimplification(pm);
     pm.addPass(mlir::createCSEPass());
     // Run SimplifyHLFIRIntrinsics pass late after CSE,
@@ -325,40 +325,26 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
       addNestedPassToAllTopLevelOperations<PassConstructor>(
           pm, hlfir::createInlineHLFIRCopy);
     }
-  } else if (config.EnableOpenMPIsTargetDevice &&
-             enableOpenMP == EnableOpenMP::Full) {
-    // At O0, only inline scalar-to-array broadcasts when compiling for an
-    // OpenMP target device. This avoids emitting Fortran runtime calls
-    // (e.g. _FortranAAssign) that use malloc/free in device code generated
-    // by OpenMP target offloading. Restricting this to target-device
-    // compilation preserves the runtime call on the host at -O0 so that a
-    // line breakpoint on a scalar-to-array assignment hits once instead of
-    // once per element.
+  } else {
+    // Always attempt to inline scalar-to-array assignments, even when other
+    // array operations are left to the runtime.
     addNestedPassToAllTopLevelOperations(pm, [&]() {
       return hlfir::createInlineHLFIRAssign({/*onlyScalarRHS=*/true});
     });
-  } else if (config.EnableCUDA) {
-    // Same at O0 for CUDA Fortran device code, where the runtime call also
-    // inflates the stack frame the device linker reserves for the kernel.
-    // The module holds host code too, hence onlyCUDADeviceContext.
-    addNestedPassToAllTopLevelOperations(pm, [&]() {
-      return hlfir::createInlineHLFIRAssign(
-          {/*onlyScalarRHS=*/true, /*onlyCUDADeviceContext=*/true});
-    });
   }
   pm.addPass(hlfir::createLowerHLFIROrderedAssignments(
-      {/*tryFusingAssignments=*/optLevel != llvm::OptimizationLevel::O0}));
+      {/*tryFusingAssignments=*/!config.useArrayRuntime}));
 
   config.invokeHLFIROptLastEPCallbacks(pm, optLevel);
 
   pm.addPass(hlfir::createLowerHLFIRIntrinsics());
 
   hlfir::BufferizeHLFIROptions bufferizeOptions;
-  // For opt-for-speed, avoid running any of the loops resulting
+  // When expanding array operations, avoid running any of the loops resulting
   // from hlfir.elemental lowering, if the result is an empty array.
   // This helps to avoid long running loops for elementals with
   // shapes like (0, HUGE).
-  if (optLevel != llvm::OptimizationLevel::O0)
+  if (!config.useArrayRuntime)
     bufferizeOptions.optimizeEmptyElementals = true;
   pm.addPass(hlfir::createBufferizeHLFIR(bufferizeOptions));
   // Run hlfir.assign inlining again after BufferizeHLFIR,
@@ -368,7 +354,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
   // TODO: we can remove the previous InlineHLFIRAssign, when
   // FIR AliasAnalysis is good enough to say that a temporary
   // array does not alias with any user object.
-  if (optLevel != llvm::OptimizationLevel::O0)
+  if (!config.useArrayRuntime)
     addNestedPassToAllTopLevelOperations<PassConstructor>(
         pm, hlfir::createInlineHLFIRAssign);
   pm.addPass(hlfir::createConvertHLFIRtoFIR());
diff --git a/flang/test/Driver/array-runtime.f90 b/flang/test/Driver/array-runtime.f90
new file mode 100644
index 0000000000000..ddfc33d0190d5
--- /dev/null
+++ b/flang/test/Driver/array-runtime.f90
@@ -0,0 +1,52 @@
+! Scalar broadcasts are expanded even at -O0. Other array assignments and
+! intrinsics retain the optimization-level-dependent default.
+! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s --check-prefixes=ALL,RUNTIME
+! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s --check-prefixes=ALL,EXPAND
+
+subroutine broadcast(x)
+  real :: x(:)
+  x = 1.
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QPbroadcast(
+! ALL-NOT: fir.call @_FortranAAssign
+! ALL: fir.do_loop
+! ALL-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+subroutine array_copy(x, y)
+  real :: x(:), y(:)
+  x = y
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QParray_copy(
+! RUNTIME: fir.call @_FortranAAssign
+! EXPAND-NOT: fir.call @_FortranAAssign
+! EXPAND: fir.do_loop
+! EXPAND-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+subroutine array_expression(x, y, z)
+  real :: x(:), y(:), z(:)
+  x = y + z
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QParray_expression(
+! RUNTIME: fir.call @_FortranAAssign
+! EXPAND-NOT: fir.call @_FortranAAssign
+! EXPAND: fir.do_loop
+! EXPAND: arith.addf
+! EXPAND-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+function reduction(x)
+  real :: x(:), reduction
+  reduction = sum(x)
+end function
+
+! ALL-LABEL: func{{(\.func)?}} @_QPreduction(
+! RUNTIME: fir.call @_FortranASumReal4
+! EXPAND-NOT: fir.call @_FortranASum
+! EXPAND: fir.do_loop
+! EXPAND-NOT: fir.call @_FortranASum
+! ALL: return
diff --git a/flang/test/Driver/mlir-debug-pass-pipeline.f90 b/flang/test/Driver/mlir-debug-pass-pipeline.f90
index 1cc4fad4f76a4..25fdc4ee55780 100644
--- a/flang/test/Driver/mlir-debug-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-debug-pass-pipeline.f90
@@ -31,18 +31,23 @@
 ! ALL-NEXT: 'fir.global' Pipeline
 ! ALL-NEXT:   InlineElementals
 ! ALL-NEXT:   SeparateAllocatableAssign
+! ALL-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT: 'func.func' Pipeline
 ! ALL-NEXT:   InlineElementals
 ! ALL-NEXT:   SeparateAllocatableAssign
+! ALL-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT: 'omp.declare_mapper' Pipeline
 ! ALL-NEXT:   InlineElementals
 ! ALL-NEXT:   SeparateAllocatableAssign
+! ALL-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT: 'omp.declare_reduction' Pipeline
 ! ALL-NEXT:   InlineElementals
 ! ALL-NEXT:   SeparateAllocatableAssign
+! ALL-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT: 'omp.private' Pipeline
 ! ALL-NEXT:   InlineElementals
 ! ALL-NEXT:   SeparateAllocatableAssign
+! ALL-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT: LowerHLFIROrderedAssignments
 ! ALL-NEXT: LowerHLFIRIntrinsics
 ! ALL-NEXT: BufferizeHLFIR
diff --git a/flang/test/Driver/mlir-omp-pass-pipeline.f90 b/flang/test/Driver/mlir-omp-pass-pipeline.f90
index 40e2c52b993a4..01eb1ee739126 100644
--- a/flang/test/Driver/mlir-omp-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-omp-pass-pipeline.f90
@@ -14,7 +14,7 @@
 ! NO_OMP-NOT: AutomapToTargetDataPass
 ! NO_OMP-NOT: MapInfoFinalizationPass
 ! NO_OMP-NOT: GenericLoopConversionPass
-! NO_OMP-NOT: InlineHLFIRAssign
+! NO_OMP: InlineHLFIRAssign
 ! NO_OMP-NOT: LowerWorkshare
 ! NO_OMP-NOT: LowerWorkdistribute
 ! NO_OMP-NOT: SimdOnlyPass
@@ -30,7 +30,7 @@
 ! FULL: AutomapToTargetDataPass
 ! FULL: MapInfoFinalizationPass
 ! FULL: GenericLoopConversionPass
-! FULL-NOT: InlineHLFIRAssign
+! FULL: InlineHLFIRAssign
 ! FULL: LowerWorkshare
 ! FULL: LowerWorkdistribute
 ! FULL-NOT: SimdOnlyPass
@@ -47,7 +47,7 @@
 ! SIMD-NOT: AutomapToTargetDataPass
 ! SIMD-NOT: MapInfoFinalizationPass
 ! SIMD-NOT: GenericLoopConversionPass
-! SIMD-NOT: InlineHLFIRAssign
+! SIMD: InlineHLFIRAssign
 ! SIMD-NOT: LowerWorkshare
 ! SIMD-NOT: LowerWorkdistribute
 ! SIMD: SimdOnlyPass
diff --git a/flang/test/Driver/mlir-pass-pipeline.f90 b/flang/test/Driver/mlir-pass-pipeline.f90
index f7f4a29ab2de9..d91d0e0177bf3 100644
--- a/flang/test/Driver/mlir-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-pass-pipeline.f90
@@ -9,11 +9,6 @@
 
 end program
 
-! At -O0 on the host (no OpenMP target-device compilation), InlineHLFIRAssign
-! is no longer scheduled. See PR #197092 follow-up restricting the -O0 pass
-! to OpenMP target-device compilation.
-! O0-NOT: InlineHLFIRAssign
-
 ! ALL: Pass statistics report
 ! ALL: Fortran::lower::VerifierPass
 
@@ -37,22 +32,27 @@
 ! O2-NEXT:   SimplifyHLFIRIntrinsics
 ! ALL:       InlineElementals
 ! ALL-NEXT:  SeparateAllocatableAssign
+! O0-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT:'func.func' Pipeline
 ! O2-NEXT:   SimplifyHLFIRIntrinsics
 ! ALL:       InlineElementals
 ! ALL-NEXT:  SeparateAllocatableAssign
+! O0-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT:'omp.declare_mapper' Pipeline
 ! O2-NEXT:   SimplifyHLFIRIntrinsics
 ! ALL:       InlineElementals
 ! ALL-NEXT:  SeparateAllocatableAssign
+! O0-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT:'omp.declare_reduction' Pipeline
 ! O2-NEXT:   SimplifyHLFIRIntrinsics
 ! ALL:       InlineElementals
 ! ALL-NEXT:  SeparateAllocatableAssign
+! O0-NEXT:   InlineHLFIRAssign
 ! ALL-NEXT:'omp.private' Pipeline
 ! O2-NEXT:   SimplifyHLFIRIntrinsics
 ! ALL:       InlineElementals
 ! ALL-NEXT:  SeparateAllocatableAssign
+! O0-NEXT:   InlineHLFIRAssign
 ! O2-NEXT: Canonicalizer
 ! O2-NEXT: CSE
 ! O2-NEXT: (S) {{.*}} num-cse'd
diff --git a/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf b/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
index 7fa6291b93f33..ad9ded3ff81b7 100644
--- a/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
+++ b/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
@@ -1,6 +1,6 @@
 ! At -O0, a scalar-to-array broadcast must be inlined in device code to keep
-! _FortranAAssign out of the kernel's call graph. Host code keeps the call so
-! that a breakpoint on the assignment fires once, not once per element.
+! _FortranAAssign out of the kernel's call graph. Host code also inlines
+! scalar-to-array broadcasts.
 ! CUDA Fortran is enabled here by the .cuf suffix rather than -x cuda.
 
 ! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s
@@ -41,4 +41,6 @@ end module
 ! CHECK-NOT:     fir.call @_FortranAAssign
 
 ! CHECK-LABEL: func.func @_QMmPhost_broadcast
-! CHECK:         fir.call @_FortranAAssign
+! CHECK-NOT:     fir.call @_FortranAAssign
+! CHECK:         fir.do_loop
+! CHECK-NOT:     fir.call @_FortranAAssign
diff --git a/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90 b/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
index 09e3375efa487..8e005ddd9dea1 100644
--- a/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
+++ b/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
@@ -60,20 +60,15 @@ subroutine teams_workdistribute()
   !$omp end teams workdistribute
 end subroutine teams_workdistribute
 
-! At -O0 host (no -fopenmp-is-target-device):
-!   - target teams workdistribute inlines both the saxpy and the scalar
-!     broadcast via workdistributeRuntimeCallLower, so no _FortranAAssign
-!     runtime call appears.
-!   - teams workdistribute (no target) keeps the saxpy result write-back
-!     and the scalar broadcast as _FortranAAssign runtime calls. The
-!     two calls correspond to source lines 50 (saxpy) and 58 (scalar
-!     broadcast) respectively; the ordered CHECK-O0 lines below match
-!     each region in source order so neither expectation can accidentally
-!     match the other assignment.
+! At -O0, target teams workdistribute expands both assignments. On the host,
+! the saxpy result write-back still uses the runtime, but the scalar broadcast
+! is inlined and workshared.
 ! CHECK-O0-LABEL: func @_QPtarget_teams_workdistribute
 ! CHECK-O0-NOT: fir.call @_FortranAAssign
 
 ! CHECK-O0-LABEL: func @_QPteams_workdistribute
 ! CHECK-O0: omp.wsloop
 ! CHECK-O0: fir.call @_FortranAAssignSimple({{.*}}%c50_i32)
-! CHECK-O0: fir.call @_FortranAAssign({{.*}}%c58_i32)
+! CHECK-O0-NOT: fir.call @_FortranAAssign
+! CHECK-O0: omp.wsloop
+! CHECK-O0-NOT: fir.call @_FortranAAssign
diff --git a/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90 b/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
index 68c9060ee9bd6..ccc5f13bbe67b 100644
--- a/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
+++ b/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
@@ -35,16 +35,13 @@ subroutine teams_workdistribute_scalar_assign()
 
 end subroutine teams_workdistribute_scalar_assign
 
-! At -O0 host (no -fopenmp-is-target-device), target teams workdistribute
-! still goes through workdistributeRuntimeCallLower, so the scalar
-! broadcast inside the target region is inlined and workshared, with no
-! _FortranAAssign runtime call.
+! At -O0, scalar broadcasts are inlined and workshared on both host and device.
 ! CHECK-O0-LABEL: func @_QPtarget_teams_workdistribute_scalar_assign
+! CHECK-O0-NOT: fir.call @_FortranAAssign
 ! CHECK-O0: omp.wsloop
 ! CHECK-O0-NOT: fir.call @_FortranAAssign
 
-! At -O0 host, teams workdistribute (no target) does not inline the
-! scalar broadcast after PR #201774, so the assignment remains a
-! _FortranAAssign runtime call. This pins the plain host -O0 behavior.
 ! CHECK-O0-LABEL: func @_QPteams_workdistribute_scalar_assign
-! CHECK-O0: fir.call @_FortranAAssign
+! CHECK-O0-NOT: fir.call @_FortranAAssign
+! CHECK-O0: omp.wsloop
+! CHECK-O0-NOT: fir.call @_FortranAAssign

>From 63f0bd44ed5c9df99b706d2d83663756a5c364d7 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 19 Oct 2026 09:53:47 -0700
Subject: [PATCH 2/2] test updates

---
 .../parallel-private-reduction-worstcase.f90  | 96 ++++++++++++-------
 .../Integration/OpenMP/private-global.f90     | 16 ++--
 flang/test/Integration/prefetch.f90           |  1 -
 .../Lower/scalar-to-array-assign-host-O0.f90  | 22 +++--
 4 files changed, 79 insertions(+), 56 deletions(-)

diff --git a/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90 b/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
index ea52c2a2b5bb8..4f86c590b7e95 100644
--- a/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
+++ b/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
@@ -117,44 +117,62 @@ subroutine worst_case(a, b, c, d)
 !                [malloc and assign the default value to the reduction variable]
 ! CHECK:         br label %omp.reduction.neutral46
 
-! CHECK:       omp.reduction.neutral46:                          ; preds = %omp.reduction.neutral44, %omp.reduction.neutral45
+! CHECK:       omp.reduction.neutral46:                          ; preds = %omp.reduction.neutral47, %omp.reduction.neutral45
+!                [loop assigning the neutral value to each element]
+! CHECK-NEXT:    %{{.*}} = phi i64
+! CHECK-NEXT:    %{{.*}} = phi i64
+! CHECK:         br i1 %{{.*}}, label %omp.reduction.neutral47, label %omp.reduction.neutral48
+
+! CHECK:       omp.reduction.neutral48:                          ; preds = %omp.reduction.neutral46
+! CHECK:         br label %omp.reduction.neutral49
+
+! CHECK:       omp.reduction.neutral49:                          ; preds = %omp.reduction.neutral44, %omp.reduction.neutral48
 ! CHECK-NEXT:    br label %omp.region.cont43
 
-! CHECK:       omp.region.cont43:                                ; preds = %omp.reduction.neutral46
+! CHECK:       omp.region.cont43:                                ; preds = %omp.reduction.neutral49
 ! CHECK-NEXT:    %{{.*}} = phi ptr
-! CHECK-NEXT:    br label %omp.reduction.neutral48
+! CHECK-NEXT:    br label %omp.reduction.neutral51
 
-! CHECK:       omp.reduction.neutral48:                          ; preds = %omp.region.cont43
+! CHECK:       omp.reduction.neutral51:                          ; preds = %omp.region.cont43
 !                [start of reduction initialization region]
 !                [null check:]
-! CHECK:         br i1 %{{.*}}, label %omp.reduction.neutral49, label %omp.reduction.neutral50
+! CHECK:         br i1 %{{.*}}, label %omp.reduction.neutral52, label %omp.reduction.neutral53
 
-! CHECK:       omp.reduction.neutral50:                          ; preds = %omp.reduction.neutral48
+! CHECK:       omp.reduction.neutral53:                          ; preds = %omp.reduction.neutral51
 !                [malloc and assign the default value to the reduction variable]
-! CHECK:         br label %omp.reduction.neutral51
+! CHECK:         br label %omp.reduction.neutral54
+
+! CHECK:       omp.reduction.neutral54:                          ; preds = %omp.reduction.neutral55, %omp.reduction.neutral53
+!                [loop assigning the neutral value to each element]
+! CHECK-NEXT:    %{{.*}} = phi i64
+! CHECK-NEXT:    %{{.*}} = phi i64
+! CHECK:         br i1 %{{.*}}, label %omp.reduction.neutral55, label %omp.reduction.neutral56
+
+! CHECK:       omp.reduction.neutral56:                          ; preds = %omp.reduction.neutral54
+! CHECK:         br label %omp.reduction.neutral57
 
-! CHECK:       omp.reduction.neutral51:                          ; preds = %omp.reduction.neutral49, %omp.reduction.neutral50
-! CHECK-NEXT:    br label %omp.region.cont47
+! CHECK:       omp.reduction.neutral57:                          ; preds = %omp.reduction.neutral52, %omp.reduction.neutral56
+! CHECK-NEXT:    br label %omp.region.cont50
 
-! CHECK:       omp.region.cont47:                                ; preds = %omp.reduction.neutral51
+! CHECK:       omp.region.cont50:                                ; preds = %omp.reduction.neutral57
 ! CHECK-NEXT:    %{{.*}} = phi ptr
-! CHECK-NEXT:    br label %omp.par.region53
+! CHECK-NEXT:    br label %omp.par.region59
 
-! CHECK:       omp.par.region53:                                 ; preds = %omp.region.cont47
-! CHECK-NEXT:    br label %omp.par.region54
+! CHECK:       omp.par.region59:                                 ; preds = %omp.region.cont50
+! CHECK-NEXT:    br label %omp.par.region60
 
-! CHECK:       omp.par.region54:                                 ; preds = %omp.par.region53
+! CHECK:       omp.par.region60:                                 ; preds = %omp.par.region59
 !                [call SUM runtime function]
 !                [if (sum(a) == 1)]
-! CHECK:         br i1 %{{.*}}, label %omp.par.region55, label %omp.par.region56
+! CHECK:         br i1 %{{.*}}, label %omp.par.region61, label %omp.par.region62
 
-! CHECK:       omp.par.region56:                                 ; preds = %omp.par.region54
-! CHECK-NEXT:    br label %omp.par.region57
+! CHECK:       omp.par.region62:                                 ; preds = %omp.par.region60
+! CHECK-NEXT:    br label %omp.par.region63
 
-! CHECK:       omp.par.region57:                                 ; preds = %omp.par.region56
-! CHECK-NEXT:    br label %omp.region.cont52
+! CHECK:       omp.par.region63:                                 ; preds = %omp.par.region62
+! CHECK-NEXT:    br label %omp.region.cont58
 
-! CHECK:       omp.region.cont52:                                ; preds = %omp.par.region57
+! CHECK:       omp.region.cont58:                                ; preds = %omp.par.region63
 !                [omp parallel region done, call into the runtime to complete reduction]
 ! CHECK:         %[[VAL_233:.*]] = call i32 @__kmpc_reduce(
 ! CHECK:         switch i32 %[[VAL_233]], label %reduce.finalize [
@@ -162,16 +180,16 @@ subroutine worst_case(a, b, c, d)
 ! CHECK-NEXT:      i32 2, label %reduce.switch.atomic
 ! CHECK-NEXT:    ]
 
-! CHECK:       reduce.switch.atomic:                             ; preds = %omp.region.cont52
+! CHECK:       reduce.switch.atomic:                             ; preds = %omp.region.cont58
 ! CHECK-NEXT:    unreachable
 
-! CHECK:       reduce.switch.nonatomic:                          ; preds = %omp.region.cont52
+! CHECK:       reduce.switch.nonatomic:                          ; preds = %omp.region.cont58
 ! CHECK-NEXT:    %[[red_private_value_0:.*]] = load ptr, ptr %{{.*}}, align 8
 ! CHECK-NEXT:    br label %omp.reduction.nonatomic.body
 
 !              [various blocks implementing the reduction]
 
-! CHECK:       omp.region.cont62:                                ; preds =
+! CHECK:       omp.region.cont68:                                ; preds =
 ! CHECK-NEXT:    %{{.*}} = phi ptr
 ! CHECK-NEXT:    call void @__kmpc_end_reduce(
 ! CHECK-NEXT:    br label %reduce.finalize
@@ -188,30 +206,38 @@ subroutine worst_case(a, b, c, d)
 
 ! CHECK:       omp.reduction.cleanup:                            ; preds = %.fini
 !                [null check]
-! CHECK:         br i1 %{{.*}}, label %omp.reduction.cleanup68, label %omp.reduction.cleanup69
+! CHECK:         br i1 %{{.*}}, label %omp.reduction.cleanup74, label %omp.reduction.cleanup75
 
-! CHECK:       omp.reduction.cleanup69:                          ; preds = %omp.reduction.cleanup68, %omp.reduction.cleanup
-! CHECK-NEXT:    br label %omp.region.cont67
+! CHECK:       omp.reduction.cleanup75:                          ; preds = %omp.reduction.cleanup74, %omp.reduction.cleanup
+! CHECK-NEXT:    br label %omp.region.cont73
 
-! CHECK:       omp.region.cont67:                                ; preds = %omp.reduction.cleanup69
+! CHECK:       omp.region.cont73:                                ; preds = %omp.reduction.cleanup75
 ! CHECK-NEXT:    %{{.*}} = load ptr, ptr
-! CHECK-NEXT:    br label %omp.reduction.cleanup71
+! CHECK-NEXT:    br label %omp.reduction.cleanup77
 
-! CHECK:       omp.reduction.cleanup71:                          ; preds = %omp.region.cont67
+! CHECK:       omp.reduction.cleanup77:                          ; preds = %omp.region.cont73
 !                [null check]
-! CHECK:         br i1 %{{.*}}, label %omp.reduction.cleanup72, label %omp.reduction.cleanup73
+! CHECK:         br i1 %{{.*}}, label %omp.reduction.cleanup78, label %omp.reduction.cleanup79
 
-! CHECK:       omp.par.region55:                                 ; preds = %omp.par.region54
+! CHECK:       omp.par.region61:                                 ; preds = %omp.par.region60
 ! CHECK-NEXT:    call void @_FortranAStopStatement
 ! CHECK-NEXT:    unreachable
 
-! CHECK:       omp.reduction.neutral49:                          ; preds = %omp.reduction.neutral48
+! CHECK:       omp.reduction.neutral55:                          ; preds = %omp.reduction.neutral54
+! CHECK:         store float 0.000000e+00, ptr %{{.*}}, align 4
+! CHECK:         br label %omp.reduction.neutral54
+
+! CHECK:       omp.reduction.neutral52:                          ; preds = %omp.reduction.neutral51
 !                [source length was zero: finish initializing array]
-! CHECK:         br label %omp.reduction.neutral51
+! CHECK:         br label %omp.reduction.neutral57
+
+! CHECK:       omp.reduction.neutral47:                          ; preds = %omp.reduction.neutral46
+! CHECK:         store float 0.000000e+00, ptr %{{.*}}, align 4
+! CHECK:         br label %omp.reduction.neutral46
 
 ! CHECK:       omp.reduction.neutral44:                          ; preds = %omp.reduction.neutral
 !                [source length was zero: finish initializing array]
-! CHECK:         br label %omp.reduction.neutral46
+! CHECK:         br label %omp.reduction.neutral49
 
 ! CHECK:       omp.private.copy41:                               ; preds = %omp.private.copy40, %omp.private.copy37
 !                [source length was non-zero: call assign runtime]
@@ -247,5 +273,5 @@ subroutine worst_case(a, b, c, d)
 !                [var extent was non-zero: malloc a private array]
 ! CHECK:         br label %omp.private.init5
 
-! CHECK:       omp.par.exit.exitStub:                           ; preds = %omp.region.cont77
+! CHECK:       omp.par.exit.exitStub:                           ; preds = %omp.region.cont83
 ! CHECK-NEXT:    ret void
diff --git a/flang/test/Integration/OpenMP/private-global.f90 b/flang/test/Integration/OpenMP/private-global.f90
index 56310a3ca21a4..2d1e63eefd8ca 100644
--- a/flang/test/Integration/OpenMP/private-global.f90
+++ b/flang/test/Integration/OpenMP/private-global.f90
@@ -22,17 +22,13 @@ program bug
 ! and no heap allocation for the private itself.
 ! CHECK:         %[[PRIV_TABLE:.*]] = alloca [10 x i32], align 4
 
-! check that we use the private copy of table for the assignment: its data
-! pointer is placed in a descriptor which -- threaded through the store and
-! memcpy below -- is the destination handed to the runtime assign.
-! CHECK:       omp.par.region1:
-! CHECK:         %[[TABLE_DESC:.*]] = insertvalue {{.*}}, ptr %[[PRIV_TABLE]], 0
-! CHECK:         store {{.*}} %[[TABLE_DESC]], ptr %[[DESC_MEM:.*]], align
-! CHECK:         call void @llvm.memcpy.p0.p0.i32(ptr %[[ASSIGN_DST:.*]], ptr %[[DESC_MEM]], i32 {{.*}}, i1 false)
-! CHECK:         call void @_FortranAAssign(ptr %[[ASSIGN_DST]],
-
 ! check that we use the private copy of table for table/=50
-! CHECK:       omp.par.region3:
+! CHECK:       omp.par.region7:
 ! CHECK:         %[[ELT_PTR:.*]] = getelementptr {{.*}} i32, ptr %[[PRIV_TABLE]], i64 %{{.*}}
 ! CHECK:         %[[ELT:.*]] = load i32, ptr %[[ELT_PTR]]
 ! CHECK:         icmp ne i32 %[[ELT]], 50
+
+! check that the inline assignment loop stores into the private copy of table
+! CHECK:       omp.par.region3:
+! CHECK:         %[[ASSIGN_ELT_PTR:.*]] = getelementptr {{.*}} i32, ptr %[[PRIV_TABLE]], i64 %{{.*}}
+! CHECK-NEXT:    store i32 50, ptr %[[ASSIGN_ELT_PTR]], align 4
diff --git a/flang/test/Integration/prefetch.f90 b/flang/test/Integration/prefetch.f90
index c015b6736972a..76227caf02b43 100644
--- a/flang/test/Integration/prefetch.f90
+++ b/flang/test/Integration/prefetch.f90
@@ -13,7 +13,6 @@
 !===============================================================================
 
 subroutine test_prefetch_01()
-    ! LLVM: {{.*}} = alloca i32, i64 1, align 4
     ! LLVM: %[[VAR_J:.*]] = alloca i32, i64 1, align 4
     ! LLVM: %[[VAR_I:.*]] = alloca i32, i64 1, align 4
     ! LLVM: %[[VAR_A:.*]] = alloca [256 x i32], i64 1, align 4
diff --git a/flang/test/Lower/scalar-to-array-assign-host-O0.f90 b/flang/test/Lower/scalar-to-array-assign-host-O0.f90
index 88d4344da6f2b..a7a40af6b5367 100644
--- a/flang/test/Lower/scalar-to-array-assign-host-O0.f90
+++ b/flang/test/Lower/scalar-to-array-assign-host-O0.f90
@@ -1,17 +1,19 @@
-! Regression test for the follow-up to PR llvm/llvm-project#197092.
-!
-! At -O0 on the host (no OpenMP target-device compilation), a scalar-to-array
-! broadcast assignment must lower to a Fortran runtime call
-! (_FortranAAssign), not to an inline assignment loop. Lowering it inline
-! at -O0 caused -g line breakpoints to hit once per array element instead
-! of once.
+! Scalar-to-array broadcast assignments are expanded inline even at -O0
+! on the host (no OpenMP target-device compilation).
 
-! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s --implicit-check-not=_FortranAAssign
 
 ! CHECK-LABEL: func @_QPhost_scalar_broadcast
 subroutine host_scalar_broadcast(arr)
   integer :: arr(4)
-  ! CHECK: fir.call @_FortranAAssign
-  ! CHECK-NOT: fir.do_loop
+  ! CHECK-DAG: %[[ONE:.*]] = arith.constant 1 : index
+  ! CHECK-DAG: %[[VALUE:.*]] = arith.constant 11 : i32
+  ! CHECK-DAG: %[[EXTENT:.*]] = arith.constant 4 : index
+  ! CHECK: %[[SHAPE:.*]] = fir.shape %[[EXTENT]]
+  ! CHECK: %[[ARR:.*]] = fir.declare %arg0(%[[SHAPE]])
+  ! CHECK: fir.do_loop %[[INDEX:.*]] = %[[ONE]] to %[[EXTENT]] step %[[ONE]] unordered {
+  ! CHECK-NEXT: %[[ELEMENT:.*]] = fir.array_coor %[[ARR]](%[[SHAPE]]) %[[INDEX]]
+  ! CHECK-NEXT: fir.store %[[VALUE]] to %[[ELEMENT]] : !fir.ref<i32>
+  ! CHECK-NEXT: }
   arr = 11
 end subroutine



More information about the flang-commits mailing list