MLIR 24.0.0git
ACCRecipeMaterialization.cpp
Go to the documentation of this file.
1//===- ACCRecipeMaterialization.cpp - Materialize ACC recipes -------------===//
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// Overview:
10// ---------
11// OpenACC compute constructs (acc.parallel, acc.serial, acc.kernels) and
12// acc.loop can carry data clauses (acc.private, acc.firstprivate,
13// acc.reduction) that refer to recipes (acc.private.recipe,
14// acc.firstprivate.recipe, acc.reduction.recipe). Recipes define how to
15// initialize, copy, combine, or destroy a particular variable. This pass clones
16// those regions into the construct and ensures the materialized SSA values are
17// used instead.
18//
19// Transforms:
20// -----------
21// 1. Firstprivate: Inserts acc.firstprivate_map so the initial value is
22// available on the device, then clones the recipe init and copy regions
23// into the construct and replaces uses with the materialized alloca.
24// Optional destroy region is cloned before the region terminator.
25//
26// 2. Private: Clones the recipe init region into the construct (at the
27// region entry or at the loop op for acc.loop private). Replaces uses
28// of the recipe result with the materialized alloca. Optional destroy
29// region is cloned before the region terminator.
30//
31// 3. Reduction: Creates acc.reduction_init (init region inlined) and
32// acc.reduction_combine_region (combiner region inlined). Uses within
33// the region are updated to the reduction init result.
34//
35// Requirements:
36// -------------
37// 1. OpenACCSupport: The pass uses the `acc::OpenACCSupport` analysis
38// including emitNYI for unsupported cases.
39//
40//===----------------------------------------------------------------------===//
41
51#include "mlir/IR/Block.h"
52#include "mlir/IR/Builders.h"
53#include "mlir/IR/IRMapping.h"
54#include "mlir/IR/SymbolTable.h"
55#include "mlir/IR/Value.h"
56#include "mlir/IR/ValueRange.h"
58#include "mlir/Support/LLVM.h"
60#include "llvm/ADT/STLExtras.h"
61#include "llvm/ADT/TypeSwitch.h"
62#include "llvm/Support/Debug.h"
63#include "llvm/Support/ErrorHandling.h"
64
65namespace mlir {
66namespace acc {
67#define GEN_PASS_DEF_ACCRECIPEMATERIALIZATION
68#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
69} // namespace acc
70} // namespace mlir
71
72#define DEBUG_TYPE "acc-recipe-materialization"
73
74namespace {
75
76using namespace mlir;
77
78static void setLocation(Region &region, Location loc) {
79 // Since recipes are generated per type and not per variable, the location
80 // of the recipe operations which get inlined will not necessarily be the
81 // same as the location of the op that is being materialized. Force an update
82 // of the location of the recipe operations to the location of the op that is
83 // being materialized.
84 region.walk([&](Operation *op) { op->setLoc(loc); });
85}
86
87static void saveVarName(StringRef name, Value dst) {
88 if (name.empty())
89 return;
90 if (Operation *dstOp = dst.getDefiningOp()) {
91 if (dstOp->getAttrOfType<acc::VarNameAttr>(acc::getVarNameAttrName()))
92 return;
93 if (isa<ACC_DATA_ENTRY_OPS>(dstOp))
94 return;
95 dstOp->setAttr(acc::getVarNameAttrName(),
96 acc::VarNameAttr::get(dstOp->getContext(), name));
97 return;
98 }
99 auto blockArg = dyn_cast<BlockArgument>(dst);
100 if (!blockArg)
101 return;
102 Block *block = blockArg.getOwner();
103 Region *region = block ? block->getParent() : nullptr;
104 if (!region || !block->isEntryBlock())
105 return;
106 Operation *parent = region->getParentOp();
107 if (!parent)
108 return;
109 auto funcOp = dyn_cast<FunctionOpInterface>(parent);
110 if (!funcOp)
111 return;
112 unsigned argIdx = blockArg.getArgNumber();
113 if (argIdx >= funcOp.getNumArguments())
114 return;
115 if (funcOp.getArgAttr(argIdx, acc::getVarNameAttrName()))
116 return;
117 funcOp.setArgAttr(argIdx, acc::getVarNameAttrName(),
118 acc::VarNameAttr::get(parent->getContext(), name));
119}
120
121static void saveVarName(Value src, Value dst) {
122 saveVarName(acc::getVariableName(src), dst);
123}
124
125static void resolveVarNamePlaceholders(Block *block, Block::iterator ip,
126 StringRef name) {
127 StringRef placeholder = acc::getVarNamePlaceholder();
128 for (auto it = block->begin(); it != std::next(ip); ++it) {
129 auto attr = it->getAttrOfType<acc::VarNameAttr>(acc::getVarNameAttrName());
130 if (attr && attr.getName() == placeholder) {
131 if (name.empty())
132 it->removeAttr(acc::getVarNameAttrName());
133 else
134 it->setAttr(acc::getVarNameAttrName(),
135 acc::VarNameAttr::get(it->getContext(), name));
136 }
137 }
138}
139
140// Clone the destroy region of the recipe before the terminator of the provided
141// block. Values must be provided for the destroy region block arguments
142// according to the recipe specifications.
143template <typename RecipeOpTy>
144static void cloneDestroy(Location loc, RecipeOpTy recipe, mlir::Block *block,
146 const llvm::SmallVector<mlir::Value> &arguments) {
147 IRMapping mapping{};
148 Region &destroyRegion = recipe.getDestroyRegion();
149 assert(destroyRegion.getBlocks().front().getNumArguments() ==
150 arguments.size() &&
151 "unexpected acc recipe destroy block arguments");
152
153 setLocation(destroyRegion, loc);
154
155 mapping.map(destroyRegion.getBlocks().front().getArguments(), arguments);
156 acc::cloneACCRegionInto(&destroyRegion, block, ip, mapping,
157 /*resultsToReplace=*/{});
158}
159
160class ACCRecipeMaterialization
161 : public acc::impl::ACCRecipeMaterializationBase<ACCRecipeMaterialization> {
162public:
164 ACCRecipeMaterialization>::ACCRecipeMaterializationBase;
165 void runOnOperation() override;
166
167private:
168 // When handling firstprivate, the initial value needs to be available on
169 // the GPU. One way to get that value there is to map the variable through
170 // global memory.
171 // Thus, when we materialize a firstprivate, we materialize it into
172 // a mapping action first. This function ends up with doing the following:
173 // %dev = acc.firstprivate var(%var)
174 // =>
175 // %copy = acc.firstprivate_map var(%var)
176 // %dev = acc.firstprivate var(%copy)
177 // When the recipe materialization happens, the `acc.firstprivate` ends up
178 // being removed. But because of the way we chain it to the
179 // `acc.firstprivate_map`, then its result becomes live-in to the
180 // compute region and used as the variable the initial value is loaded from.
181 void handleFirstprivateMapping(acc::FirstprivateOp firstprivateOp) const;
182 template <typename OpTy>
183 void removeRecipe(OpTy op, ModuleOp moduleOp) const;
184 template <typename OpTy, typename RecipeOpTy, typename AccOpTy>
185 LogicalResult materialize(OpTy op, RecipeOpTy recipe, AccOpTy accOp,
186 acc::OpenACCSupport &accSupport,
187 acc::ACCToGPUMappingPolicy &policy) const;
188 template <typename OpTy>
189 LogicalResult materializeForACCOp(OpTy accOp, acc::OpenACCSupport &accSupport,
190 acc::ACCToGPUMappingPolicy &policy) const;
191};
192
193void ACCRecipeMaterialization::handleFirstprivateMapping(
194 acc::FirstprivateOp firstprivateOp) const {
195 OpBuilder builder(firstprivateOp);
196 auto mapFirstprivateOp = acc::FirstprivateMapInitialOp::create(
197 builder, firstprivateOp.getLoc(), firstprivateOp.getVar(),
198 firstprivateOp.getStructured(), firstprivateOp.getImplicit(),
199 firstprivateOp.getBounds());
200 mapFirstprivateOp.setName(firstprivateOp.getName());
201 firstprivateOp.getVarMutable().assign(mapFirstprivateOp.getAccVar());
202}
203
204template <typename OpTy>
205void ACCRecipeMaterialization::removeRecipe(OpTy op, ModuleOp moduleOp) const {
206 auto recipeName = op.getNameAttr();
207 if (SymbolTable::symbolKnownUseEmpty(recipeName, moduleOp)) {
208 LLVM_DEBUG(llvm::dbgs() << "erasing recipe: " << recipeName << "\n");
209 op.erase();
210 } else {
211 LLVM_DEBUG({
212 std::optional<SymbolTable::UseRange> symbolUses =
213 op.getSymbolUses(moduleOp);
214 if (symbolUses.has_value()) {
215 for (SymbolTable::SymbolUse symbolUse : *symbolUses) {
216 llvm::dbgs() << "symbol use: ";
217 symbolUse.getUser()->dump();
218 }
219 }
220 });
221 llvm_unreachable("expected no use of recipe symbol");
222 }
223}
224
225template <typename OpTy, typename RecipeOpTy, typename AccOpTy>
226LogicalResult ACCRecipeMaterialization::materialize(
227 OpTy op, RecipeOpTy recipe, AccOpTy accOp, acc::OpenACCSupport &accSupport,
228 acc::ACCToGPUMappingPolicy &policy) const {
229 Region &region = accOp.getRegion();
230 Value origPtr = op.getVar();
231 Value accPtr = op.getAccVar();
232 assert(accPtr && "invalid op: null acc var");
233
234 OpBuilder b(op);
235 SmallVector<Value> triples;
236
237 // Clone init block into the region at the insertion point specified.
238 Region &initRegion = recipe.getInitRegion();
239 unsigned initNumArguments =
240 initRegion.getBlocks().front().getArguments().size();
241 if (initNumArguments > 1) {
242 // Code from C/C++ will most likely only provide extent arguments to the
243 // recipe arguments.
244 if ((initNumArguments - 1) % 3 != 0) {
245 (void)accSupport.emitNYI(recipe.getLoc(),
246 "privatization of array section with extents");
247 return failure();
248 }
249 // The remaining arguments must be the bounds triples
250 // (lower-bound, upper-bound, step), ...
251 unsigned argIdx = 1;
252 // Cast the given value to the type of the combiner region's argument
253 // at position argIdx, and increment argIdx.
254 auto castValueToArgType = [&](Location loc, Value v) {
256 b, loc, v,
257 initRegion.getBlocks().front().getArgument(argIdx++).getType(),
258 /*isUnsignedCast=*/false);
259 };
260 for (Value bound : acc::getBounds(op)) {
261 auto dataBound = bound.getDefiningOp<acc::DataBoundsOp>();
262 assert(dataBound &&
263 "acc.reduction's bound must be defined by acc.bounds");
264 // NOTE: we should probably generate get_lowerbound, get_upperbound
265 // and get_stride here, so that we can stop looking for the acc.bounds
266 // operation above, and just use the `bound` value.
267 Value lb =
268 castValueToArgType(dataBound.getLoc(), dataBound.getLowerbound());
269 Value ub =
270 castValueToArgType(dataBound.getLoc(), dataBound.getUpperbound());
271 Value step =
272 castValueToArgType(dataBound.getLoc(), dataBound.getStride());
273 triples.append({lb, ub, step});
274 }
275 assert(triples.size() + 1 == initNumArguments &&
276 "mismatch between number bounds and number of recipe init block "
277 "arguments");
278 }
279
280 IRMapping mapping;
281 SmallVector<Value> initArgs{origPtr};
282 initArgs.append(triples);
283 mapping.map(initRegion.getBlocks().front().getArguments(), initArgs);
284
285 Location loc = op.getLoc();
286 setLocation(initRegion, loc);
287
288 if constexpr (std::is_same_v<OpTy, acc::PrivateOp>) {
289 // Clone the init region for a private.
290 Block *block = &region.front();
291 auto [results, ip] = acc::cloneACCRegionInto(
292 &initRegion, block, block->begin(), mapping, {accPtr});
293 assert(results.size() == 1 && "expected single result from init region");
294 saveVarName(op.getAccVar(), results[0]);
295 resolveVarNamePlaceholders(block, ip, acc::getVariableName(op.getAccVar()));
296 // Clone the destroy region for a private, if it exists.
297 if (!recipe.getDestroyRegion().empty()) {
298 results.insert(results.begin(), origPtr);
299 results.append(triples);
300 cloneDestroy(loc, recipe, block, std::prev(block->end()), results);
301 }
302 } else if constexpr (std::is_same_v<OpTy, acc::FirstprivateOp>) {
303 // Clone the init region for a firstprivate.
304 Block *block = &region.front();
305 auto [results, ip] = acc::cloneACCRegionInto(
306 &initRegion, block, block->begin(), mapping, {accPtr});
307 assert(results.size() == 1 && "expected single result from init region");
308 saveVarName(op.getAccVar(), results[0]);
309 resolveVarNamePlaceholders(block, ip, acc::getVariableName(op.getAccVar()));
310 // We want the copy to store the origPtr to private
311 results.insert(results.begin(), origPtr);
312 results.append(triples);
313
314 // Clone the copy region for a firstprivate
315 mapping.clear();
316 mapping.map(recipe.getCopyRegion().front().getArguments(), results);
317 // Clone the copy region for a firstprivate.
318 Region &copyRegion = recipe.getCopyRegion();
319 setLocation(copyRegion, loc);
320 acc::cloneACCRegionInto(&copyRegion, block, std::next(ip), mapping, {});
321 if (!recipe.getDestroyRegion().empty()) {
322 // origPtr was already pushed.
323 cloneDestroy(loc, recipe, block, std::prev(block->end()), results);
324 }
325 } else if constexpr (std::is_same_v<OpTy, acc::ReductionOp>) {
326 auto cloneRegionIntoAccRegion = [&](Region *src, Region *dest,
327 bool hasResult) {
328 src->cloneInto(dest, mapping);
329 Block *block = &dest->front();
330 Operation *terminator = block->getTerminator();
331 b.setInsertionPoint(terminator);
332 if (hasResult)
333 acc::YieldOp::create(b, op.getLoc(), terminator->getOperands());
334 else
335 acc::YieldOp::create(b, op.getLoc(), ValueRange{});
336 terminator->erase();
337 };
338
339 // Clone the init region into acc.reduction_init.
340 if constexpr (std::is_same_v<AccOpTy, acc::ParallelOp>)
341 b.setInsertionPointToStart(&region.front());
342 else if constexpr (std::is_same_v<AccOpTy, acc::LoopOp>)
343 b.setInsertionPoint(op);
344 else
345 llvm_unreachable("unexpected acc op with reduction recipe");
346
347 auto reductionOp = acc::ReductionInitOp::create(
348 b, op.getLoc(), origPtr, recipe.getReductionOperatorAttr());
349 saveVarName(op.getAccVar(), reductionOp.getResult());
350 cloneRegionIntoAccRegion(&initRegion, &reductionOp.getRegion(),
351 /*hasResult=*/true);
352 Block *initBlock = &reductionOp.getRegion().front();
353 resolveVarNamePlaceholders(initBlock, std::prev(initBlock->end()),
354 acc::getVariableName(op.getAccVar()));
355
356 // Update the uses within the loop to use the reduction op result.
357 replaceAllUsesInRegionWith(accPtr, reductionOp.getResult(), region);
358
359 // Clone the combiner region into acc.reduction_combine_region.
360 Region &combinerRegion = recipe.getCombinerRegion();
361 setLocation(combinerRegion, loc);
362
363 Block *entryBlock = &combinerRegion.front();
364
365 if constexpr (std::is_same_v<AccOpTy, acc::ParallelOp>)
366 b.setInsertionPoint(region.back().getTerminator());
367 else if constexpr (std::is_same_v<AccOpTy, acc::LoopOp>)
368 b.setInsertionPointAfter(accOp);
369 else
370 llvm_unreachable("unexpected acc op with reduction recipe");
371
372 // Map the first two block arguments to the original and private
373 // reduction variables. If the recipe's combiner region has the bounds
374 // arguments, we have to map them to the corresponding operands of
375 // acc.reduction operation.
376 mapping.clear();
377 SmallVector<Value, 2> argsRemapping{origPtr, reductionOp.getResult()};
378 argsRemapping.append(triples);
379 mapping.map(entryBlock->getArguments(), argsRemapping);
380
381 auto combineRegionOp = acc::ReductionCombineRegionOp::create(
382 b, op.getLoc(), origPtr, reductionOp.getResult());
383 cloneRegionIntoAccRegion(&combinerRegion, &combineRegionOp.getRegion(),
384 /*hasResult=*/false);
385
386 auto *ctx = b.getContext();
387
388 // For reductions that come from parallel constructs, explicitly set the
389 // GPU parallel dimensions attribute to blockXDim since they will always be
390 // gang private. GPU parallel dimensions cannot be determined for acc.loop
391 // at this point.
392 if constexpr (std::is_same_v<AccOpTy, acc::ParallelOp>) {
393 acc::GPUParallelDimsAttr parDimsAttr;
394 if (accOp.isEffectivelySerial()) {
395 // If acc.serial has been lowered to a parallel op that is effectively
396 // sequential
397 parDimsAttr = acc::getSeqParDimsAttr(ctx, policy);
398 } else {
399 parDimsAttr = acc::getGangDim1ParDimsAttr(ctx, policy);
400 }
401 acc::setParDimsAttr(reductionOp, parDimsAttr);
402 acc::setParDimsAttr(combineRegionOp, parDimsAttr);
403 }
404
405 // Set sequential parallel dimensions attribute for loops in the recipe.
406 auto setSeqParDimsForRecipeLoops = [&](Region *r) {
407 r->walk([&](LoopLikeOpInterface loopLike) {
408 acc::setParDimsAttr(loopLike, acc::getSeqParDimsAttr(ctx, policy));
409 });
410 };
411 setSeqParDimsForRecipeLoops(&reductionOp.getRegion());
412 setSeqParDimsForRecipeLoops(&combineRegionOp.getRegion());
413
414 if (!recipe.getDestroyRegion().empty()) {
415 SmallVector<Value> results{origPtr, reductionOp.getResult()};
416 results.append(triples);
417 Block::iterator ip = std::next(Block::iterator(combineRegionOp));
418 cloneDestroy(loc, recipe, combineRegionOp->getBlock(), ip, results);
419 }
420 } else {
421 llvm_unreachable("unexpected op type");
422 }
423
424 op.erase();
425 return success();
426}
427
428template <typename OpTy>
429LogicalResult ACCRecipeMaterialization::materializeForACCOp(
430 OpTy accOp, acc::OpenACCSupport &accSupport,
431 acc::ACCToGPUMappingPolicy &policy) const {
432 assert(isa<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>(accOp));
433
434 if (!accOp.getFirstprivateOperands().empty()) {
435 // Clear the firstprivate operands list so there will be no uses after
436 // the recipe is materialized.
437 SmallVector<Value> operands(accOp.getFirstprivateOperands());
438 accOp.getFirstprivateOperandsMutable().clear();
439 for (Value operand : operands) {
440 auto firstprivateOp = cast<acc::FirstprivateOp>(operand.getDefiningOp());
441 auto symbolRef = cast<SymbolRefAttr>(firstprivateOp.getRecipeAttr());
442 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
443 auto recipeOp = cast<acc::FirstprivateRecipeOp>(decl);
444 LLVM_DEBUG(llvm::dbgs() << "materializing: " << firstprivateOp << "\n"
445 << symbolRef << "\n");
446 handleFirstprivateMapping(firstprivateOp);
447 if (failed(
448 materialize(firstprivateOp, recipeOp, accOp, accSupport, policy)))
449 return failure();
450 }
451 }
452
453 if (!accOp.getPrivateOperands().empty()) {
454 // Clear the private operands list so there will be no uses after
455 // the recipe is materialized.
456 SmallVector<Value> operands(accOp.getPrivateOperands());
457 accOp.getPrivateOperandsMutable().clear();
458 for (Value operand : operands) {
459 auto privateOp = cast<acc::PrivateOp>(operand.getDefiningOp());
460 auto symbolRef = cast<SymbolRefAttr>(privateOp.getRecipeAttr());
461 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
462 auto recipeOp = cast<acc::PrivateRecipeOp>(decl);
463 LLVM_DEBUG(llvm::dbgs() << "materializing: " << privateOp << "\n"
464 << symbolRef << "\n");
465 if (failed(materialize(privateOp, recipeOp, accOp, accSupport, policy)))
466 return failure();
467 }
468 }
469
470 if (!accOp.getReductionOperands().empty()) {
471 // Clear the reduction operands list so there will be no uses after
472 // the recipe is materialized.
473 SmallVector<Value> operands(accOp.getReductionOperands());
474 accOp.getReductionOperandsMutable().clear();
475 for (Value operand : operands) {
476 auto reductionOp = cast<acc::ReductionOp>(operand.getDefiningOp());
477 auto symbolRef = cast<SymbolRefAttr>(reductionOp.getRecipeAttr());
478 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
479 auto recipeOp = cast<acc::ReductionRecipeOp>(decl);
480 LLVM_DEBUG(llvm::dbgs() << "materializing: " << reductionOp << "\n"
481 << symbolRef << "\n");
482 if (failed(materialize(reductionOp, recipeOp, accOp, accSupport, policy)))
483 return failure();
484 }
485 }
486 return success();
487}
488
489void ACCRecipeMaterialization::runOnOperation() {
490 ModuleOp moduleOp = getOperation();
491 acc::OpenACCSupport &accSupport = getAnalysis<acc::OpenACCSupport>();
492
494
495 // Materialize all recipes for all compute constructs and loop constructs.
496 bool anyFailed = false;
497 moduleOp.walk([&](Operation *op) {
498 if (anyFailed)
499 return;
501 [&](auto constructOp) {
502 if (failed(materializeForACCOp(constructOp, accSupport, policy)))
503 anyFailed = true;
504 });
505 });
506 if (anyFailed) {
507 signalPassFailure();
508 return;
509 }
510
511 // Remove all recipes.
512 moduleOp.walk([&](Operation *op) {
513 if (auto recipe = dyn_cast<acc::ReductionRecipeOp>(op))
514 removeRecipe(recipe, moduleOp);
515 else if (auto recipe = dyn_cast<acc::PrivateRecipeOp>(op))
516 removeRecipe(recipe, moduleOp);
517 else if (auto recipe = dyn_cast<acc::FirstprivateRecipeOp>(op))
518 removeRecipe(recipe, moduleOp);
519 });
520}
521
522} // namespace
return success()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
Block represents an ordered list of Operations.
Definition Block.h:33
OpListType::iterator iterator
Definition Block.h:164
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition Block.cpp:27
Operation & front()
Definition Block.h:177
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
BlockArgListType getArguments()
Definition Block.h:111
iterator end()
Definition Block.h:168
iterator begin()
Definition Block.h:167
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Definition Block.cpp:36
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
void clear()
Clears all mappings held by the mapper.
Definition IRMapping.h:79
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition IRMapping.h:30
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:209
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
Definition Operation.h:243
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
Block & back()
Definition Region.h:64
void cloneInto(Region *dest, IRMapping &mapper)
Clone the internal blocks from this region into dest.
Definition Region.cpp:70
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:213
BlockListType & getBlocks()
Definition Region.h:45
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
Definition Region.h:309
This class represents a specific symbol use.
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
static bool symbolKnownUseEmpty(StringAttr symbol, Operation *from)
Return if the given symbol is known to have no uses that are nested within the given operation 'from'...
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
Default policy that provides the standard GPU mapping: gang(dim:1) -> BlockX (gridDim....
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
#define ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS
Definition OpenACC.h:65
std::string getVariableName(mlir::Value v)
Attempts to extract the variable name from a value by walking through view-like operations until an a...
GPUParallelDimsAttr getGangDim1ParDimsAttr(MLIRContext *ctx, ACCToGPUMappingPolicy &policy)
Create a gang dim 1 GPUParallelDimsAttr based on the mapping policy.
mlir::SmallVector< mlir::Value > getBounds(mlir::Operation *accDataClauseOp)
Used to obtain bounds from an acc data clause operation.
Definition OpenACC.cpp:5274
GPUParallelDimsAttr getSeqParDimsAttr(MLIRContext *ctx, ACCToGPUMappingPolicy &policy)
Create a sequential GPUParallelDimsAttr based on the mapping policy.
llvm::StringLiteral getVarNamePlaceholder()
Returns a placeholder string for use as an acc.var_name attribute value when the actual variable name...
static constexpr StringLiteral getVarNameAttrName()
Definition OpenACC.h:215
void setParDimsAttr(Operation *op, GPUParallelDimsAttr attr)
Set parallel dimensions on op.
std::pair< llvm::SmallVector< Value >, Block::iterator > cloneACCRegionInto(Region *src, Block *dest, Block::iterator inlinePoint, IRMapping &mapping, ValueRange resultsToReplace)
Clone an ACC region into a destination block at the given insertion point.
ACCParMappingPolicy< mlir::acc::GPUParallelDimAttr > ACCToGPUMappingPolicy
Type alias for the GPU-specific mapping policy.
Include the generated interface declarations.
Value convertScalarToDtype(OpBuilder &b, Location loc, Value operand, Type toType, bool isUnsignedCast)
Converts a scalar value operand to type toType.
Definition Utils.cpp:241
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region &region)
Replace all uses of orig within the given region with replacement.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:139