[flang-commits] [flang] [llvm] [flang][OpenMP] Inline the firstprivate array copy instead of calling Assign() (PR #211543)

Spencer Bryngelson via flang-commits flang-commits at lists.llvm.org
Thu Jul 23 05:59:27 PDT 2026


https://github.com/sbryngelson created https://github.com/llvm/llvm-project/pull/211543

The copy region of an `omp.private` firstprivate privatizer holds an `hlfir.assign` from the original host variable to the privatized clone:

```mlir
omp.private {type = firstprivate} @_QFkEc_firstprivate_box_1xf64 : !fir.box<!fir.array<1xf64>> init {
  ...
} copy {
^bb0(%arg0: !fir.ref<!fir.box<!fir.array<1xf64>>>, %arg1: !fir.ref<!fir.box<!fir.array<1xf64>>>):
  %0 = fir.load %arg0 : !fir.ref<!fir.box<!fir.array<1xf64>>>
  hlfir.assign %0 to %arg1 : !fir.box<!fir.array<1xf64>>, !fir.ref<!fir.box<!fir.array<1xf64>>>
  omp.yield(%arg1 : !fir.ref<!fir.box<!fir.array<1xf64>>>)
}
```

`InlineHLFIRAssign` declines to expand it: both sides are block arguments, `fir::AliasAnalysis` reports `MayAlias`, and `ArraySectionAnalyzer` returns `Unknown`. The assignment therefore lowers to a `_FortranAAssign` runtime call.

That call is not available in device code. This does not link today:

```fortran
subroutine k(a, b, n, c)
  real(8), intent(in)    :: a(*)
  real(8), intent(inout) :: b(*)
  integer, intent(in)    :: n
  real(8), intent(in)    :: c(1)
  integer :: i
  !$omp target teams distribute parallel do firstprivate(c)
  do i = 1, n
     b(i) = a(i) * c(1)
  end do
end subroutine
```

```
$ flang -fopenmp --offload-arch=gfx90a -O3 t.f90
ld.lld: error: undefined symbol: _FortranAAssign
```

Eight bytes of data, and it needs the runtime.

The op already documents the invariant that makes the aliasing question moot — from `OpenMPOps.td`:

> `%arg0` is the original host variable. `%arg1` represents the memory allocated for this private variable.

The clone is fresh memory allocated by the init region, so it cannot overlap the original. This patch skips the aliasing check for an assignment in a copy region whose LHS is that clone block argument, and the existing inlining then produces a plain element loop.

Alias analysis is not the right place for it: classifying `%arg1` as `SourceKind::Allocate` describes the *descriptor*, not the data it points at, so the query still comes back `MayAlias`. Proving the data is fresh means reasoning from the copy region into the init region.

An assignment in the copy region that does not write the clone keeps its aliasing check; there is a test for that.

### Results

gfx90a, one-element `real(8)` array, upstream at `02c51adb8ff2`:

| | before | after |
|---|---|---|
| offload link | `undefined symbol: _FortranAAssign` | links |
| `_FortranAAssign` in device IR | 3 (1 decl, 2 calls) | 0 |
| ScratchSize, device compile | 208 B/lane | 112 B/lane |
| result on MI210 | does not link | `2.0`, correct |

`ninja check-flang` is clean: 4602 passed, 11 expected failures, 190 unsupported, no failures.

The kernel still reports `Dynamic Stack: True` after this change. That is #211132, the un-inlined device-outlined target region, not this.

Fixes #203890. The downstream report is ROCm/llvm-project#2909, where the same runtime call shows up as a ~35 KB/lane spill and an occupancy collapse rather than a link failure. I have only verified the upstream half here — I cannot rebuild the AFAR drop that report is against.


>From 79d556654ac3a825921909ba589a177908c272c4 Mon Sep 17 00:00:00 2001
From: Spencer Bryngelson <sbryngelson at gmail.com>
Date: Thu, 23 Jul 2026 07:58:52 -0500
Subject: [PATCH] [flang][OpenMP] Inline the firstprivate array copy instead of
 calling Assign()

The copy region of an `omp.private` firstprivate privatizer holds an
`hlfir.assign` from the original host variable to the privatized clone.
`InlineHLFIRAssign` declines to expand it because both sides are block
arguments, so alias analysis cannot prove the two do not overlap, and the
assignment falls back to a `_FortranAAssign` runtime call.

That call is unusable in device code. Compiling a `target` region with a
`firstprivate` fixed-size array for `amdgcn-amd-amdhsa` fails to link:

  ld.lld: error: undefined symbol: _FortranAAssign

The operation already defines the two copy-region block arguments to be the
original host variable and the memory allocated for the clone, so they cannot
overlap. Skip the aliasing check for an assignment that writes the clone, and
the existing inlining produces a plain element loop.

For a one-element `real(8)` array on gfx90a this removes both
`_FortranAAssign` calls from the device IR, drops the device compile's
ScratchSize from 208 to 112 bytes/lane, and the program links and returns the
correct result on an MI210.

An assignment in the copy region that does not write the clone keeps its
aliasing check.

Fixes #203890.
---
 cmake.log                                     | 334 ++++++++++++++++++
 .../HLFIR/Transforms/InlineHLFIRAssign.cpp    |  19 +-
 flang/test/HLFIR/inline-hlfir-assign.fir      |  34 ++
 3 files changed, 386 insertions(+), 1 deletion(-)
 create mode 100644 cmake.log

diff --git a/cmake.log b/cmake.log
new file mode 100644
index 0000000000000..4b21216ad06f5
--- /dev/null
+++ b/cmake.log
@@ -0,0 +1,334 @@
+CMake Warning at CMakeLists.txt:4 (message):
+  Your CMake version is 3.25.2.  Starting with LLVM 24, the minimum version
+  of CMake required to build LLVM will become 3.31.0, and using an older
+  CMake will become an error.  Please upgrade your CMake to at least 3.31.0
+  now to avoid issues in the future.
+
+
+-- The C compiler identification is GNU 12.2.0
+-- The CXX compiler identification is GNU 12.2.0
+-- The ASM compiler identification is GNU
+-- Found assembler: /opt/ohpc/pub/compiler/gcc/12.2.0/bin/gcc
+-- Detecting C compiler ABI info
+-- Detecting C compiler ABI info - done
+-- Check for working C compiler: /opt/ohpc/pub/compiler/gcc/12.2.0/bin/gcc - skipped
+-- Detecting C compile features
+-- Detecting C compile features - done
+-- Detecting CXX compiler ABI info
+-- Detecting CXX compiler ABI info - done
+-- Check for working CXX compiler: /opt/ohpc/pub/compiler/gcc/12.2.0/bin/g++ - skipped
+-- Detecting CXX compile features
+-- Detecting CXX compile features - done
+-- Enabling Flang-RT as a dependency of Flang
+-- bolt project is disabled
+-- clang project is enabled
+-- clang-tools-extra project is disabled
+-- cross-project-tests project is disabled
+-- lld project is disabled
+-- lldb project is disabled
+-- mlir project is enabled
+-- polly project is disabled
+-- flang project is enabled
+-- libc project is disabled
+-- compiler-rt project is disabled
+-- Doxygen disabled.
+-- Found Python3: /usr/bin/python3.12 (found suitable version "3.12.12", minimum required is "3.8") found components: Interpreter 
+-- Looking for __GLIBC__
+-- Looking for __GLIBC__ - found
+-- Looking for valgrind/valgrind.h
+-- Looking for valgrind/valgrind.h - found
+-- Looking for FE_ALL_EXCEPT
+-- Looking for FE_ALL_EXCEPT - found
+-- Looking for FE_INEXACT
+-- Looking for FE_INEXACT - found
+-- Performing Test HAVE_BUILTIN_THREAD_POINTER
+-- Performing Test HAVE_BUILTIN_THREAD_POINTER - Success
+-- Looking for CrashReporterClient.h
+-- Looking for CrashReporterClient.h - not found
+-- Looking for linux/magic.h
+-- Looking for linux/magic.h - found
+-- Looking for pthread_create in pthread
+-- Looking for pthread_create in pthread - found
+-- Looking for pthread_rwlock_init in pthread
+-- Looking for pthread_rwlock_init in pthread - found
+-- Looking for pthread_mutex_lock in pthread
+-- Looking for pthread_mutex_lock in pthread - found
+-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
+-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
+-- Found Threads: TRUE  
+-- Looking for dlopen in dl
+-- Looking for dlopen in dl - found
+-- Looking for shm_open in rt
+-- Looking for shm_open in rt - found
+-- Looking for pfm_initialize in pfm
+-- Looking for pfm_initialize in pfm - not found
+-- Found ZLIB: /usr/lib64/libz.so (found version "1.2.11") 
+-- Looking for compress2
+-- Looking for compress2 - found
+-- Found LibXml2: /usr/lib64/libxml2.so (found version "2.9.13") 
+-- Looking for xmlReadMemory
+-- Looking for xmlReadMemory - found
+-- Could NOT find LibEdit (missing: LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES) 
+-- Looking for arc4random
+-- Looking for arc4random - not found
+-- Looking for backtrace
+-- Looking for backtrace - found
+-- backtrace facility detected in default set of libraries
+-- Found Backtrace: /usr/include  
+-- Performing Test C_SUPPORTS_WERROR_UNGUARDED_AVAILABILITY_NEW
+-- Performing Test C_SUPPORTS_WERROR_UNGUARDED_AVAILABILITY_NEW - Failed
+-- Looking for __register_frame
+-- Looking for __register_frame - found
+-- Looking for __deregister_frame
+-- Looking for __deregister_frame - found
+-- Looking for __unw_add_dynamic_fde
+-- Looking for __unw_add_dynamic_fde - not found
+-- Looking for _Unwind_Backtrace
+-- Looking for _Unwind_Backtrace - found
+-- Looking for getpagesize
+-- Looking for getpagesize - found
+-- Looking for sysconf
+-- Looking for sysconf - found
+-- Looking for getrusage
+-- Looking for getrusage - found
+-- Looking for isatty
+-- Looking for isatty - found
+-- Looking for futimens
+-- Looking for futimens - found
+-- Looking for futimes
+-- Looking for futimes - found
+-- Looking for getauxval
+-- Looking for getauxval - found
+-- Looking for sigaltstack
+-- Looking for sigaltstack - found
+-- Looking for mallctl
+-- Looking for mallctl - not found
+-- Looking for mallinfo
+-- Looking for mallinfo - found
+-- Looking for mallinfo2
+-- Looking for mallinfo2 - found
+-- Looking for malloc_zone_statistics
+-- Looking for malloc_zone_statistics - not found
+-- Looking for posix_spawn
+-- Looking for posix_spawn - found
+-- Looking for pread
+-- Looking for pread - found
+-- Looking for sbrk
+-- Looking for sbrk - found
+-- Looking for strerror_r
+-- Looking for strerror_r - found
+-- Looking for strerror_s
+-- Looking for strerror_s - not found
+-- Looking for setenv
+-- Looking for setenv - found
+-- Performing Test HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+-- Performing Test HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC - Failed
+-- Performing Test HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+-- Performing Test HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - Success
+-- Looking for pthread_getname_np
+-- Looking for pthread_getname_np - found
+-- Looking for pthread_setname_np
+-- Looking for pthread_setname_np - found
+-- Looking for pthread_get_name_np
+-- Looking for pthread_get_name_np - not found
+-- Looking for pthread_set_name_np
+-- Looking for pthread_set_name_np - not found
+-- Looking for dlopen
+-- Looking for dlopen - found
+-- Looking for proc_pid_rusage
+-- Looking for proc_pid_rusage - not found
+-- Performing Test HAVE_CXX_ATOMICS_WITHOUT_LIB
+-- Performing Test HAVE_CXX_ATOMICS_WITHOUT_LIB - Success
+-- Performing Test HAVE_CXX_ATOMICS64_WITHOUT_LIB
+-- Performing Test HAVE_CXX_ATOMICS64_WITHOUT_LIB - Success
+-- Performing Test LLVM_HAS_ATOMICS
+-- Performing Test LLVM_HAS_ATOMICS - Success
+-- LLVM host triple: x86_64-unknown-linux-gnu
+-- Native target architecture is X86
+-- Threads enabled.
+-- Could NOT find OCaml (missing: OCAMLFIND OCAML_VERSION OCAML_STDLIB_PATH) 
+-- Could NOT find OCaml (missing: OCAMLFIND OCAML_VERSION OCAML_STDLIB_PATH) 
+-- OCaml bindings disabled.
+-- Could NOT find Python module pygments
+-- Could NOT find Python module pygments.lexers.c_cpp
+-- Could NOT find Python module yaml
+-- LLVM default target triple: x86_64-unknown-linux-gnu
+CMake Warning at cmake/modules/HandleLLVMOptions.cmake:88 (message):
+  Job pooling is only available with Ninja generators.
+Call Stack (most recent call first):
+  CMakeLists.txt:1145 (include)
+
+
+-- Performing Test SUPPORTS_LIBCXX_HARDENING_MODE
+-- Performing Test SUPPORTS_LIBCXX_HARDENING_MODE - Success
+-- Performing Test LLVM_USES_LIBSTDCXX
+-- Performing Test LLVM_USES_LIBSTDCXX - Success
+-- Performing Test LLVM_DEFAULT_TO_GLIBCXX_USE_CXX11_ABI
+-- Performing Test LLVM_DEFAULT_TO_GLIBCXX_USE_CXX11_ABI - Success
+-- Performing Test _CAN_LINK_EXECUTABLE
+-- Performing Test _CAN_LINK_EXECUTABLE - Success
+-- Performing Test CXX_SUPPORTS_CUSTOM_LINKER
+-- Performing Test CXX_SUPPORTS_CUSTOM_LINKER - Success
+-- Performing Test C_SUPPORTS_FPIC
+-- Performing Test C_SUPPORTS_FPIC - Success
+-- Performing Test CXX_SUPPORTS_FPIC
+-- Performing Test CXX_SUPPORTS_FPIC - Success
+-- Building with -fPIC
+-- Performing Test C_SUPPORTS_FNO_SEMANTIC_INTERPOSITION
+-- Performing Test C_SUPPORTS_FNO_SEMANTIC_INTERPOSITION - Success
+-- Performing Test CXX_SUPPORTS_FNO_SEMANTIC_INTERPOSITION
+-- Performing Test CXX_SUPPORTS_FNO_SEMANTIC_INTERPOSITION - Success
+-- Performing Test SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG
+-- Performing Test SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG - Success
+-- Performing Test C_SUPPORTS_CXX98_COMPAT_EXTRA_SEMI_FLAG
+-- Performing Test C_SUPPORTS_CXX98_COMPAT_EXTRA_SEMI_FLAG - Failed
+-- Performing Test CXX_SUPPORTS_CXX98_COMPAT_EXTRA_SEMI_FLAG
+-- Performing Test CXX_SUPPORTS_CXX98_COMPAT_EXTRA_SEMI_FLAG - Failed
+-- Performing Test CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG
+-- Performing Test CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG - Success
+-- Performing Test CXX_WSUGGEST_OVERRIDE_ALLOWS_ONLY_FINAL
+-- Performing Test CXX_WSUGGEST_OVERRIDE_ALLOWS_ONLY_FINAL - Success
+-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP
+-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP - Failed
+-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSUPPORTED_FLAG
+-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSUPPORTED_FLAG - Failed
+-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSUPPORTED_FLAG
+-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSUPPORTED_FLAG - Success
+-- Performing Test GLIBC_2_36_OR_NEWER
+-- Performing Test GLIBC_2_36_OR_NEWER - Failed
+Precompiled headers are disabled by default with GCC. Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.
+-- Precompiled headers disabled.
+-- Looking for os_signpost_interval_begin
+-- Looking for os_signpost_interval_begin - not found
+-- Looking for flock
+-- Looking for flock - found
+-- Linker detection: unknown
+-- Setting native build dir to /work1/spencerbryngelson/sbryngelson/llvm-full/build/NATIVE
+-- Setting native stamp dir to /work1/spencerbryngelson/sbryngelson/llvm-full/build/NATIVE-stamps
+-- Performing Test LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS
+-- Performing Test LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS - Success
+-- Performing Test HAS_WERROR_GLOBAL_CTORS
+-- Performing Test HAS_WERROR_GLOBAL_CTORS - Failed
+-- Looking for __x86_64__
+-- Looking for __x86_64__ - found
+-- Found Git: /usr/bin/git (found version "2.43.5") 
+-- Looking for logf128
+-- Looking for logf128 - found
+-- Targeting X86
+CMake Warning at /work1/spencerbryngelson/sbryngelson/llvm-full/mlir/CMakeLists.txt:4 (message):
+  Your CMake version is 3.25.2.  Starting with LLVM 24, the minimum version
+  of CMake required to build LLVM will become 3.31.0, and using an older
+  CMake will become an error.  Please upgrade your CMake to at least 3.31.0
+  now to avoid issues in the future.
+
+
+-- Performing Test C_SUPPORTS_WERROR_IMPLICIT_FUNCTION_DECLARATION
+-- Performing Test C_SUPPORTS_WERROR_IMPLICIT_FUNCTION_DECLARATION - Success
+-- Performing Test C_SUPPORTS_WUNDEF
+-- Performing Test C_SUPPORTS_WUNDEF - Success
+-- Performing Test C_SUPPORTS_WERROR_MISMATCHED_TAGS
+-- Performing Test C_SUPPORTS_WERROR_MISMATCHED_TAGS - Failed
+-- Performing Test CXX_SUPPORTS_WNO_UNUSED_BUT_SET_PARAMETER
+-- Performing Test CXX_SUPPORTS_WNO_UNUSED_BUT_SET_PARAMETER - Success
+-- Performing Test C_SUPPORTS_WERROR_GLOBAL_CONSTRUCTOR
+-- Performing Test C_SUPPORTS_WERROR_GLOBAL_CONSTRUCTOR - Failed
+-- Performing Test CXX_SUPPORTS_WERROR_GLOBAL_CONSTRUCTOR
+-- Performing Test CXX_SUPPORTS_WERROR_GLOBAL_CONSTRUCTOR - Failed
+-- Searching for ocloc
+-- ocloc not found
+-- ocloc not found, MLIRXeVMTarget will not be able to use ocloc for native binary compilation.
+-- Performing Test COMPILER_SUPPORTS_WARNING_WEAK_VTABLES
+-- Performing Test COMPILER_SUPPORTS_WARNING_WEAK_VTABLES - Failed
+CMake Warning at /work1/spencerbryngelson/sbryngelson/llvm-full/clang/CMakeLists.txt:3 (message):
+  Your CMake version is 3.25.2.  Starting with LLVM 24, the minimum version
+  of CMake required to build LLVM will become 3.31.0, and using an older
+  CMake will become an error.  Please upgrade your CMake to at least 3.31.0
+  now to avoid issues in the future.
+
+
+-- Looking for sys/resource.h
+-- Looking for sys/resource.h - found
+-- Looking for dlfcn.h
+-- Looking for dlfcn.h - found
+-- Looking for dladdr
+-- Looking for dladdr - found
+-- Clang version: 24.0.0git
+-- Looking for include file sys/inotify.h
+-- Looking for include file sys/inotify.h - found
+-- Performing Test HAVE_LINKER_FLAG_LONG_PLT
+-- Performing Test HAVE_LINKER_FLAG_LONG_PLT - Success
+-- Found Perl: /usr/bin/perl (found version "5.32.1") 
+-- Found Python3: /usr/bin/python3.12 (found version "3.12.12") found components: Interpreter 
+CMake Warning at /work1/spencerbryngelson/sbryngelson/llvm-full/flang/CMakeLists.txt:3 (message):
+  Your CMake version is 3.25.2.  Starting with LLVM 24, the minimum version
+  of CMake required to build LLVM will become 3.31.0, and using an older
+  CMake will become an error.  Please upgrade your CMake to at least 3.31.0
+  now to avoid issues in the future.
+
+
+-- Found Python3: /usr/bin/python3.12 (found suitable version "3.12.12", minimum required is "3.8") found components: Interpreter 
+-- Flang version: 24.0.0
+-- Performing Test CXX_SUPPORTS_NO_DEPRECATED_COPY_FLAG
+-- Performing Test CXX_SUPPORTS_NO_DEPRECATED_COPY_FLAG - Success
+-- Performing Test CXX_SUPPORTS_NO_STRING_CONVERSION_FLAG
+-- Performing Test CXX_SUPPORTS_NO_STRING_CONVERSION_FLAG - Failed
+-- Performing Test CXX_SUPPORTS_NO_CTAD_MAYBE_UNSUPPORTED_FLAG
+-- Performing Test CXX_SUPPORTS_NO_CTAD_MAYBE_UNSUPPORTED_FLAG - Success
+-- Performing Test CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG
+-- Performing Test CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG - Failed
+-- Performing Test HAVE_LDBL_MANT_DIG_113
+-- Performing Test HAVE_LDBL_MANT_DIG_113 - Failed
+-- Looking for quadmath.h
+-- Looking for quadmath.h - found
+-- quadmath.h found without additional include paths
+-- Looking for sinq in quadmath
+-- Looking for sinq in quadmath - found
+-- Registering ExampleIRTransforms as a pass plugin (static build: OFF)
+-- Registering Bye as a pass plugin (static build: OFF)
+-- Failed to find LLVM FileCheck
+-- Google Benchmark version: v1.9.5, normalized to 1.9.5
+-- Looking for shm_open in rt
+-- Looking for shm_open in rt - found
+-- Performing Test HAVE_CXX_FLAG_WALL
+-- Performing Test HAVE_CXX_FLAG_WALL - Success
+-- Performing Test HAVE_CXX_FLAG_WEXTRA
+-- Performing Test HAVE_CXX_FLAG_WEXTRA - Success
+-- Performing Test HAVE_CXX_FLAG_WSHADOW
+-- Performing Test HAVE_CXX_FLAG_WSHADOW - Success
+-- Performing Test HAVE_CXX_FLAG_WFLOAT_EQUAL
+-- Performing Test HAVE_CXX_FLAG_WFLOAT_EQUAL - Success
+-- Performing Test HAVE_CXX_FLAG_WOLD_STYLE_CAST
+-- Performing Test HAVE_CXX_FLAG_WOLD_STYLE_CAST - Success
+-- Performing Test HAVE_CXX_FLAG_WCONVERSION
+-- Performing Test HAVE_CXX_FLAG_WCONVERSION - Success
+-- Performing Test HAVE_CXX_FLAG_WFORMAT_2
+-- Performing Test HAVE_CXX_FLAG_WFORMAT_2 - Success
+-- Performing Test HAVE_CXX_FLAG_WSUGGEST_OVERRIDE
+-- Performing Test HAVE_CXX_FLAG_WSUGGEST_OVERRIDE - Success
+-- Performing Test HAVE_CXX_FLAG_PEDANTIC
+-- Performing Test HAVE_CXX_FLAG_PEDANTIC - Success
+-- Performing Test HAVE_CXX_FLAG_PEDANTIC_ERRORS
+-- Performing Test HAVE_CXX_FLAG_PEDANTIC_ERRORS - Success
+-- Performing Test HAVE_CXX_FLAG_WSHORTEN_64_TO_32
+-- Performing Test HAVE_CXX_FLAG_WSHORTEN_64_TO_32 - Failed
+-- Performing Test HAVE_CXX_FLAG_FSTRICT_ALIASING
+-- Performing Test HAVE_CXX_FLAG_FSTRICT_ALIASING - Success
+-- Performing Test HAVE_CXX_FLAG_WNO_DEPRECATED_DECLARATIONS
+-- Performing Test HAVE_CXX_FLAG_WNO_DEPRECATED_DECLARATIONS - Success
+-- Performing Test HAVE_CXX_FLAG_FNO_EXCEPTIONS
+-- Performing Test HAVE_CXX_FLAG_FNO_EXCEPTIONS - Success
+-- Performing Test HAVE_CXX_FLAG_WSTRICT_ALIASING
+-- Performing Test HAVE_CXX_FLAG_WSTRICT_ALIASING - Success
+-- Performing Test HAVE_CXX_FLAG_WTHREAD_SAFETY
+-- Performing Test HAVE_CXX_FLAG_WTHREAD_SAFETY - Failed
+-- Performing Test HAVE_CXX_FLAG_COVERAGE
+-- Performing Test HAVE_CXX_FLAG_COVERAGE - Success
+CMake Warning at /work1/spencerbryngelson/sbryngelson/llvm-full/third-party/benchmark/CMakeLists.txt:329 (message):
+  Using std::regex with exceptions disabled is not fully supported
+
+
+-- Performing Test STEADY_CLOCK -- success
+-- Performing Test PTHREAD_AFFINITY -- success
+-- Configuring done
+-- Generating done
+-- Build files have been written to: /work1/spencerbryngelson/sbryngelson/llvm-full/build
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
index 44affd514f613..46996b2161383 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
@@ -19,6 +19,7 @@
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
 #include "flang/Optimizer/HLFIR/Passes.h"
 #include "flang/Optimizer/OpenMP/Passes.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/IR/PatternMatch.h"
 #include "mlir/Pass/Pass.h"
 #include "mlir/Support/LLVM.h"
@@ -39,6 +40,22 @@ static llvm::cl::opt<bool> inlineAllocatableExprAssignFlag(
                    "hlfir.expr (e.g., from hlfir.elemental)"),
     llvm::cl::init(false));
 
