Skip to content

[flang][acc] Add AA implementation for acc operations#189772

Merged
razvanlupusoru merged 7 commits into
llvm:mainfrom
razvanlupusoru:accaa
Apr 1, 2026
Merged

[flang][acc] Add AA implementation for acc operations#189772
razvanlupusoru merged 7 commits into
llvm:mainfrom
razvanlupusoru:accaa

Conversation

@razvanlupusoru
Copy link
Copy Markdown
Contributor

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.

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.
@llvmbot llvmbot added mlir flang Flang issues not falling into any other category mlir:openacc flang:fir-hlfir openacc labels Mar 31, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 31, 2026

@llvm/pr-subscribers-mlir-openacc
@llvm/pr-subscribers-mlir

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

Author: Razvan Lupusoru (razvanlupusoru)

Changes

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 --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]

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 31, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Copy Markdown
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks

Copy link
Copy Markdown
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Razvan!

@razvanlupusoru razvanlupusoru merged commit 9506f20 into llvm:main Apr 1, 2026
10 checks passed
@llvm-ci
Copy link
Copy Markdown

llvm-ci commented Apr 1, 2026

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux-fast running on sanitizer-buildbot4 while building flang,mlir at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/169/builds/21491

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 97296 of 97844 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 
FAIL: Clang :: Interpreter/global-dtor.cpp (56040 of 97296)
******************** TEST 'Clang :: Interpreter/global-dtor.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 5
cat /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp | /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/clang-repl | /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/FileCheck /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# executed command: cat /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# note: command had no output on stdout or stderr
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/clang-repl
# .---command stderr------------
# | JIT session error: In graph incr_module_9-jitted-objectbuffer, section .text.startup: relocation target 0x6df76200bffc (__dso_handle:0x6df76200c000 + 0xfffffffffffffffc) is out of range of Delta32 fixup at address 0x6df76200c000 (<anonymous block> @ 0x71f76295f010 + 0x1f)
# | error: Failed to materialize symbols: { (main, { __clang_call_terminate, DW.ref.__gxx_personality_v0, $.incr_module_9.__inits.0, _ZN1DD2Ev, _ZN1DC2Ev, __orc_init_func.incr_module_9, d }) }
# | error: Failed to materialize symbols: { (main, { __orc_init_func.incr_module_9 }) }
# `-----------------------------
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/FileCheck /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# .---command stderr------------
# | /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp:10:11: error: CHECK: expected string not found in input
# | // CHECK: D[f=1.000000, m=0x0]
# |           ^
# | <stdin>:1:1: note: scanning from here
# | clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> 
# | ^
# | <stdin>:1:11: note: possible intended match here
# | clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> 
# |           ^
# | 
# | Input file: <stdin>
# | Check file: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |             1: clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl>  
# | check:10'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
# | check:10'1               ?                                                                                                                                       possible intended match
# | >>>>>>
Step 10 (stage2/asan_ubsan check) failure: stage2/asan_ubsan check (failure)
...
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 97296 of 97844 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 
FAIL: Clang :: Interpreter/global-dtor.cpp (56040 of 97296)
******************** TEST 'Clang :: Interpreter/global-dtor.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 5
cat /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp | /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/clang-repl | /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/FileCheck /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# executed command: cat /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# note: command had no output on stdout or stderr
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/clang-repl
# .---command stderr------------
# | JIT session error: In graph incr_module_9-jitted-objectbuffer, section .text.startup: relocation target 0x6df76200bffc (__dso_handle:0x6df76200c000 + 0xfffffffffffffffc) is out of range of Delta32 fixup at address 0x6df76200c000 (<anonymous block> @ 0x71f76295f010 + 0x1f)
# | error: Failed to materialize symbols: { (main, { __clang_call_terminate, DW.ref.__gxx_personality_v0, $.incr_module_9.__inits.0, _ZN1DD2Ev, _ZN1DC2Ev, __orc_init_func.incr_module_9, d }) }
# | error: Failed to materialize symbols: { (main, { __orc_init_func.incr_module_9 }) }
# `-----------------------------
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/FileCheck /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# .---command stderr------------
# | /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp:10:11: error: CHECK: expected string not found in input
# | // CHECK: D[f=1.000000, m=0x0]
# |           ^
# | <stdin>:1:1: note: scanning from here
# | clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> 
# | ^
# | <stdin>:1:11: note: possible intended match here
# | clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> 
# |           ^
# | 
# | Input file: <stdin>
# | Check file: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/clang/test/Interpreter/global-dtor.cpp
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |             1: clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl> clang-repl>  
# | check:10'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
# | check:10'1               ?                                                                                                                                       possible intended match
# | >>>>>>

joaovam pushed a commit to joaovam/llvm-project that referenced this pull request Apr 2, 2026
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.
zwu-2025 pushed a commit to zwu-2025/llvm-project that referenced this pull request May 17, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang Flang issues not falling into any other category mlir:openacc mlir openacc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants