MLIR 24.0.0git
ACCSpecializeForDevice.cpp
Go to the documentation of this file.
1//===- ACCSpecializeForDevice.cpp -----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass strips OpenACC constructs that are invalid or unnecessary inside
10// device code (specialized acc routines or compute construct regions).
11//
12// Overview:
13// ---------
14// In a specialized acc routine or compute construct, many OpenACC operations
15// do not make sense because they are host-side constructs. This pass removes
16// or transforms these operations appropriately:
17//
18// - Data operations that manage device memory from host perspective
19// - Compute constructs that launch kernels (we're already on device)
20// - Runtime operations like init/shutdown/set/wait
21//
22// Transformations:
23// ----------------
24// The pass applies the following transformations:
25//
26// 1. Data Entry Ops (replaced with var operand):
27// acc.attach, acc.copyin, acc.create, acc.declare_device_resident,
28// acc.declare_link, acc.deviceptr, acc.get_deviceptr, acc.nocreate,
29// acc.present, acc.update_device, acc.use_device
30//
31// 2. Data Exit Ops (erased):
32// acc.copyout, acc.delete, acc.detach, acc.update_host
33//
34// 3. Structured Data/Compute Constructs (region inlined):
35// acc.data, acc.host_data, acc.kernel_environment, acc.parallel,
36// acc.serial, acc.kernels
37//
38// 4. Unstructured Data Ops (erased):
39// acc.enter_data, acc.exit_data, acc.update, acc.declare_enter,
40// acc.declare_exit
41//
42// 5. Runtime Ops (erased):
43// acc.init, acc.shutdown, acc.set, acc.wait
44//
45// 6. acc.on_device (folded):
46// acc.on_device with constant device type is folded to a boolean constant.
47//
48// Scope of Application:
49// ---------------------
50// - For functions with `acc.specialized_routine` attribute: patterns are
51// applied to the entire function body.
52// - For non-specialized functions: patterns are applied only to ACC
53// operations INSIDE compute constructs (parallel, serial, kernels),
54// not to the compute constructs themselves or their data operands.
55//
56// Note: acc.cache, acc.private, acc.reduction, acc.firstprivate are NOT
57// transformed by this pass as they are valid in device code.
58//
59//===----------------------------------------------------------------------===//
60
63
68#include "mlir/IR/MLIRContext.h"
71
72namespace mlir {
73namespace acc {
74#define GEN_PASS_DEF_ACCSPECIALIZEFORDEVICE
75#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
76} // namespace acc
77} // namespace mlir
78
79using namespace mlir;
80using namespace mlir::acc;
81
82namespace {
83/// Fold acc.on_device with a constant device type in device code.
84class FoldAccOnDeviceOpConversion : public OpRewritePattern<acc::OnDeviceOp> {
85 using OpRewritePattern<acc::OnDeviceOp>::OpRewritePattern;
86
87 const TypesForDevice &theDeviceTypes;
88
89public:
90 FoldAccOnDeviceOpConversion(MLIRContext *context,
91 const TypesForDevice &theDeviceTypes)
92 : OpRewritePattern<acc::OnDeviceOp>(context),
93 theDeviceTypes(theDeviceTypes) {}
94
95 LogicalResult matchAndRewrite(acc::OnDeviceOp op,
96 PatternRewriter &rewriter) const override {
97 APInt constVal;
98 if (!matchPattern(op.getDeviceType(), m_ConstantInt(&constVal)))
99 return failure();
100
101 bool result = theDeviceTypes.contains(constVal.getSExtValue());
102 rewriter.replaceOpWithNewOp<arith::ConstantOp>(
103 op, rewriter.getI1Type(), rewriter.getBoolAttr(result));
104 return success();
105 }
106};
107
108class ACCSpecializeForDevice
109 : public acc::impl::ACCSpecializeForDeviceBase<ACCSpecializeForDevice> {
110public:
111 using ACCSpecializeForDeviceBase<
112 ACCSpecializeForDevice>::ACCSpecializeForDeviceBase;
113
114 void getDependentDialects(DialectRegistry &registry) const override {
115 ACCSpecializeForDeviceBase<ACCSpecializeForDevice>::getDependentDialects(
116 registry);
118 }
119
120 void runOnOperation() override {
121 func::FuncOp func = getOperation();
122
123 TypesForDevice types{theDeviceTypes.begin(), theDeviceTypes.end()};
124
125 RewritePatternSet patterns(&getContext());
127 GreedyRewriteConfig config;
128 config.setUseTopDownTraversal(true);
129
131 // For specialized acc routines, apply patterns to the entire function
132 (void)applyPatternsGreedily(func, std::move(patterns), config);
133 } else {
134 // For non-specialized functions, apply patterns only to ACC operations
135 // inside compute constructs (not to the compute constructs themselves).
136 // Use ExistingOps strictness so the greedy driver does not expand the
137 // worklist to parent ops, which would accidentally unwrap the compute
138 // construct (e.g. after inlining acc routines with their own data
139 // regions).
140 config.setStrictness(GreedyRewriteStrictness::ExistingOps);
141 SmallVector<Operation *> opsToTransform;
142 func.walk([&](Operation *op) {
143 if (isa<ACC_COMPUTE_CONSTRUCT_OPS>(op)) {
144 // Walk inside the compute construct and collect ACC ops
145 op->walk([&](Operation *innerOp) {
146 // Skip the compute construct itself
147 if (innerOp == op)
148 return;
149 if (isa<acc::OpenACCDialect>(innerOp->getDialect()))
150 opsToTransform.push_back(innerOp);
151 });
152 }
153 });
154 if (!opsToTransform.empty())
155 (void)applyOpPatternsGreedily(opsToTransform, std::move(patterns),
156 config);
157 }
158 }
159};
160} // namespace
161
162//===----------------------------------------------------------------------===//
163// Pattern population functions
164//===----------------------------------------------------------------------===//
165
167 RewritePatternSet &patterns, const TypesForDevice &theDeviceTypes) {
168 MLIRContext *context = patterns.getContext();
169
170 // Declare patterns - erase declare_enter and its associated declare_exit
171 patterns.insert<ACCDeclareEnterOpConversion>(context);
172
173 // Data entry ops - replaced with their var operand
174 // Note: acc.cache, acc.private, acc.reduction, acc.firstprivate are NOT
175 // included here - they are valid in device code
187
188 // Data exit ops - simply erased (no results)
193
194 // Structured data constructs - unwrap their regions
198
199 // Compute constructs - unwrap their regions
203
204 // Unstructured data operations - erase them
208
209 // Runtime operations - erase them
210 patterns.insert<
213 context);
214
215 // Fold acc.on_device calls so dead-code elimination can remove host-only
216 // code paths in device code.
217 patterns.insert<FoldAccOnDeviceOpConversion>(context, theDeviceTypes);
218}
return success()
b getContext())
BoolAttr getBoolAttr(bool value)
Definition Builders.cpp:108
IntegerType getI1Type()
Definition Builders.cpp:61
GreedyRewriteConfig & setUseTopDownTraversal(bool use=true)
GreedyRewriteConfig & setStrictness(GreedyRewriteStrictness mode)
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:64
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition Operation.h:237
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Definition Operation.h:849
RewritePatternSet & insert(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
MLIRContext * getContext() const
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Pattern to erase acc.declare_enter and its associated acc.declare_exit.
Pattern to simply erase an ACC op (for ops with no results).
Pattern to replace an ACC op with its var operand.
Pattern to unwrap a region from an ACC op and erase the wrapper.
llvm::SmallSetVector< int64_t, 3 > TypesForDevice
Holds information for which integers represent a device type in the runtime.
Definition Passes.h:33
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
Definition OpenACC.h:219
void registerAllExtensions(DialectRegistry &registry)
Register the standard OpenACC models for GPU, LLVM and MemRef IR.
void populateACCSpecializeForDevicePatterns(RewritePatternSet &patterns, const TypesForDevice &theDeviceTypes)
Populates all patterns for device specialization.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition Matchers.h:490
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
Definition Matchers.h:527
LogicalResult applyPatternsGreedily(Region &region, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
LogicalResult applyOpPatternsGreedily(ArrayRef< Operation * > ops, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr, bool *allErased=nullptr)
Rewrite the specified ops by repeatedly applying the highest benefit patterns in a greedy worklist dr...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...