[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