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:
163 using acc::impl::ACCRecipeMaterializationBase<
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 SmallVector<Value> reductionBounds(acc::getBounds(op));
348 auto reductionOp =
349 acc::ReductionInitOp::create(b, op.getLoc(), origPtr, reductionBounds,
350 recipe.getReductionOperatorAttr());
351 saveVarName(op.getAccVar(), reductionOp.getResult());
352 cloneRegionIntoAccRegion(&initRegion, &reductionOp.getRegion(),
353 /*hasResult=*/true);
354 Block *initBlock = &reductionOp.getRegion().front();
355 resolveVarNamePlaceholders(initBlock, std::prev(initBlock->end()),
356 acc::getVariableName(op.getAccVar()));
357
358 // Update the uses within the loop to use the reduction op result.
359 replaceAllUsesInRegionWith(accPtr, reductionOp.getResult(), region);
360
361 // Clone the combiner region into acc.reduction_combine_region.
362 Region &combinerRegion = recipe.getCombinerRegion();
363 setLocation(combinerRegion, loc);
364
365 Block *entryBlock = &combinerRegion.front();
366
367 if constexpr (std::is_same_v<AccOpTy, acc::ParallelOp>)
368 b.setInsertionPoint(region.back().getTerminator());
369 else if constexpr (std::is_same_v<AccOpTy, acc::LoopOp>)
370 b.setInsertionPointAfter(accOp);
371 else
372 llvm_unreachable("unexpected acc op with reduction recipe");
373
374 // Map the first two block arguments to the original and private
375 // reduction variables. If the recipe's combiner region has the bounds
376 // arguments, we have to map them to the corresponding operands of
377 // acc.reduction operation.
378 mapping.clear();
379 SmallVector<Value, 2> argsRemapping{origPtr, reductionOp.getResult()};
380 argsRemapping.append(triples);
381 mapping.map(entryBlock->getArguments(), argsRemapping);
382
383 auto combineRegionOp = acc::ReductionCombineRegionOp::create(
384 b, op.getLoc(), origPtr, reductionOp.getResult());
385 cloneRegionIntoAccRegion(&combinerRegion, &combineRegionOp.getRegion(),
386 /*hasResult=*/false);
387
388 auto *ctx = b.getContext();
389
390 // For reductions that come from parallel constructs, explicitly set the
391 // GPU parallel dimensions attribute to blockXDim since they will always be
392 // gang private. GPU parallel dimensions cannot be determined for acc.loop
393 // at this point.
394 if constexpr (std::is_same_v<AccOpTy, acc::ParallelOp>) {
395 acc::GPUParallelDimsAttr parDimsAttr;
396 if (accOp.isEffectivelySerial()) {
397 // If acc.serial has been lowered to a parallel op that is effectively
398 // sequential
399 parDimsAttr = acc::getSeqParDimsAttr(ctx, policy);
400 } else {
401 parDimsAttr = acc::getGangDim1ParDimsAttr(ctx, policy);
402 }
403 acc::setParDimsAttr(reductionOp, parDimsAttr);
404 acc::setParDimsAttr(combineRegionOp, parDimsAttr);
405 }
406
407 // Set sequential parallel dimensions attribute for loops in the recipe.
408 auto setSeqParDimsForRecipeLoops = [&](Region *r) {
409 r->walk([&](LoopLikeOpInterface loopLike) {
410 acc::setParDimsAttr(loopLike, acc::getSeqParDimsAttr(ctx, policy));
411 });
412 };
413 setSeqParDimsForRecipeLoops(&reductionOp.getRegion());
414 setSeqParDimsForRecipeLoops(&combineRegionOp.getRegion());
415
416 if (!recipe.getDestroyRegion().empty()) {
417 SmallVector<Value> results{origPtr, reductionOp.getResult()};
418 results.append(triples);
419 Block::iterator ip = std::next(Block::iterator(combineRegionOp));
420 cloneDestroy(loc, recipe, combineRegionOp->getBlock(), ip, results);
421 }
422 } else {
423 llvm_unreachable("unexpected op type");
424 }
425
426 op.erase();
427 return success();
428}
429
430template <typename OpTy>
431LogicalResult ACCRecipeMaterialization::materializeForACCOp(
432 OpTy accOp, acc::OpenACCSupport &accSupport,
433 acc::ACCToGPUMappingPolicy &policy) const {
434 assert(isa<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>(accOp));
435
436 if (!accOp.getFirstprivateOperands().empty()) {
437 // Clear the firstprivate operands list so there will be no uses after
438 // the recipe is materialized.
439 SmallVector<Value> operands(accOp.getFirstprivateOperands());
440 accOp.getFirstprivateOperandsMutable().clear();
441 for (Value operand : operands) {
442 auto firstprivateOp = cast<acc::FirstprivateOp>(operand.getDefiningOp());
443 auto symbolRef = cast<SymbolRefAttr>(firstprivateOp.getRecipeAttr());
444 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
445 auto recipeOp = cast<acc::FirstprivateRecipeOp>(decl);
446 LLVM_DEBUG(llvm::dbgs() << "materializing: " << firstprivateOp << "\n"
447 << symbolRef << "\n");
448 handleFirstprivateMapping(firstprivateOp);
449 if (failed(
450 materialize(firstprivateOp, recipeOp, accOp, accSupport, policy)))
451 return failure();
452 }
453 }
454
455 if (!accOp.getPrivateOperands().empty()) {
456 // Clear the private operands list so there will be no uses after
457 // the recipe is materialized.
458 SmallVector<Value> operands(accOp.getPrivateOperands());
459 accOp.getPrivateOperandsMutable().clear();
460 for (Value operand : operands) {
461 auto privateOp = cast<acc::PrivateOp>(operand.getDefiningOp());
462 auto symbolRef = cast<SymbolRefAttr>(privateOp.getRecipeAttr());
463 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
464 auto recipeOp = cast<acc::PrivateRecipeOp>(decl);
465 LLVM_DEBUG(llvm::dbgs() << "materializing: " << privateOp << "\n"
466 << symbolRef << "\n");
467 if (failed(materialize(privateOp, recipeOp, accOp, accSupport, policy)))
468 return failure();
469 }
470 }
471
472 if (!accOp.getReductionOperands().empty()) {
473 // Clear the reduction operands list so there will be no uses after
474 // the recipe is materialized.
475 SmallVector<Value> operands(accOp.getReductionOperands());
476 accOp.getReductionOperandsMutable().clear();
477 for (Value operand : operands) {
478 auto reductionOp = cast<acc::ReductionOp>(operand.getDefiningOp());
479 auto symbolRef = cast<SymbolRefAttr>(reductionOp.getRecipeAttr());
480 auto decl = SymbolTable::lookupNearestSymbolFrom(accOp, symbolRef);
481 auto recipeOp = cast<acc::ReductionRecipeOp>(decl);
482 LLVM_DEBUG(llvm::dbgs() << "materializing: " << reductionOp << "\n"
483 << symbolRef << "\n");
484 if (failed(materialize(reductionOp, recipeOp, accOp, accSupport, policy)))
485 return failure();
486 }
487 }
488 return success();
489}
490
491void ACCRecipeMaterialization::runOnOperation() {
492 ModuleOp moduleOp = getOperation();
493 acc::OpenACCSupport &accSupport = getAnalysis<acc::OpenACCSupport>();
494
496
497 // Materialize all recipes for all compute constructs and loop constructs.
498 bool anyFailed = false;
499 moduleOp.walk([&](Operation *op) {
500 if (anyFailed)
501 return;
503 [&](auto constructOp) {
504 if (failed(materializeForACCOp(constructOp, accSupport, policy)))
505 anyFailed = true;
506 });
507 });
508 if (anyFailed) {
509 signalPassFailure();
510 return;
511 }
512
513 // Remove all recipes.
514 moduleOp.walk([&](Operation *op) {
515 if (auto recipe = dyn_cast<acc::ReductionRecipeOp>(op))
516 removeRecipe(recipe, moduleOp);
517 else if (auto recipe = dyn_cast<acc::PrivateRecipeOp>(op))
518 removeRecipe(recipe, moduleOp);
519 else if (auto recipe = dyn_cast<acc::FirstprivateRecipeOp>(op))
520 removeRecipe(recipe, moduleOp);
521 });
522}
523
524} // 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:210
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:312
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:5279
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