[flang-commits] [flang] [mlir] [flang][acc] Add AA implementation for acc operations (PR #189772)

via flang-commits flang-commits at lists.llvm.org
Tue Mar 31 16:46:28 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir

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

Author: Razvan Lupusoru (razvanlupusoru)

<details>
<summary>Changes</summary>

This PR extends flang's alias analysis so it can reason about values that originate from OpenACC data and privatization operations, including values passed through block arguments.

---

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


8 Files Affected:

- (modified) flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h (+16) 
- (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+24) 
- (modified) flang/lib/Optimizer/Analysis/CMakeLists.txt (+4) 
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp (+38) 
- (added) flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir (+546) 
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACC.h (+2) 
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h (+5) 
- (modified) mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp (+16) 


``````````diff
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
index a8b9bcf5cfd4b..840622b7dd0f9 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
@@ -13,14 +13,30 @@
 #ifndef FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
 #define FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
 
+#include "flang/Optimizer/Analysis/AliasAnalysis.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/IR/Builders.h"
+#include "mlir/IR/Operation.h"
 #include "mlir/IR/Value.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include <string>
 
 namespace fir {
 namespace acc {
 
+/// Memory source for `mappedValue` when it is produced by OpenACC mapping op
+/// `accOp` . Private-like ops return `SourceKind::Allocate`; other data clauses
+/// trace the host variable via `traceValue`.
+///
+/// `accumulatedAttrs` collects Fortran variable attributes from the path from
+/// the queried value to `accOp` (e.g. [hl]fir.declare); they are merged into
+/// the returned source so TARGET/POINTER/INTENT_IN are not dropped.
+fir::AliasAnalysis::Source getSourceFromACCValue(
+    mlir::Value mappedValue, mlir::Operation *accOp,
+    llvm::function_ref<fir::AliasAnalysis::Source(mlir::Value)> traceValue,
+    bool originIsData,
+    fir::AliasAnalysis::Source::Attributes accumulatedAttrs = {});
+
 /// Attempts to extract the variable name from a value by walking through
 /// FIR operations and looking for variable names.
 /// \param v The value to extract the variable name from
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 550e8a3a281d6..77d334657ad9b 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -13,8 +13,11 @@
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/Dialect/FortranVariableInterface.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "mlir/Analysis/AliasAnalysis.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
 #include "mlir/IR/BuiltinOps.h"
@@ -24,6 +27,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
+#include <optional>
 
 using namespace mlir;
 
@@ -680,6 +684,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
     auto opResult = mlir::cast<OpResult>(v);
     assert(opResult.getOwner() == defOp && "v must be a result of defOp");
     ty = opResult.getType();
+    std::optional<AliasAnalysis::Source> accSourceReturn;
     llvm::TypeSwitch<Operation *>(defOp)
         .Case([&](hlfir::AsExprOp op) {
           // TODO: we should probably always report hlfir.as_expr
@@ -937,10 +942,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
               !mlir::isa<fir::BaseBoxType>(ty))
             followBoxData = true;
         })
+        .Case<ACC_DATA_ENTRY_AND_INIT_OPS>([&](auto op) {
+          accSourceReturn = fir::acc::getSourceFromACCValue(
+              v, op.getOperation(),
+              [&](mlir::Value x) {
+                return getSource(x, getLastInstantiationPoint);
+              },
+              followingData, attributes);
+          breakFromLoop = true;
+        })
         .Default([&](auto op) {
           defOp = nullptr;
           breakFromLoop = true;
         });
+    if (accSourceReturn)
+      return *accSourceReturn;
   }
   if (!defOp && type == SourceKind::Unknown) {
     // Check if the memory source is coming through a dummy argument.
@@ -956,6 +972,14 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
       // hlfir.eval_in_mem block operands is allocated by the operation.
       type = SourceKind::Allocate;
       ty = v.getType();
+    } else if (mlir::Operation *accOp =
+                   mlir::acc::getACCDataClauseOpForBlockArg(v)) {
+      return fir::acc::getSourceFromACCValue(
+          v, accOp,
+          [&](mlir::Value x) {
+            return getSource(x, getLastInstantiationPoint);
+          },
+          followingData, attributes);
     }
   }
 
