MLIR  22.0.0git
InliningUtils.cpp
Go to the documentation of this file.
1 //===- InliningUtils.cpp ---- Misc utilities for inlining -----------------===//
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 file implements miscellaneous inlining utilities.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
15 #include "mlir/IR/Builders.h"
16 #include "mlir/IR/BuiltinOps.h"
17 #include "mlir/IR/IRMapping.h"
18 #include "mlir/IR/Operation.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/DebugLog.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <optional>
24 
25 #define DEBUG_TYPE "inlining"
26 
27 using namespace mlir;
28 
29 /// Combine `callee` location with `caller` location to create a stack that
30 /// represents the call chain.
31 /// If `callee` location is a `CallSiteLoc`, indicating an existing stack of
32 /// locations, the `caller` location is appended to the end of it, extending
33 /// the chain.
34 /// Otherwise, a single `CallSiteLoc` is created, representing a direct call
35 /// from `caller` to `callee`.
36 static LocationAttr stackLocations(Location callee, Location caller) {
37  Location lastCallee = callee;
38  SmallVector<CallSiteLoc> calleeInliningStack;
39  while (auto nextCallSite = dyn_cast<CallSiteLoc>(lastCallee)) {
40  calleeInliningStack.push_back(nextCallSite);
41  lastCallee = nextCallSite.getCaller();
42  }
43 
44  CallSiteLoc firstCallSite = CallSiteLoc::get(lastCallee, caller);
45  for (CallSiteLoc currentCallSite : reverse(calleeInliningStack))
46  firstCallSite =
47  CallSiteLoc::get(currentCallSite.getCallee(), firstCallSite);
48 
49  return firstCallSite;
50 }
51 
52 /// Remap all locations reachable from the inlined blocks with CallSiteLoc
53 /// locations with the provided caller location.
54 static void
56  Location callerLoc) {
57  DenseMap<Location, LocationAttr> mappedLocations;
58  auto remapLoc = [&](Location loc) {
59  auto [it, inserted] = mappedLocations.try_emplace(loc);
60  // Only query the attribute uniquer once per callsite attribute.
61  if (inserted) {
62  LocationAttr newLoc = stackLocations(loc, callerLoc);
63  it->getSecond() = newLoc;
64  }
65  return it->second;
66  };
67 
68  AttrTypeReplacer attrReplacer;
69  attrReplacer.addReplacement(
70  [&](LocationAttr loc) -> std::pair<LocationAttr, WalkResult> {
71  return {remapLoc(loc), WalkResult::skip()};
72  });
73 
74  for (Block &block : inlinedBlocks) {
75  for (BlockArgument &arg : block.getArguments())
76  if (LocationAttr newLoc = remapLoc(arg.getLoc()))
77  arg.setLoc(newLoc);
78 
79  for (Operation &op : block)
80  attrReplacer.recursivelyReplaceElementsIn(&op, /*replaceAttrs=*/false,
81  /*replaceLocs=*/true);
82  }
83 }
84 
86  IRMapping &mapper) {
87  auto remapOperands = [&](Operation *op) {
88  for (auto &operand : op->getOpOperands())
89  if (auto mappedOp = mapper.lookupOrNull(operand.get()))
90  operand.set(mappedOp);
91  };
92  for (auto &block : inlinedBlocks)
93  block.walk(remapOperands);
94 }
95 
96 //===----------------------------------------------------------------------===//
97 // InlinerInterface
98 //===----------------------------------------------------------------------===//
99 
101  bool wouldBeCloned) const {
102  if (auto *handler = getInterfaceFor(call))
103  return handler->isLegalToInline(call, callable, wouldBeCloned);
104  return false;
105 }
106 
108  bool wouldBeCloned,
109  IRMapping &valueMapping) const {
110  if (auto *handler = getInterfaceFor(dest->getParentOp()))
111  return handler->isLegalToInline(dest, src, wouldBeCloned, valueMapping);
112  return false;
113 }
114 
116  bool wouldBeCloned,
117  IRMapping &valueMapping) const {
118  if (auto *handler = getInterfaceFor(op))
119  return handler->isLegalToInline(op, dest, wouldBeCloned, valueMapping);
120  return false;
121 }
122 
124  auto *handler = getInterfaceFor(op);
125  return handler ? handler->shouldAnalyzeRecursively(op) : true;
126 }
127 
128 /// Handle the given inlined terminator by replacing it with a new operation
129 /// as necessary.
131  auto *handler = getInterfaceFor(op);
132  assert(handler && "expected valid dialect handler");
133  handler->handleTerminator(op, newDest);
134 }
135 
136 /// Handle the given inlined terminator by replacing it with a new operation
137 /// as necessary.
139  ValueRange valuesToRepl) const {
140  auto *handler = getInterfaceFor(op);
141  assert(handler && "expected valid dialect handler");
142  handler->handleTerminator(op, valuesToRepl);
143 }
144 
145 /// Returns true if the inliner can assume a fast path of not creating a
146 /// new block, if there is only one block.
148  iterator_range<Region::iterator> inlinedBlocks) const {
149  if (inlinedBlocks.empty()) {
150  return true;
151  }
152  auto *handler = getInterfaceFor(inlinedBlocks.begin()->getParentOp());
153  assert(handler && "expected valid dialect handler");
154  return handler->allowSingleBlockOptimization(inlinedBlocks);
155 }
156 
158  Operation *callable, Value argument,
159  DictionaryAttr argumentAttrs) const {
160  auto *handler = getInterfaceFor(callable);
161  assert(handler && "expected valid dialect handler");
162  return handler->handleArgument(builder, call, callable, argument,
163  argumentAttrs);
164 }
165 
167  Operation *callable, Value result,
168  DictionaryAttr resultAttrs) const {
169  auto *handler = getInterfaceFor(callable);
170  assert(handler && "expected valid dialect handler");
171  return handler->handleResult(builder, call, callable, result, resultAttrs);
172 }
173 
175  Operation *call, iterator_range<Region::iterator> inlinedBlocks) const {
176  auto *handler = getInterfaceFor(call);
177  assert(handler && "expected valid dialect handler");
178  handler->processInlinedCallBlocks(call, inlinedBlocks);
179 }
180 
181 /// Utility to check that all of the operations within 'src' can be inlined.
182 static bool isLegalToInline(InlinerInterface &interface, Region *src,
183  Region *insertRegion, bool shouldCloneInlinedRegion,
184  IRMapping &valueMapping) {
185  for (auto &block : *src) {
186  for (auto &op : block) {
187  // UnrealizedConversionCastOp is inlineable but cannot implement the
188  // inliner interface due to layering constraints.
189  if (isa<UnrealizedConversionCastOp>(op))
190  continue;
191 
192  // Check this operation.
193  if (!interface.isLegalToInline(&op, insertRegion,
194  shouldCloneInlinedRegion, valueMapping)) {
195  LDBG() << "* Illegal to inline because of op: "
196  << OpWithFlags(&op, OpPrintingFlags().skipRegions());
197  return false;
198  }
199  // Check any nested regions.
200  if (interface.shouldAnalyzeRecursively(&op) &&
201  llvm::any_of(op.getRegions(), [&](Region &region) {
202  return !isLegalToInline(interface, &region, insertRegion,
203  shouldCloneInlinedRegion, valueMapping);
204  }))
205  return false;
206  }
207  }
208  return true;
209 }
210 
211 //===----------------------------------------------------------------------===//
212 // Inline Methods
213 //===----------------------------------------------------------------------===//
214 
215 static void handleArgumentImpl(InlinerInterface &interface, OpBuilder &builder,
216  CallOpInterface call,
217  CallableOpInterface callable,
218  IRMapping &mapper) {
219  // Unpack the argument attributes if there are any.
221  callable.getCallableRegion()->getNumArguments(),
222  builder.getDictionaryAttr({}));
223  if (ArrayAttr arrayAttr = callable.getArgAttrsAttr()) {
224  assert(arrayAttr.size() == argAttrs.size());
225  for (auto [idx, attr] : llvm::enumerate(arrayAttr))
226  argAttrs[idx] = cast<DictionaryAttr>(attr);
227  }
228 
229  // Run the argument attribute handler for the given argument and attribute.
230  for (auto [blockArg, argAttr] :
231  llvm::zip(callable.getCallableRegion()->getArguments(), argAttrs)) {
232  Value newArgument = interface.handleArgument(
233  builder, call, callable, mapper.lookup(blockArg), argAttr);
234  assert(newArgument.getType() == mapper.lookup(blockArg).getType() &&
235  "expected the argument type to not change");
236 
237  // Update the mapping to point the new argument returned by the handler.
238  mapper.map(blockArg, newArgument);
239  }
240 }
241 
242 static void handleResultImpl(InlinerInterface &interface, OpBuilder &builder,
243  CallOpInterface call, CallableOpInterface callable,
244  ValueRange results) {
245  // Unpack the result attributes if there are any.
246  SmallVector<DictionaryAttr> resAttrs(results.size(),
247  builder.getDictionaryAttr({}));
248  if (ArrayAttr arrayAttr = callable.getResAttrsAttr()) {
249  assert(arrayAttr.size() == resAttrs.size());
250  for (auto [idx, attr] : llvm::enumerate(arrayAttr))
251  resAttrs[idx] = cast<DictionaryAttr>(attr);
252  }
253 
254  // Run the result attribute handler for the given result and attribute.
255  for (auto [result, resAttr] : llvm::zip(results, resAttrs)) {
256  // Store the original result users before running the handler.
257  DenseSet<Operation *> resultUsers(llvm::from_range, result.getUsers());
258 
259  Value newResult =
260  interface.handleResult(builder, call, callable, result, resAttr);
261  assert(newResult.getType() == result.getType() &&
262  "expected the result type to not change");
263 
264  // Replace the result uses except for the ones introduce by the handler.
265  result.replaceUsesWithIf(newResult, [&](OpOperand &operand) {
266  return resultUsers.count(operand.getOwner());
267  });
268  }
269 }
270 
271 static LogicalResult inlineRegionImpl(
272  InlinerInterface &interface,
274  Region *src, Block *inlineBlock, Block::iterator inlinePoint,
275  IRMapping &mapper, ValueRange resultsToReplace, TypeRange regionResultTypes,
276  std::optional<Location> inlineLoc, bool shouldCloneInlinedRegion,
277  CallOpInterface call = {}) {
278  assert(resultsToReplace.size() == regionResultTypes.size());
279  // We expect the region to have at least one block.
280  if (src->empty())
281  return failure();
282 
283  // Check that all of the region arguments have been mapped.
284  auto *srcEntryBlock = &src->front();
285  if (llvm::any_of(srcEntryBlock->getArguments(),
286  [&](BlockArgument arg) { return !mapper.contains(arg); }))
287  return failure();
288 
289  // Check that the operations within the source region are valid to inline.
290  Region *insertRegion = inlineBlock->getParent();
291  if (!interface.isLegalToInline(insertRegion, src, shouldCloneInlinedRegion,
292  mapper) ||
293  !isLegalToInline(interface, src, insertRegion, shouldCloneInlinedRegion,
294  mapper))
295  return failure();
296 
297  // Run the argument attribute handler before inlining the callable region.
298  OpBuilder builder(inlineBlock, inlinePoint);
299  auto callable = dyn_cast<CallableOpInterface>(src->getParentOp());
300  if (call && callable)
301  handleArgumentImpl(interface, builder, call, callable, mapper);
302 
303  // Clone the callee's source into the caller.
304  Block *postInsertBlock = inlineBlock->splitBlock(inlinePoint);
305  cloneCallback(builder, src, inlineBlock, postInsertBlock, mapper,
306  shouldCloneInlinedRegion);
307 
308  // Get the range of newly inserted blocks.
309  auto newBlocks = llvm::make_range(std::next(inlineBlock->getIterator()),
310  postInsertBlock->getIterator());
311  Block *firstNewBlock = &*newBlocks.begin();
312 
313  // Remap the locations of the inlined operations if a valid source location
314  // was provided.
315  if (inlineLoc && !llvm::isa<UnknownLoc>(*inlineLoc))
316  remapInlinedLocations(newBlocks, *inlineLoc);
317 
318  // If the blocks were moved in-place, make sure to remap any necessary
319  // operands.
320  if (!shouldCloneInlinedRegion)
321  remapInlinedOperands(newBlocks, mapper);
322 
323  // Process the newly inlined blocks.
324  if (call)
325  interface.processInlinedCallBlocks(call, newBlocks);
326  interface.processInlinedBlocks(newBlocks);
327 
328  bool singleBlockFastPath = interface.allowSingleBlockOptimization(newBlocks);
329 
330  // Handle the case where only a single block was inlined.
331  if (singleBlockFastPath && llvm::hasSingleElement(newBlocks)) {
332  // Run the result attribute handler on the terminator operands.
333  Operation *firstBlockTerminator = firstNewBlock->getTerminator();
334  builder.setInsertionPoint(firstBlockTerminator);
335  if (call && callable)
336  handleResultImpl(interface, builder, call, callable,
337  firstBlockTerminator->getOperands());
338 
339  // Have the interface handle the terminator of this block.
340  interface.handleTerminator(firstBlockTerminator, resultsToReplace);
341  firstBlockTerminator->erase();
342 
343  // Merge the post insert block into the cloned entry block.
344  firstNewBlock->getOperations().splice(firstNewBlock->end(),
345  postInsertBlock->getOperations());
346  postInsertBlock->erase();
347  } else {
348  // Otherwise, there were multiple blocks inlined. Add arguments to the post
349  // insertion block to represent the results to replace.
350  for (const auto &resultToRepl : llvm::enumerate(resultsToReplace)) {
351  resultToRepl.value().replaceAllUsesWith(
352  postInsertBlock->addArgument(regionResultTypes[resultToRepl.index()],
353  resultToRepl.value().getLoc()));
354  }
355 
356  // Run the result attribute handler on the post insertion block arguments.
357  builder.setInsertionPointToStart(postInsertBlock);
358  if (call && callable)
359  handleResultImpl(interface, builder, call, callable,
360  postInsertBlock->getArguments());
361 
362  /// Handle the terminators for each of the new blocks.
363  for (auto &newBlock : newBlocks)
364  interface.handleTerminator(newBlock.getTerminator(), postInsertBlock);
365  }
366 
367  // Splice the instructions of the inlined entry block into the insert block.
368  inlineBlock->getOperations().splice(inlineBlock->end(),
369  firstNewBlock->getOperations());
370  firstNewBlock->erase();
371  return success();
372 }
373 
374 static LogicalResult inlineRegionImpl(
375  InlinerInterface &interface,
377  Region *src, Block *inlineBlock, Block::iterator inlinePoint,
378  ValueRange inlinedOperands, ValueRange resultsToReplace,
379  std::optional<Location> inlineLoc, bool shouldCloneInlinedRegion,
380  CallOpInterface call = {}) {
381  // We expect the region to have at least one block.
382  if (src->empty())
383  return failure();
384 
385  auto *entryBlock = &src->front();
386  if (inlinedOperands.size() != entryBlock->getNumArguments())
387  return failure();
388 
389  // Map the provided call operands to the arguments of the region.
390  IRMapping mapper;
391  for (unsigned i = 0, e = inlinedOperands.size(); i != e; ++i) {
392  // Verify that the types of the provided values match the function argument
393  // types.
394  BlockArgument regionArg = entryBlock->getArgument(i);
395  if (inlinedOperands[i].getType() != regionArg.getType())
396  return failure();
397  mapper.map(regionArg, inlinedOperands[i]);
398  }
399 
400  // Call into the main region inliner function.
401  return inlineRegionImpl(interface, cloneCallback, src, inlineBlock,
402  inlinePoint, mapper, resultsToReplace,
403  resultsToReplace.getTypes(), inlineLoc,
404  shouldCloneInlinedRegion, call);
405 }
406 
407 LogicalResult mlir::inlineRegion(
408  InlinerInterface &interface,
410  Region *src, Operation *inlinePoint, IRMapping &mapper,
411  ValueRange resultsToReplace, TypeRange regionResultTypes,
412  std::optional<Location> inlineLoc, bool shouldCloneInlinedRegion) {
413  return inlineRegion(interface, cloneCallback, src, inlinePoint->getBlock(),
414  ++inlinePoint->getIterator(), mapper, resultsToReplace,
415  regionResultTypes, inlineLoc, shouldCloneInlinedRegion);
416 }
417 
418 LogicalResult mlir::inlineRegion(
419  InlinerInterface &interface,
421  Region *src, Block *inlineBlock, Block::iterator inlinePoint,
422  IRMapping &mapper, ValueRange resultsToReplace, TypeRange regionResultTypes,
423  std::optional<Location> inlineLoc, bool shouldCloneInlinedRegion) {
424  return inlineRegionImpl(
425  interface, cloneCallback, src, inlineBlock, inlinePoint, mapper,
426  resultsToReplace, regionResultTypes, inlineLoc, shouldCloneInlinedRegion);
427 }
428 
429 LogicalResult mlir::inlineRegion(
430  InlinerInterface &interface,
432  Region *src, Operation *inlinePoint, ValueRange inlinedOperands,
433  ValueRange resultsToReplace, std::optional<Location> inlineLoc,
434  bool shouldCloneInlinedRegion) {
435  return inlineRegion(interface, cloneCallback, src, inlinePoint->getBlock(),
436  ++inlinePoint->getIterator(), inlinedOperands,
437  resultsToReplace, inlineLoc, shouldCloneInlinedRegion);
438 }
439 
440 LogicalResult mlir::inlineRegion(
441  InlinerInterface &interface,
443  Region *src, Block *inlineBlock, Block::iterator inlinePoint,
444  ValueRange inlinedOperands, ValueRange resultsToReplace,
445  std::optional<Location> inlineLoc, bool shouldCloneInlinedRegion) {
446  return inlineRegionImpl(interface, cloneCallback, src, inlineBlock,
447  inlinePoint, inlinedOperands, resultsToReplace,
448  inlineLoc, shouldCloneInlinedRegion);
449 }
450 
451 /// Utility function used to generate a cast operation from the given interface,
452 /// or return nullptr if a cast could not be generated.
455  OpBuilder &castBuilder, Value arg, Type type,
456  Location conversionLoc) {
457  if (!interface)
458  return nullptr;
459 
460  // Check to see if the interface for the call can materialize a conversion.
461  Operation *castOp = interface->materializeCallConversion(castBuilder, arg,
462  type, conversionLoc);
463  if (!castOp)
464  return nullptr;
465  castOps.push_back(castOp);
466 
467  // Ensure that the generated cast is correct.
468  assert(castOp->getNumOperands() == 1 && castOp->getOperand(0) == arg &&
469  castOp->getNumResults() == 1 && *castOp->result_type_begin() == type);
470  return castOp->getResult(0);
471 }
472 
473 /// This function inlines a given region, 'src', of a callable operation,
474 /// 'callable', into the location defined by the given call operation. This
475 /// function returns failure if inlining is not possible, success otherwise. On
476 /// failure, no changes are made to the module. 'shouldCloneInlinedRegion'
477 /// corresponds to whether the source region should be cloned into the 'call' or
478 /// spliced directly.
479 LogicalResult mlir::inlineCall(
480  InlinerInterface &interface,
482  CallOpInterface call, CallableOpInterface callable, Region *src,
483  bool shouldCloneInlinedRegion) {
484  // We expect the region to have at least one block.
485  if (src->empty())
486  return failure();
487  auto *entryBlock = &src->front();
488  ArrayRef<Type> callableResultTypes = callable.getResultTypes();
489 
490  // Make sure that the number of arguments and results matchup between the call
491  // and the region.
492  SmallVector<Value, 8> callOperands(call.getArgOperands());
493  SmallVector<Value, 8> callResults(call->getResults());
494  if (callOperands.size() != entryBlock->getNumArguments() ||
495  callResults.size() != callableResultTypes.size())
496  return failure();
497 
498  // A set of cast operations generated to matchup the signature of the region
499  // with the signature of the call.
501  castOps.reserve(callOperands.size() + callResults.size());
502 
503  // Functor used to cleanup generated state on failure.
504  auto cleanupState = [&] {
505  for (auto *op : castOps) {
506  op->getResult(0).replaceAllUsesWith(op->getOperand(0));
507  op->erase();
508  }
509  return failure();
510  };
511 
512  // Builder used for any conversion operations that need to be materialized.
513  OpBuilder castBuilder(call);
514  Location castLoc = call.getLoc();
515  const auto *callInterface = interface.getInterfaceFor(call->getDialect());
516 
517  // Map the provided call operands to the arguments of the region.
518  IRMapping mapper;
519  for (unsigned i = 0, e = callOperands.size(); i != e; ++i) {
520  BlockArgument regionArg = entryBlock->getArgument(i);
521  Value operand = callOperands[i];
522 
523  // If the call operand doesn't match the expected region argument, try to
524  // generate a cast.
525  Type regionArgType = regionArg.getType();
526  if (operand.getType() != regionArgType) {
527  if (!(operand = materializeConversion(callInterface, castOps, castBuilder,
528  operand, regionArgType, castLoc)))
529  return cleanupState();
530  }
531  mapper.map(regionArg, operand);
532  }
533 
534  // Ensure that the resultant values of the call match the callable.
535  castBuilder.setInsertionPointAfter(call);
536  for (unsigned i = 0, e = callResults.size(); i != e; ++i) {
537  Value callResult = callResults[i];
538  if (callResult.getType() == callableResultTypes[i])
539  continue;
540 
541  // Generate a conversion that will produce the original type, so that the IR
542  // is still valid after the original call gets replaced.
543  Value castResult =
544  materializeConversion(callInterface, castOps, castBuilder, callResult,
545  callResult.getType(), castLoc);
546  if (!castResult)
547  return cleanupState();
548  callResult.replaceAllUsesWith(castResult);
549  castResult.getDefiningOp()->replaceUsesOfWith(castResult, callResult);
550  }
551 
552  // Check that it is legal to inline the callable into the call.
553  if (!interface.isLegalToInline(call, callable, shouldCloneInlinedRegion))
554  return cleanupState();
555 
556  // Attempt to inline the call.
557  if (failed(inlineRegionImpl(interface, cloneCallback, src, call->getBlock(),
558  ++call->getIterator(), mapper, callResults,
559  callableResultTypes, call.getLoc(),
560  shouldCloneInlinedRegion, call)))
561  return cleanupState();
562  return success();
563 }
static void remapInlinedOperands(iterator_range< Region::iterator > inlinedBlocks, IRMapping &mapper)
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
static void handleResultImpl(InlinerInterface &interface, OpBuilder &builder, CallOpInterface call, CallableOpInterface callable, ValueRange results)
static LocationAttr stackLocations(Location callee, Location caller)
Combine callee location with caller location to create a stack that represents the call chain.
static LogicalResult inlineRegionImpl(InlinerInterface &interface, function_ref< InlinerInterface::CloneCallbackSigTy > cloneCallback, Region *src, Block *inlineBlock, Block::iterator inlinePoint, IRMapping &mapper, ValueRange resultsToReplace, TypeRange regionResultTypes, std::optional< Location > inlineLoc, bool shouldCloneInlinedRegion, CallOpInterface call={})
static Value materializeConversion(const DialectInlinerInterface *interface, SmallVectorImpl< Operation * > &castOps, OpBuilder &castBuilder, Value arg, Type type, Location conversionLoc)
Utility function used to generate a cast operation from the given interface, or return nullptr if a c...
static void remapInlinedLocations(iterator_range< Region::iterator > inlinedBlocks, Location callerLoc)
Remap all locations reachable from the inlined blocks with CallSiteLoc locations with the provided ca...
static void handleArgumentImpl(InlinerInterface &interface, OpBuilder &builder, CallOpInterface call, CallableOpInterface callable, IRMapping &mapper)
This is an attribute/type replacer that is naively cached.
This class represents an argument of a Block.
Definition: Value.h:309
Block represents an ordered list of Operations.
Definition: Block.h:33
OpListType::iterator iterator
Definition: Block.h:140
void erase()
Unlink this Block from its parent region and delete it.
Definition: Block.cpp:66
Block * splitBlock(iterator splitBefore)
Split the block into two blocks before the specified operation or iterator.
Definition: Block.cpp:318
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition: Block.cpp:27
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:244
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:153
OpListType & getOperations()
Definition: Block.h:137
BlockArgListType getArguments()
Definition: Block.h:87
iterator end()
Definition: Block.h:144
iterator begin()
Definition: Block.h:143
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
Definition: Builders.cpp:99
This is the interface that must be implemented by the dialects of operations to be inlined.
Definition: InliningUtils.h:44
virtual Operation * materializeCallConversion(OpBuilder &builder, Value input, Type resultType, Location conversionLoc) const
Attempt to materialize a conversion for a type mismatch between a call from this dialect,...
const DialectInlinerInterface * getInterfaceFor(Object *obj) const
Get the interface for a given object, or null if one is not registered.
This is a utility class for mapping one set of IR entities to another.
Definition: IRMapping.h:26
auto lookup(T from) const
Lookup a mapped value within the map.
Definition: IRMapping.h:72
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition: IRMapping.h:30
auto lookupOrNull(T from) const
Lookup a mapped value within the map.
Definition: IRMapping.h:58
This interface provides the hooks into the inlining interface.
virtual Value handleResult(OpBuilder &builder, Operation *call, Operation *callable, Value result, DictionaryAttr resultAttrs) const
virtual Value handleArgument(OpBuilder &builder, Operation *call, Operation *callable, Value argument, DictionaryAttr argumentAttrs) const
virtual bool shouldAnalyzeRecursively(Operation *op) const
virtual bool allowSingleBlockOptimization(iterator_range< Region::iterator > inlinedBlocks) const
Returns true if the inliner can assume a fast path of not creating a new block, if there is only one ...
virtual void handleTerminator(Operation *op, Block *newDest) const
Handle the given inlined terminator by replacing it with a new operation as necessary.
virtual void processInlinedCallBlocks(Operation *call, iterator_range< Region::iterator > inlinedBlocks) const
virtual void processInlinedBlocks(iterator_range< Region::iterator > inlinedBlocks)
Process a set of blocks that have been inlined.
virtual bool isLegalToInline(Operation *call, Operation *callable, bool wouldBeCloned) const
These hooks mirror the hooks for the DialectInlinerInterface, with default implementations that call ...
Location objects represent source locations information in MLIR.
Definition: Location.h:32
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:205
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Definition: Builders.h:410
This class represents an operand of an operation.
Definition: Value.h:257
Set of flags used to control the behavior of the various IR print methods (e.g.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Definition: Operation.h:1111
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
void replaceUsesOfWith(Value from, Value to)
Replace any uses of 'from' with 'to' within this operation.
Definition: Operation.cpp:226
Value getOperand(unsigned idx)
Definition: Operation.h:350
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:407
unsigned getNumOperands()
Definition: Operation.h:346
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:213
result_type_iterator result_type_begin()
Definition: Operation.h:426
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:378
void erase()
Remove this operation from its parent block and delete it.
Definition: Operation.cpp:538
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:404
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
bool empty()
Definition: Region.h:60
Block & front()
Definition: Region.h:65
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:105
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
Definition: Value.h:149
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:18
static WalkResult skip()
Definition: WalkResult.h:48
void recursivelyReplaceElementsIn(Operation *op, bool replaceAttrs=true, bool replaceLocs=false, bool replaceTypes=false)
Replace the elements within the given operation, and all nested operations.
void addReplacement(ReplaceFn< Attribute > fn)
Register a replacement function for mapping a given attribute or type.
Operation * getOwner() const
Return the owner of this operand.
Definition: UseDefLists.h:38
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:304
LogicalResult inlineCall(InlinerInterface &interface, function_ref< InlinerInterface::CloneCallbackSigTy > cloneCallback, CallOpInterface call, CallableOpInterface callable, Region *src, bool shouldCloneInlinedRegion=true)
This function inlines a given region, 'src', of a callable operation, 'callable', into the location d...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult inlineRegion(InlinerInterface &interface, function_ref< InlinerInterface::CloneCallbackSigTy > cloneCallback, Region *src, Operation *inlinePoint, IRMapping &mapper, ValueRange resultsToReplace, TypeRange regionResultTypes, std::optional< Location > inlineLoc=std::nullopt, bool shouldCloneInlinedRegion=true)
This function inlines a region, 'src', into another.