MLIR 23.0.0git
OpenACCCG.cpp
Go to the documentation of this file.
1//===- OpenACCCG.cpp - OpenACC codegen ops, attributes, and types ---------===//
2//
3// Part of the MLIR 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// Implementation for OpenACC codegen operations, attributes, and types.
10// These correspond to the definitions in OpenACCCG*.td tablegen files
11// and are kept in a separate file because they do not represent direct mappings
12// of OpenACC language constructs; they are intermediate representations used
13// when decomposing and lowering primary `acc` dialect operations.
14//
15//===----------------------------------------------------------------------===//
16
18#include "mlir/IR/Region.h"
21#include "llvm/ADT/SmallVector.h"
22
23using namespace mlir;
24using namespace acc;
25
26namespace {
27
28/// Generic helper for single-region OpenACC ops that execute their body once
29/// and then return to the parent operation with their results (if any).
30static void
34 if (point.isParent()) {
35 regions.push_back(RegionSuccessor(&region));
36 return;
37 }
38 regions.push_back(RegionSuccessor::parent());
39}
40
42 RegionSuccessor successor) {
43 return successor.isParent() ? ValueRange(op->getResults()) : ValueRange();
44}
45
46/// Remove empty acc.kernel_environment operations. If the operation has wait
47/// operands, create a acc.wait operation to preserve synchronization.
48struct RemoveEmptyKernelEnvironment
49 : public OpRewritePattern<acc::KernelEnvironmentOp> {
50 using OpRewritePattern<acc::KernelEnvironmentOp>::OpRewritePattern;
51
52 LogicalResult matchAndRewrite(acc::KernelEnvironmentOp op,
53 PatternRewriter &rewriter) const override {
54 assert(op->getNumRegions() == 1 && "expected op to have one region");
55
56 Block &block = op.getRegion().front();
57 if (!block.empty())
58 return failure();
59
60 // Conservatively disable canonicalization of empty acc.kernel_environment
61 // operations if the wait operands in the kernel_environment cannot be fully
62 // represented by acc.wait operation.
63
64 // Disable canonicalization if device type is not the default
65 if (auto deviceTypeAttr = op.getWaitOperandsDeviceTypeAttr()) {
66 for (auto attr : deviceTypeAttr) {
67 if (auto dtAttr = mlir::dyn_cast<acc::DeviceTypeAttr>(attr)) {
68 if (dtAttr.getValue() != mlir::acc::DeviceType::None)
69 return failure();
70 }
71 }
72 }
73
74 // Disable canonicalization if any wait segment has a devnum
75 if (auto hasDevnumAttr = op.getHasWaitDevnumAttr()) {
76 for (auto attr : hasDevnumAttr) {
77 if (auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>(attr)) {
78 if (boolAttr.getValue())
79 return failure();
80 }
81 }
82 }
83
84 // Disable canonicalization if there are multiple wait segments
85 if (auto segmentsAttr = op.getWaitOperandsSegmentsAttr()) {
86 if (segmentsAttr.size() > 1)
87 return failure();
88 }
89
90 // Remove empty kernel environment.
91 // Preserve synchronization by creating acc.wait operation if needed.
92 if (!op.getWaitOperands().empty() || op.getWaitOnlyAttr())
93 rewriter.replaceOpWithNewOp<acc::WaitOp>(op, op.getWaitOperands(),
94 /*asyncOperand=*/Value(),
95 /*waitDevnum=*/Value(),
96 /*async=*/nullptr,
97 /*ifCond=*/Value());
98 else
99 rewriter.eraseOp(op);
100
101 return success();
102 }
103};
104
105template <typename EffectTy>
106static void addOperandEffect(
108 &effects,
109 const MutableOperandRange &operand) {
110 for (unsigned i = 0, e = operand.size(); i < e; ++i)
111 effects.emplace_back(EffectTy::get(), &operand[i]);
112}
113
114template <typename EffectTy>
115static void addResultEffect(
117 &effects,
118 Value result) {
119 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(result));
120}
121
122} // namespace
123
124//===----------------------------------------------------------------------===//
125// KernelEnvironmentOp
126//===----------------------------------------------------------------------===//
127
128void KernelEnvironmentOp::getSuccessorRegions(
130 getSingleRegionOpSuccessorRegions(getOperation(), getRegion(), point,
131 regions);
132}
133
134ValueRange KernelEnvironmentOp::getSuccessorInputs(RegionSuccessor successor) {
135 return getSingleRegionSuccessorInputs(getOperation(), successor);
136}
137
138void KernelEnvironmentOp::getCanonicalizationPatterns(
139 RewritePatternSet &results, MLIRContext *context) {
140 results.add<RemoveEmptyKernelEnvironment>(context);
141}
142
143//===----------------------------------------------------------------------===//
144// FirstprivateMapInitialOp
145//===----------------------------------------------------------------------===//
146
147LogicalResult FirstprivateMapInitialOp::verify() {
148 if (getDataClause() != acc::DataClause::acc_firstprivate)
149 return emitError("data clause associated with firstprivate operation must "
150 "match its intent");
151 if (!getVar())
152 return emitError("must have var operand");
153 if (!mlir::isa<mlir::acc::PointerLikeType>(getVar().getType()) &&
154 !mlir::isa<mlir::acc::MappableType>(getVar().getType()))
155 return emitError("var must be mappable or pointer-like");
156 if (mlir::isa<mlir::acc::PointerLikeType>(getVar().getType()) &&
157 getVarType() == getVar().getType())
158 return emitError("varType must capture the element type of var");
159 if (getModifiers() != acc::DataClauseModifier::none)
160 return emitError("no data clause modifiers are allowed");
161 return success();
162}
163
164void FirstprivateMapInitialOp::getEffects(
166 &effects) {
167 effects.emplace_back(MemoryEffects::Read::get(),
169 addOperandEffect<MemoryEffects::Read>(effects, getVarMutable());
171}
172
173//===----------------------------------------------------------------------===//
174// ReductionCombineOp
175//===----------------------------------------------------------------------===//
176
177void ReductionCombineOp::getEffects(
179 &effects) {
180 effects.emplace_back(MemoryEffects::Read::get(), &getSrcMemrefMutable(),
182 effects.emplace_back(MemoryEffects::Read::get(), &getDestMemrefMutable(),
184 effects.emplace_back(MemoryEffects::Write::get(), &getDestMemrefMutable(),
186}
return success()
static void addOperandEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, MutableOperandRange operand)
Helper to add an effect on an operand, referenced by its mutable range.
Definition OpenACC.cpp:1223
static void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
Definition OpenACC.cpp:1233
static void getSingleRegionOpSuccessorRegions(Operation *op, Region &region, RegionBranchPoint point, SmallVectorImpl< RegionSuccessor > &regions)
Generic helper for single-region OpenACC ops that execute their body once and then return to the pare...
Definition OpenACC.cpp:422
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
Definition OpenACC.cpp:433
bool empty()
Definition Block.h:158
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class provides a mutable adaptor for a range of operands.
Definition ValueRange.h:118
unsigned size() const
Returns the current size of the range.
Definition ValueRange.h:156
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
result_range getResults()
Definition Operation.h:415
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
This class represents a successor of a region.
static RegionSuccessor parent()
Initialize a successor that branches after/out of the parent operation.
bool isParent() const
Return true if the successor is the parent operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class represents a specific instance of an effect.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
Definition OpenACC.cpp:5089
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
Definition OpenACC.cpp:5058
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
Definition OpenACC.cpp:5162
mlir::Type getVarType(mlir::Operation *accDataClauseOp)
Used to obtains the varType from a data clause operation which records the type of variable.
Definition OpenACC.cpp:5066
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:305
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...