diff --git a/flang/lib/Optimizer/Analysis/CMakeLists.txt b/flang/lib/Optimizer/Analysis/CMakeLists.txt
index 398a6d3b88427..c017708e35ddf 100644
--- a/flang/lib/Optimizer/Analysis/CMakeLists.txt
+++ b/flang/lib/Optimizer/Analysis/CMakeLists.txt
@@ -6,22 +6,26 @@ add_flang_library(FIRAnalysis
   DEPENDS
   CUFDialect
   FIRDialect
+  FIROpenACCSupport
   FIRSupport
   HLFIRDialect
 
   LINK_LIBS
   CUFDialect
   FIRDialect
+  FIROpenACCSupport
   FIRSupport
   HLFIRDialect
 
   MLIR_DEPS
   MLIRIR
+  MLIROpenACCDialect
   MLIROpenMPDialect
 
   MLIR_LIBS
   MLIRFuncDialect
   MLIRLLVMDialect
   MLIRMathTransforms
+  MLIROpenACCDialect
   MLIROpenMPDialect
 )
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index 519978dba1afd..39ccd3aad1598 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
+#include "flang/Optimizer/Analysis/AliasAnalysis.h"
 #include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Builder/Complex.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
@@ -29,6 +30,7 @@
 #include "mlir/Interfaces/ViewLikeInterface.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/Support/raw_ostream.h"
+#include <mlir/Support/LLVM.h>
 
 using namespace mlir;
 
@@ -616,6 +618,42 @@ mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe(
   return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
 }
 
