[flang][acc] Add AA implementation for acc operations (#189772)
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 commit is contained in:
parent
16255e457c
commit
9506f20b4d
@ -15,6 +15,7 @@
|
||||
|
||||
#include "mlir/Dialect/OpenACC/OpenACC.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
#include "flang/Optimizer/HLFIR/HLFIROps.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 +26,7 @@
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <optional>
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
@ -112,6 +115,39 @@ static bool isPrivateArg(omp::BlockArgOpenMPOpInterface &argIface,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Classify `mappedValue` when defined by OpenACC mapping op `accOp`.
|
||||
/// Private-like ops use `SourceKind::Allocate`; other data clauses use
|
||||
/// `getSourceFn` on the mapped host variable (`mlir::acc::getVar`).
|
||||
static fir::AliasAnalysis::Source getSourceForACCMappedValue(
|
||||
mlir::Value mappedValue, mlir::Operation *accOp,
|
||||
llvm::function_ref<fir::AliasAnalysis::Source(mlir::Value)> getSourceFn,
|
||||
bool originIsData,
|
||||
fir::AliasAnalysis::Source::Attributes accumulatedAttrs) {
|
||||
assert(accOp && "OpenACC mapping op required");
|
||||
// Private-like ops use SourceKind::Allocate.
|
||||
if (mlir::isa<mlir::acc::ReductionInitOp, mlir::acc::PrivateOp,
|
||||
mlir::acc::FirstprivateOp, mlir::acc::FirstprivateMapInitialOp>(
|
||||
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 source = getSourceFn(mlir::acc::getVar(accOp));
|
||||
source.attributes |= accumulatedAttrs;
|
||||
return source;
|
||||
}
|
||||
|
||||
namespace fir {
|
||||
|
||||
void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
|
||||
@ -680,6 +716,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 +974,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 = getSourceForACCMappedValue(
|
||||
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 +1004,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 getSourceForACCMappedValue(
|
||||
v, accOp,
|
||||
[&](mlir::Value x) {
|
||||
return getSource(x, getLastInstantiationPoint);
|
||||
},
|
||||
followingData, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,11 +17,15 @@ add_flang_library(FIRAnalysis
|
||||
|
||||
MLIR_DEPS
|
||||
MLIRIR
|
||||
MLIROpenACCDialect
|
||||
MLIROpenACCUtils
|
||||
MLIROpenMPDialect
|
||||
|
||||
MLIR_LIBS
|
||||
MLIRFuncDialect
|
||||
MLIRLLVMDialect
|
||||
MLIRMathTransforms
|
||||
MLIROpenACCDialect
|
||||
MLIROpenACCUtils
|
||||
MLIROpenMPDialect
|
||||
)
|
||||
|
||||
546
flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir
Normal file
546
flang/test/Analysis/AliasAnalysis/alias-analysis-acc.mlir
Normal file
@ -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.func @testComputeRegionCopyinVsPrivateSameHostNoAlias() {
|
||||
%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"}
|
||||
%pp = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %ca, %arg1 = %pp) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_mix_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_mix_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.parallel"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: Testing : "testComputeRegionCreateVsPrivateSameHostNoAlias"
|
||||
// CHECK-DAG: cr_mix_cr#0 <-> cr_mix_pr2#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionCreateVsPrivateSameHostNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%ta = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
%pp = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %ta, %arg1 = %pp) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_mix_cr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_mix_pr2"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.parallel"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// Same host: acc.copyin vs acc.firstprivate.
|
||||
// CHECK-LABEL: Testing : "testComputeRegionCopyinVsFirstprivateSameHostNoAlias"
|
||||
// CHECK-DAG: cr_fp_cp#0 <-> cr_fp_pr#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionCopyinVsFirstprivateSameHostNoAlias() {
|
||||
%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"}
|
||||
%pf = acc.firstprivate varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %ca, %arg1 = %pf) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_fp_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_fp_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.parallel"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// Same host: acc.copyin vs acc.firstprivate_map.
|
||||
// CHECK-LABEL: Testing : "testComputeRegionCopyinVsFirstprivateMapSameHostNoAlias"
|
||||
// CHECK-DAG: cr_fpm_cp#0 <-> cr_fpm_fm#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionCopyinVsFirstprivateMapSameHostNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%fm = acc.firstprivate_map varPtr(%da : !fir.ref<f32>) varType(f32) -> !fir.ref<f32> {name = "a"}
|
||||
%ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %ca, %arg1 = %fm) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_fpm_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_fpm_fm"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.kernels"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// acc.kernels: same host as copyin and acc.private dataOperands.
|
||||
// CHECK-LABEL: Testing : "testKernelsCopyinVsPrivateSameHostNoAlias"
|
||||
// CHECK-DAG: k_mix_cp#0 <-> k_mix_pr#0: NoAlias
|
||||
|
||||
func.func @testKernelsCopyinVsPrivateSameHostNoAlias() {
|
||||
%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"}
|
||||
%pp = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.kernels dataOperands(%ca : !fir.ref<f32>) private(%pp : !fir.ref<f32>) {
|
||||
%va = fir.convert %ca {test.ptr = "k_mix_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %pp {test.ptr = "k_mix_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: Testing : "testKernelsCreateVsPrivateSameHostNoAlias"
|
||||
// CHECK-DAG: k_mix_cr#0 <-> k_mix_pr2#0: NoAlias
|
||||
|
||||
func.func @testKernelsCreateVsPrivateSameHostNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%ta = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
%pp = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.kernels dataOperands(%ta : !fir.ref<f32>) private(%pp : !fir.ref<f32>) {
|
||||
%va = fir.convert %ta {test.ptr = "k_mix_cr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %pp {test.ptr = "k_mix_pr2"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// acc.kernels: acc.copyin vs acc.firstprivate.
|
||||
// CHECK-LABEL: Testing : "testKernelsCopyinVsFirstprivateSameHostNoAlias"
|
||||
// CHECK-DAG: k_fp_cp#0 <-> k_fp_pr#0: NoAlias
|
||||
|
||||
func.func @testKernelsCopyinVsFirstprivateSameHostNoAlias() {
|
||||
%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"}
|
||||
%pf = acc.firstprivate varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.kernels dataOperands(%ca : !fir.ref<f32>) firstprivate(%pf : !fir.ref<f32>) {
|
||||
%va = fir.convert %ca {test.ptr = "k_fp_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %pf {test.ptr = "k_fp_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// acc.kernels: acc.copyin vs acc.firstprivate_map.
|
||||
// CHECK-LABEL: Testing : "testKernelsCopyinVsFirstprivateMapSameHostNoAlias"
|
||||
// CHECK-DAG: k_fpm_cp#0 <-> k_fpm_fm#0: NoAlias
|
||||
|
||||
func.func @testKernelsCopyinVsFirstprivateMapSameHostNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%fm = acc.firstprivate_map varPtr(%da : !fir.ref<f32>) varType(f32) -> !fir.ref<f32> {name = "a"}
|
||||
%ca = acc.copyin varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.kernels dataOperands(%ca : !fir.ref<f32>) firstprivate(%fm : !fir.ref<f32>) {
|
||||
%va = fir.convert %ca {test.ptr = "k_fpm_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %fm {test.ptr = "k_fpm_fm"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// acc.private inside acc.compute_region; ins carries acc.create from the host ref.
|
||||
// CHECK-LABEL: Testing : "testComputeRegionPrivateOpInsideVsInsCreateNoAlias"
|
||||
// CHECK-DAG: cr_body_pr#0 <-> cr_body_cr#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionPrivateOpInsideVsInsCreateNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%tc = acc.create varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %tc) : (!fir.ref<f32>) {
|
||||
%pv = acc.private varPtr(%arg0 : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
%vb = fir.convert %pv {test.ptr = "cr_body_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vc = fir.convert %arg0 {test.ptr = "cr_body_cr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.parallel"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// acc.private inside acc.kernels on the dataOperand copyin of the host ref.
|
||||
// CHECK-LABEL: Testing : "testKernelsPrivateOpInsideVsDataCopyinNoAlias"
|
||||
// CHECK-DAG: k_body_pr#0 <-> k_body_cp#0: NoAlias
|
||||
|
||||
func.func @testKernelsPrivateOpInsideVsDataCopyinNoAlias() {
|
||||
%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>) {
|
||||
%pv = acc.private varPtr(%ca : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
%vb = fir.convert %pv {test.ptr = "k_body_pr"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vc = fir.convert %ca {test.ptr = "k_body_cp"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
acc.reduction.recipe @red_f32_aa : !fir.ref<f32> reduction_operator <add> init {
|
||||
^bb0(%arg0: !fir.ref<f32>):
|
||||
%init = fir.alloca f32
|
||||
acc.yield %init : !fir.ref<f32>
|
||||
} combiner {
|
||||
^bb0(%lhs: !fir.ref<f32>, %rhs: !fir.ref<f32>):
|
||||
%lv = fir.load %lhs : !fir.ref<f32>
|
||||
%rv = fir.load %rhs : !fir.ref<f32>
|
||||
%s = arith.addf %lv, %rv : f32
|
||||
%out = fir.alloca f32
|
||||
fir.store %s to %out : !fir.ref<f32>
|
||||
acc.yield %out : !fir.ref<f32>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Testing : "testBothOutsideReductionDistinctHosts"
|
||||
// CHECK-DAG: red_a#0 <-> red_b#0: NoAlias
|
||||
|
||||
func.func @testBothOutsideReductionDistinctHosts() {
|
||||
%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>
|
||||
%ra = acc.reduction varPtr(%da : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "a", test.ptr = "red_a"}
|
||||
%rb = acc.reduction varPtr(%db : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "b", test.ptr = "red_b"}
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Testing : "testComputeRegionReductionDistinctHostsInsideConvert"
|
||||
// CHECK-DAG: cr_red_a#0 <-> cr_red_b#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionReductionDistinctHostsInsideConvert() {
|
||||
%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>
|
||||
%ra = acc.reduction varPtr(%da : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "a"}
|
||||
%rb = acc.reduction varPtr(%db : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "b"}
|
||||
acc.compute_region ins(%arg0 = %ra, %arg1 = %rb) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_red_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_red_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.parallel"}
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Testing : "testKernelsReductionDistinctHostsInsideConvert"
|
||||
// CHECK-DAG: kern_red_a#0 <-> kern_red_b#0: NoAlias
|
||||
|
||||
func.func @testKernelsReductionDistinctHostsInsideConvert() {
|
||||
%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>
|
||||
%ra = acc.reduction varPtr(%da : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "a"}
|
||||
%rb = acc.reduction varPtr(%db : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "b"}
|
||||
acc.kernels reduction(%ra, %rb : !fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %ra {test.ptr = "kern_red_a"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %rb {test.ptr = "kern_red_b"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Testing : "testComputeRegionReductionVsPrivateSameHostNoAlias"
|
||||
// CHECK-DAG: cr_mix_rd#0 <-> cr_mix_pr3#0: NoAlias
|
||||
|
||||
func.func @testComputeRegionReductionVsPrivateSameHostNoAlias() {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa"}
|
||||
%da = fir.declare %a {uniq_name = "_QFEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%ra = acc.reduction varPtr(%da : !fir.ref<f32>) recipe(@red_f32_aa) -> !fir.ref<f32> {name = "a"}
|
||||
%pp = acc.private varPtr(%da : !fir.ref<f32>) -> !fir.ref<f32> {name = "a"}
|
||||
acc.compute_region ins(%arg0 = %ra, %arg1 = %pp) : (!fir.ref<f32>, !fir.ref<f32>) {
|
||||
%va = fir.convert %arg0 {test.ptr = "cr_mix_rd"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
%vb = fir.convert %arg1 {test.ptr = "cr_mix_pr3"} : (!fir.ref<f32>) -> !fir.ref<f32>
|
||||
acc.yield
|
||||
} {origin = "acc.kernels"}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// Allocas inside acc.parallel.
|
||||
// CHECK-LABEL: Testing : "testBothInsideParallel"
|
||||
// CHECK-DAG: par_a#0 <-> par_b#0: NoAlias
|
||||
|
||||
func.func @testBothInsideParallel() {
|
||||
acc.parallel {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa", test.ptr = "par_a"}
|
||||
%b = fir.alloca f32 {uniq_name = "_QFEb", test.ptr = "par_b"}
|
||||
acc.yield
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// Allocas inside acc.kernels.
|
||||
// CHECK-LABEL: Testing : "testBothInsideKernels"
|
||||
// CHECK-DAG: kern_a#0 <-> kern_b#0: NoAlias
|
||||
|
||||
func.func @testBothInsideKernels() {
|
||||
acc.kernels {
|
||||
%a = fir.alloca f32 {uniq_name = "_QFEa", test.ptr = "kern_a"}
|
||||
%b = fir.alloca f32 {uniq_name = "_QFEb", test.ptr = "kern_b"}
|
||||
acc.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -53,6 +53,8 @@
|
||||
mlir::acc::UpdateDeviceOp, mlir::acc::UseDeviceOp, \
|
||||
mlir::acc::ReductionOp, mlir::acc::DeclareDeviceResidentOp, \
|
||||
mlir::acc::DeclareLinkOp, mlir::acc::CacheOp
|
||||
#define ACC_DATA_ENTRY_AND_INIT_OPS \
|
||||
ACC_DATA_ENTRY_OPS, mlir::acc::ReductionInitOp
|
||||
#define ACC_DATA_EXIT_OPS \
|
||||
mlir::acc::CopyoutOp, mlir::acc::DeleteOp, mlir::acc::DetachOp, \
|
||||
mlir::acc::UpdateHostOp
|
||||
|
||||
@ -29,6 +29,11 @@ namespace acc {
|
||||
/// `ACC_COMPUTE_CONSTRUCT_OPS`.
|
||||
mlir::Operation *getEnclosingComputeOp(mlir::Region ®ion);
|
||||
|
||||
/// If `v` is not a block argument of an `acc.compute_region` body, returns
|
||||
/// nullptr. Otherwise maps the block argument to its operand and returns the
|
||||
/// defining operation if it is one of `ACC_DATA_ENTRY_OPS`.
|
||||
mlir::Operation *getACCDataClauseOpForBlockArg(mlir::Value v);
|
||||
|
||||
/// Returns true if this value is only used by `acc.private` operations in the
|
||||
/// `region`.
|
||||
bool isOnlyUsedByPrivateClauses(mlir::Value val, mlir::Region ®ion);
|
||||
|
||||
@ -25,6 +25,22 @@ mlir::Operation *mlir::acc::getEnclosingComputeOp(mlir::Region ®ion) {
|
||||
.getParentOfType<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::ComputeRegionOp>();
|
||||
}
|
||||
|
||||
mlir::Operation *mlir::acc::getACCDataClauseOpForBlockArg(mlir::Value v) {
|
||||
auto barg = mlir::dyn_cast<mlir::BlockArgument>(v);
|
||||
if (!barg)
|
||||
return nullptr;
|
||||
|
||||
mlir::Block *block = barg.getOwner();
|
||||
auto computeReg =
|
||||
mlir::dyn_cast<mlir::acc::ComputeRegionOp>(block->getParentOp());
|
||||
if (!computeReg || block != computeReg.getBody())
|
||||
return nullptr;
|
||||
|
||||
mlir::Value orig = computeReg.getOperand(barg);
|
||||
mlir::Operation *def = orig.getDefiningOp();
|
||||
return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS>(def) ? def : nullptr;
|
||||
}
|
||||
|
||||
template <typename OpTy>
|
||||
static bool isOnlyUsedByOpClauses(mlir::Value val, mlir::Region ®ion) {
|
||||
auto checkIfUsedOnlyByOpInside = [&](mlir::Operation *user) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user