+/// Is \p assign the copy-in of an `omp.private` copy region, writing the
+/// privatized clone? The operation defines its first copy-region block
+/// argument to be the original host variable and the second to be the memory
+/// allocated for the clone, so the two cannot overlap and the copy can be
+/// inlined without an aliasing check.
+static bool isOmpPrivateCopyInAssign(hlfir::AssignOp assign) {
+  mlir::Region *region = assign->getParentRegion();
+  auto privateOp =
+      llvm::dyn_cast_or_null<mlir::omp::PrivateClauseOp>(region->getParentOp());
+  if (!privateOp || region != &privateOp.getCopyRegion())
+    return false;
+  auto blockArg = llvm::dyn_cast<mlir::BlockArgument>(assign.getLhs());
+  return blockArg && blockArg.getOwner()->getParent() == region &&
+         blockArg.getArgNumber() == 1;
+}
+
 namespace {
 /// Expand hlfir.assign of array RHS to array LHS into a loop nest
 /// of element-by-element assignments. Also handles scalar RHS broadcast
@@ -104,7 +121,7 @@ class InlineHLFIRAssignConversion
 
     bool rhsNeedsTemporary = false;
     if (rhs.isArray() && !mlir::isa<hlfir::ExprType>(rhs.getType()) &&
-        !assign.getTemporaryLhs()) {
+        !assign.getTemporaryLhs() && !isOmpPrivateCopyInAssign(assign)) {
       fir::AliasAnalysis aliasAnalysis;
       mlir::AliasResult aliasRes = aliasAnalysis.alias(lhs, rhs);
       if (!aliasRes.isNo()) {
diff --git a/flang/test/HLFIR/inline-hlfir-assign.fir b/flang/test/HLFIR/inline-hlfir-assign.fir
index 6cf6fcedb0af1..19a7ef32fdf4a 100644
--- a/flang/test/HLFIR/inline-hlfir-assign.fir
+++ b/flang/test/HLFIR/inline-hlfir-assign.fir
@@ -496,3 +496,37 @@ func.func @_QPtest_scalar_ref_from_lhs(%arg0: !fir.ref<!fir.array<10xf32>>) {
 // CHECK:           }
 // CHECK:           return
 // CHECK:         }
+
+// The copy-in of an omp.private copy region writes the privatized clone,
+// which the operation defines to be distinct from the original host variable,
+// so it inlines even though alias analysis cannot prove it from the block
+// arguments alone.
+omp.private {type = firstprivate} @_QFtestEc_firstprivate : !fir.box<!fir.array<1xf64>> copy {
+^bb0(%arg0: !fir.ref<!fir.box<!fir.array<1xf64>>>, %arg1: !fir.ref<!fir.box<!fir.array<1xf64>>>):
+  %0 = fir.load %arg0 : !fir.ref<!fir.box<!fir.array<1xf64>>>
+  hlfir.assign %0 to %arg1 : !fir.box<!fir.array<1xf64>>, !fir.ref<!fir.box<!fir.array<1xf64>>>
+  omp.yield(%arg1 : !fir.ref<!fir.box<!fir.array<1xf64>>>)
+}
+// CHECK-LABEL:   omp.private {type = firstprivate} @_QFtestEc_firstprivate : !fir.box<!fir.array<1xf64>> copy {
+// CHECK:         ^bb0(%[[ORIG:.*]]: !fir.ref<!fir.box<!fir.array<1xf64>>>, %[[CLONE:.*]]: !fir.ref<!fir.box<!fir.array<1xf64>>>):
+// CHECK:           %[[RHS:.*]] = fir.load %[[ORIG]] : !fir.ref<!fir.box<!fir.array<1xf64>>>
+// CHECK:           %[[LHS:.*]] = fir.load %[[CLONE]] : !fir.ref<!fir.box<!fir.array<1xf64>>>
+// CHECK:           fir.do_loop
+// CHECK-NOT:       hlfir.assign %[[RHS]] to %[[CLONE]]
+// CHECK:           omp.yield(%[[CLONE]] : !fir.ref<!fir.box<!fir.array<1xf64>>>)
+// CHECK:         }
+
+// An assignment in the copy region that does not write the clone keeps its
+// aliasing check.
+omp.private {type = firstprivate} @_QFtestEd_firstprivate : !fir.box<!fir.array<1xf64>> copy {
+^bb0(%arg0: !fir.ref<!fir.box<!fir.array<1xf64>>>, %arg1: !fir.ref<!fir.box<!fir.array<1xf64>>>):
+  %0 = fir.load %arg1 : !fir.ref<!fir.box<!fir.array<1xf64>>>
+  hlfir.assign %0 to %arg0 : !fir.box<!fir.array<1xf64>>, !fir.ref<!fir.box<!fir.array<1xf64>>>
+  omp.yield(%arg1 : !fir.ref<!fir.box<!fir.array<1xf64>>>)
+}
+// CHECK-LABEL:   omp.private {type = firstprivate} @_QFtestEd_firstprivate : !fir.box<!fir.array<1xf64>> copy {
+// CHECK:         ^bb0(%[[ORIG2:.*]]: !fir.ref<!fir.box<!fir.array<1xf64>>>, %[[CLONE2:.*]]: !fir.ref<!fir.box<!fir.array<1xf64>>>):
+// CHECK:           %[[RHS2:.*]] = fir.load %[[CLONE2]] : !fir.ref<!fir.box<!fir.array<1xf64>>>
+// CHECK:           hlfir.assign %[[RHS2]] to %[[ORIG2]] : !fir.box<!fir.array<1xf64>>, !fir.ref<!fir.box<!fir.array<1xf64>>>
+// CHECK:           omp.yield(%[[CLONE2]] : !fir.ref<!fir.box<!fir.array<1xf64>>>)
+// CHECK:         }



More information about the flang-commits mailing list