+static bool isACCPrivateLikeOp(mlir::Operation *op) {
+  if (!op)
+    return false;
+  return mlir::isa<mlir::acc::ReductionInitOp, mlir::acc::PrivateOp,
+                   mlir::acc::FirstprivateOp,
+                   mlir::acc::FirstprivateMapInitialOp>(op);
+}
+
+fir::AliasAnalysis::Source fir::acc::getSourceFromACCValue(
+    mlir::Value mappedValue, mlir::Operation *accOp,
+    llvm::function_ref<fir::AliasAnalysis::Source(mlir::Value)> traceValue,
+    bool originIsData,
+    fir::AliasAnalysis::Source::Attributes accumulatedAttrs) {
+  assert(accOp && "OpenACC mapping op required");
+  if (isACCPrivateLikeOp(accOp))
+    return {{mappedValue, nullptr, originIsData},
+            fir::AliasAnalysis::SourceKind::Allocate,
+            mappedValue.getType(),
+            accumulatedAttrs,
+            false,
+            false};
+
+  // Not private-like: classify using the corresponding host variable's source.
+  //
+  // Caveat: with discrete device memory, host and device copies do not alias
+  // even when this path makes them look related. Alias analysis here is usually
+  // about two values *inside* a compute region, not host-vs-device pointer
+  // queries, so using the host source remains a reasonable tradeoff for
+  // disambiguating in-region uses. Finer modeling would require extending
+  // AliasAnalysis::Source (with address space) and teaching AA to use it.
+  fir::AliasAnalysis::Source traced =
+      traceValue(mlir::acc::getVar(accOp));
+  traced.attributes |= accumulatedAttrs;
+  return traced;
+}
+
 mlir::Value fir::acc::getOriginalDef(mlir::Value value, bool stripDeclare) {
   mlir::Value currentValue = value;
 
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir b/flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir
new file mode 100644
index 0000000000000..9fb5ee221691d
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir
@@ -0,0 +1,546 @@
+// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
+
+// -----
+
+// Two acc.copyin results from distinct host allocas do not alias.
+// CHECK-LABEL: Testing : "testBothOutsideCopyinDistinctHosts"
+// CHECK-DAG: cin_a#0 <-> cin_b#0: NoAlias
+
+func.func @testBothOutsideCopyinDistinctHosts() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a", test.ptr = "cin_a"}
+  %cb = acc.copyin varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b", test.ptr = "cin_b"}
+  return
+}
+
+// -----
+
+// Two acc.copyin results from dummy arguments that are Fortran TARGET variables:
+// they may alias.
+// CHECK-LABEL: Testing : "testBothOutsideCopyinTargetDummyArgsMayAlias"
+// CHECK-DAG: arg_cp_a#0 <-> arg_cp_b#0: MayAlias
+
+func.func @testBothOutsideCopyinTargetDummyArgsMayAlias(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) {
+  %ds = fir.dummy_scope : !fir.dscope
+  %dx = fir.declare %arg0 dummy_scope %ds arg 1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEex"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %dy = fir.declare %arg1 dummy_scope %ds arg 2 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEey"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %cx = acc.copyin varPtr(%dx : !fir.ref<f32>) -> !fir.ref<f32> {name = "x", test.ptr = "arg_cp_a"}
+  %cy = acc.copyin varPtr(%dy : !fir.ref<f32>) -> !fir.ref<f32> {name = "y", test.ptr = "arg_cp_b"}
+  return
+}
+
+// -----
+
+// Two acc.copyin results mapping the same host ref must alias.
+// CHECK-LABEL: Testing : "testBothOutsideCopyinSameHostMustAlias"
+// CHECK-DAG: out_must_a#0 <-> out_must_b#0: MustAlias
+
+func.func @testBothOutsideCopyinSameHostMustAlias() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca1 = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a", test.ptr = "out_must_a"}
+  %ca2 = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a", test.ptr = "out_must_b"}
+  return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "testBothOutsideCreateDistinctHosts"
+// CHECK-DAG: crt_a#0 <-> crt_b#0: NoAlias
+
+func.func @testBothOutsideCreateDistinctHosts() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ta = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a", test.ptr = "crt_a"}
+  %tb = acc.create varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b", test.ptr = "crt_b"}
+  return
+}
+
+// -----
+
+// Same distinct-host copyins as above, but threaded through acc.compute_region
+// block arguments.
+// CHECK-LABEL: Testing : "testComputeRegionCopyinDistinctHostsInsideConvert"
+// CHECK-DAG: cr_dist_a#0 <-> cr_dist_b#0: NoAlias
+
+func.func @testComputeRegionCopyinDistinctHostsInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  %cb = acc.copyin varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b"}
+  acc.compute_region ins(%arg0 = %ca, %arg1 = %cb) : (!fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %arg0 {test.ptr = "cr_dist_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %arg1 {test.ptr = "cr_dist_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.yield
+  } {origin = "acc.kernels"}
+  return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "testComputeRegionCreateDistinctHostsInsideConvert"
+// CHECK-DAG: cr_crt_a#0 <-> cr_crt_b#0: NoAlias
+
+func.func @testComputeRegionCreateDistinctHostsInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ta = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  %tb = acc.create varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b"}
+  acc.compute_region ins(%arg0 = %ta, %arg1 = %tb) : (!fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %arg0 {test.ptr = "cr_crt_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %arg1 {test.ptr = "cr_crt_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.yield
+  } {origin = "acc.kernels"}
+  return
+}
+
+// -----
+
+// Same TARGET dummy copyins as testBothOutsideCopyinTargetDummyArgsMayAlias,
+// through acc.compute_region block args.
+// CHECK-LABEL: Testing : "testComputeRegionCopyinTargetDummiesMayAliasInsideConvert"
+// CHECK-DAG: cr_tgt_a#0 <-> cr_tgt_b#0: MayAlias
+
+func.func @testComputeRegionCopyinTargetDummiesMayAliasInsideConvert(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) {
+  %ds = fir.dummy_scope : !fir.dscope
+  %dx = fir.declare %arg0 dummy_scope %ds arg 1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEex"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %dy = fir.declare %arg1 dummy_scope %ds arg 2 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEey"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %cx = acc.copyin varPtr(%dx : !fir.ref<f32>) -> !fir.ref<f32> {name = "x"}
+  %cy = acc.copyin varPtr(%dy : !fir.ref<f32>) -> !fir.ref<f32> {name = "y"}
+  acc.compute_region ins(%cr0 = %cx, %cr1 = %cy) : (!fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %cr0 {test.ptr = "cr_tgt_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %cr1 {test.ptr = "cr_tgt_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.yield
+  } {origin = "acc.parallel"}
+  return
+}
+
+// -----
+
+// Single host copyin wired twice through arguments; both block args alias the
+// same mapped host variable.
+// CHECK-LABEL: Testing : "testComputeRegionCopyinSameHostMustAliasInsideConvert"
+// CHECK-DAG: cr_must_a#0 <-> cr_must_b#0: MustAlias
+
+func.func @testComputeRegionCopyinSameHostMustAliasInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  acc.compute_region ins(%arg0 = %ca, %arg1 = %ca) : (!fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %arg0 {test.ptr = "cr_must_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %arg1 {test.ptr = "cr_must_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.yield
+  } {origin = "acc.kernels"}
+  return
+}
+
+// -----
+
+// Distinct-host copyins passed as acc.kernels dataOperands.
+// CHECK-LABEL: Testing : "testKernelsCopyinDistinctHostsInsideConvert"
+// CHECK-DAG: kern_dist_a#0 <-> kern_dist_b#0: NoAlias
+
+func.func @testKernelsCopyinDistinctHostsInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  %cb = acc.copyin varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b"}
+  acc.kernels dataOperands(%ca, %cb : !fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %ca {test.ptr = "kern_dist_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %cb {test.ptr = "kern_dist_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.terminator
+  }
+  return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "testKernelsCreateDistinctHostsInsideConvert"
+// CHECK-DAG: kern_crt_a#0 <-> kern_crt_b#0: NoAlias
+
+func.func @testKernelsCreateDistinctHostsInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ta = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  %tb = acc.create varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b"}
+  acc.kernels dataOperands(%ta, %tb : !fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %ta {test.ptr = "kern_crt_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %tb {test.ptr = "kern_crt_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.terminator
+  }
+  return
+}
+
+// -----
+
+// TARGET dummy copyins as acc.kernels dataOperands.
+// CHECK-LABEL: Testing : "testKernelsCopyinTargetDummiesMayAliasInsideConvert"
+// CHECK-DAG: kern_tgt_a#0 <-> kern_tgt_b#0: MayAlias
+
+func.func @testKernelsCopyinTargetDummiesMayAliasInsideConvert(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) {
+  %ds = fir.dummy_scope : !fir.dscope
+  %dx = fir.declare %arg0 dummy_scope %ds arg 1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEex"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %dy = fir.declare %arg1 dummy_scope %ds arg 2 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEey"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %cx = acc.copyin varPtr(%dx : !fir.ref<f32>) -> !fir.ref<f32> {name = "x"}
+  %cy = acc.copyin varPtr(%dy : !fir.ref<f32>) -> !fir.ref<f32> {name = "y"}
+  acc.kernels dataOperands(%cx, %cy : !fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %cx {test.ptr = "kern_tgt_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %cy {test.ptr = "kern_tgt_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.terminator
+  }
+  return
+}
+
+// -----
+
+// Same copyin value listed twice in dataOperands; both converts must alias.
+// CHECK-LABEL: Testing : "testKernelsCopyinSameHostMustAliasInsideConvert"
+// CHECK-DAG: kern_must_a#0 <-> kern_must_b#0: MustAlias
+
+func.func @testKernelsCopyinSameHostMustAliasInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  acc.kernels dataOperands(%ca : !fir.ref<f32>) {
+    %va = fir.convert %ca {test.ptr = "kern_must_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %ca {test.ptr = "kern_must_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.terminator
+  }
+  return
+}
+
+// -----
+
+// acc.compute_region: both queried values are inside the region; test.ptr is on
+// fir.convert of each captured private (traces block operands without tagging
+// the region op).
+// CHECK-LABEL: Testing : "testComputeRegionPrivateInsideConvert"
+// CHECK-DAG: cr_priv_a#0 <-> cr_priv_b#0: NoAlias
+
+func.func @testComputeRegionPrivateInsideConvert() {
+  %a = fir.alloca f32 {uniq_name = "_QFEa"}
+  %b = fir.alloca f32 {uniq_name = "_QFEb"}
+  %da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %db = fir.declare %b {uniq_name = "_QFEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %pa = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
+  %pb = acc.private varPtr(%db : !fir.ref<f32>) -> !fir.ref<f32> {name = "b"}
+  acc.compute_region ins(%arg0 = %pa, %arg1 = %pb) : (!fir.ref<f32>, !fir.ref<f32>) {
+    %va = fir.convert %arg0 {test.ptr = "cr_priv_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %vb = fir.convert %arg1 {test.ptr = "cr_priv_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    acc.yield
+  } {origin = "acc.parallel"}
+  return
+}
+
+// -----
+
+// Same host ref as both acc.copyin and acc.private operands (two copyins would
+// must-alias); private-like mapping is a distinct allocation vs copyin.
+// CHECK-LABEL: Testing : "testComputeRegionCopyinVsPrivateSameHostNoAlias"
+// CHECK-DAG: cr_mix_cp#0 <-> cr_mix_pr#0: NoAlias
+
+func....
[truncated]

``````````

</details>


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


More information about the flang-commits mailing list