MLIR 23.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
62
67#include "mlir/IR/MLIRContext.h"
70
71namespace mlir {
72namespace acc {
73#define GEN_PASS_DEF_ACCSPECIALIZEFORDEVICE
74#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
75} // namespace acc
76} // namespace mlir
77
78using namespace mlir;
79using namespace mlir::acc;
80
81namespace {
82
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 runOnOperation() override {
115 func::FuncOp func = getOperation();
116
117 TypesForDevice types{theDeviceTypes.begin(), theDeviceTypes.end()};
118
119 RewritePatternSet patterns(&getContext());
121 GreedyRewriteConfig config;
122 config.setUseTopDownTraversal(true);
123
125 // For specialized acc routines, apply patterns to the entire function
126 (void)applyPatternsGreedily(func, std::move(patterns), config);
127 } else {
128 // For non-specialized functions, apply patterns only to ACC operations
129 // inside compute constructs (not to the compute constructs themselves).
130 // Use ExistingOps strictness so the greedy driver does not expand the
131 // worklist to parent ops, which would accidentally unwrap the compute
132 // construct (e.g. after inlining acc routines with their own data
133 // regions).
134 config.setStrictness(GreedyRewriteStrictness::ExistingOps);
135 SmallVector<Operation *> opsToTransform;
136 func.walk([&](Operation *op) {
137 if (isa<ACC_COMPUTE_CONSTRUCT_OPS>(op)) {
138 // Walk inside the compute construct and collect ACC ops
139 op->walk([&](Operation *innerOp) {
140 // Skip the compute construct itself
141 if (innerOp == op)
142 return;
143 if (isa<acc::OpenACCDialect>(innerOp->getDialect()))
144 opsToTransform.push_back(innerOp);
145 });
146 }
147 });
148 if (!opsToTransform.empty())
149 (void)applyOpPatternsGreedily(opsToTransform, std::move(patterns),
150 config);
151 }
152 }
153};
154
155} // namespace
156
157//===----------------------------------------------------------------------===//
158// Pattern population functions
159//===----------------------------------------------------------------------===//
160
162 RewritePatternSet &patterns, const TypesForDevice &theDeviceTypes) {
163 MLIRContext *context = patterns.getContext();
164
165 // Declare patterns - erase declare_enter and its associated declare_exit
166 patterns.insert<ACCDeclareEnterOpConversion>(context);
167
168 // Data entry ops - replaced with their var operand
169 // Note: acc.cache, acc.private, acc.reduction, acc.firstprivate are NOT
170 // included here - they are valid in device code
182
183 // Data exit ops - simply erased (no results)
188
189 // Structured data constructs - unwrap their regions
193
194 // Compute constructs - unwrap their regions
198
199 // Unstructured data operations - erase them
203
204 // Runtime operations - erase them
205 patterns.insert<
208 context);
209
210 // Fold acc.on_device calls so dead-code elimination can remove host-only
211 // code paths in device code.
212 patterns.insert<FoldAccOnDeviceOpConversion>(context, theDeviceTypes);
213}
return success()
b getContext())
BoolAttr getBoolAttr(bool value)
Definition Builders.cpp:104
IntegerType getI1Type()
Definition Builders.cpp:57
GreedyRewriteConfig & setUseTopDownTraversal(bool use=true)
GreedyRewriteConfig & setStrictness(GreedyRewriteStrictness mode)
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
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:822
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:201
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...