MLIR 23.0.0git
ACCDeclareGPUModuleInsertion.cpp
Go to the documentation of this file.
1//===- ACCDeclareGPUModuleInsertion.cpp
2//------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass copies globals marked with the `acc.declare` attribute into the
11// GPU module so that device code (e.g. acc routine, compute regions) can
12// reference them.
13//
14// Overview:
15// ---------
16// Globals that have the `acc.declare` attribute (from the OpenACC declare
17// directive or from the `ACCImplicitDeclare` pass) must be present in the
18// GPU module for device code to use them. This pass inserts copies of those
19// globals into the GPU module, creating the module if it does not yet exist.
20// The host copy of each global remains in the parent module.
21//
22// Example:
23// --------
24//
25// Before:
26// module {
27// memref.global @arr : memref<7xf32> = dense<0.0>
28// {acc.declare = #acc.declare<dataClause = acc_create>}
29// }
30//
31// After:
32// module attributes {gpu.container_module} {
33// memref.global @arr : memref<7xf32> = dense<0.0>
34// {acc.declare = #acc.declare<dataClause = acc_create>}
35// gpu.module @acc_gpu_module {
36// memref.global @arr : memref<7xf32> = dense<0.0>
37// {acc.declare = #acc.declare<dataClause = acc_create>}
38// }
39// }
40//
41// Requirements:
42// -------------
43// The pass uses the `acc::OpenACCSupport` for:
44// - getOrCreateGPUModule: to obtain or create the GPU module.
45// - emitNYI: to report failure when GPU module creation is not supported.
46// If no custom implementation is registered, the default implementation is
47// used (see OpenACCSupport).
48//
49//===----------------------------------------------------------------------===//
50
55#include "mlir/IR/BuiltinOps.h"
60namespace mlir {
61namespace acc {
62#define GEN_PASS_DEF_ACCDECLAREGPUMODULEINSERTION
63#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
64} // namespace acc
65} // namespace mlir
66
67#define DEBUG_TYPE "acc-declare-gpu-module-insertion"
68
69using namespace mlir;
70
71namespace {
73static bool hasAccDeclareGlobals(ModuleOp mod) {
74 for (Operation &op : mod.getBody()->getOperations())
75 if (op.getAttr(acc::getDeclareAttrName()))
76 return true;
77 return false;
78}
79
80class ACCDeclareGPUModuleInsertion
82 ACCDeclareGPUModuleInsertion> {
83public:
85 ACCDeclareGPUModuleInsertion>::ACCDeclareGPUModuleInsertionBase;
86
87 LogicalResult copyGlobalsToGPUModule(gpu::GPUModuleOp gpuMod, ModuleOp mod,
88 acc::OpenACCSupport &accSupport) const {
89 SymbolTable gpuSymTable(gpuMod);
90
91 for (Operation &globalOp : mod.getBody()->getOperations()) {
92 if (!globalOp.getAttr(acc::getDeclareAttrName()))
93 continue;
94
95 auto symOp = dyn_cast<SymbolOpInterface>(&globalOp);
96 if (!symOp)
97 continue;
98
99 StringAttr name = symOp.getNameAttr();
100
101 if (Operation *existing = gpuSymTable.lookup(name.getValue())) {
102 // Reuse only when the existing GPU symbol is structurally equivalent to
103 // the global we would insert. Otherwise treat as a conflict (different
104 // op type or different definition).
105 if (existing->getName() != globalOp.getName() ||
107 existing, &globalOp,
109 /*markEquivalent=*/nullptr,
111 accSupport.emitNYI(globalOp.getLoc(),
112 llvm::Twine("duplicate global symbol '") +
113 name.getValue() + "' in gpu module");
114 return failure();
115 }
116 continue;
117 }
118
119 gpuSymTable.insert(globalOp.clone());
120 }
121 return success();
122 }
123
124 void runOnOperation() override {
125 ModuleOp mod = getOperation();
126
127 // Check for any candidates first - do this to avoid creating the GPU module
128 // if there are no candidates.
129 if (!hasAccDeclareGlobals(mod))
130 return;
131
132 acc::OpenACCSupport &accSupport = getAnalysis<acc::OpenACCSupport>();
133 std::optional<gpu::GPUModuleOp> gpuMod =
134 accSupport.getOrCreateGPUModule(mod);
135 if (!gpuMod) {
136 accSupport.emitNYI(mod.getLoc(), "Failed to create GPU module");
137 return;
138 }
139
140 if (failed(copyGlobalsToGPUModule(*gpuMod, mod, accSupport)))
141 return;
142 }
143};
144
145} // namespace
return success()
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
Definition SymbolTable.h:24
Operation * lookup(StringRef name) const
Look up a symbol with the specified name, returning null if no such name exists.
StringAttr insert(Operation *symbol, Block::iterator insertPt={})
Insert a new symbol into the table, and rename it as necessary to avoid collisions.
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
std::optional< gpu::GPUModuleOp > getOrCreateGPUModule(ModuleOp mod, bool create=true, llvm::StringRef name="")
Get or optionally create a GPU module in the given module.
static constexpr StringLiteral getDeclareAttrName()
Used to obtain the attribute name for declare.
Definition OpenACC.h:172
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two operations (including their regions) and return if they are equivalent.
static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs)
Helper that can be used with isEquivalentTo above to consider ops equivalent even if their operands a...