MLIR: lib/IR/PatternMatch.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

10 #include "mlir/Config/mlir-config.h"

14 #include "llvm/ADT/SmallPtrSet.h"

15

16 using namespace mlir;

17

18

19

20

21

23 assert(representation == benefit && benefit != ImpossibleToMatchSentinel &&

24 "This pattern match benefit is too large to represent");

25 }

26

29 return representation;

30 }

31

32

33

34

35

36

37

38

39

43 RootKind::OperationName, generatedNames, benefit, context) {}

44

45

46

47

48

51 : Pattern(nullptr, RootKind::Any, generatedNames, benefit, context) {}

52

53

54

55

56

60 : Pattern(interfaceID.getAsOpaquePointer(), RootKind::InterfaceID,

61 generatedNames, benefit, context) {}

62

63

64

65

66

70 : Pattern(traitID.getAsOpaquePointer(), RootKind::TraitID, generatedNames,

71 benefit, context) {}

72

73

74

75

76

80 : rootValue(rootValue), rootKind(rootKind), benefit(benefit),

81 contextAndHasBoundedRecursion(context, false) {

82 if (generatedNames.empty())

83 return;

84 generatedOps.reserve(generatedNames.size());

85 std::transform(generatedNames.begin(), generatedNames.end(),

86 std::back_inserter(generatedOps), [context](StringRef name) {

87 return OperationName(name, context);

88 });

89 }

90

91

92

93

94

95

96 void RewritePattern::anchor() {}

97

98

99

100

101

104 }

105

107

108 }

109

111

112 if (auto *rewriteListener = dyn_cast_if_present(listener))

113 rewriteListener->notifyOperationReplaced(from, to);

114

116 }

117

119

120 if (auto *rewriteListener = dyn_cast_if_present(listener))

121 rewriteListener->notifyOperationReplaced(from, to);

122

124 }

125

126

127

128

130 assert(op->getNumResults() == newValues.size() &&

131 "incorrect # of replacement values");

132

133

135

136

138 }

139

140

141

142

144 assert(op && newOp && "expected non-null op");

146 "ops have different number of results");

147

148

150

151

153 }

154

155

156

158 assert(op->use_empty() && "expected 'op' to have no uses");

159 auto *rewriteListener = dyn_cast_if_present(listener);

160

161

162 if (!rewriteListener) {

164 return;

165 }

166

167

168 auto eraseSingleOp = [&](Operation *op) {

169 #ifndef NDEBUG

170

171 assert(

172 llvm::all_of(op->getRegions(), [&](Region &r) { return r.empty(); }) &&

173 "expected empty regions");

174

175

178 "expected that op has no uses");

179 #endif

180 rewriteListener->notifyOperationErased(op);

181

182

185 };

186

187

188

189

191

193

194

195

196

197

198 while (!r.empty()) {

200

201

203 for (Block *b : llvm::post_order_ext(&r.front(), visited)) {

204

207 eraseTree(&op);

208

209

210 erasedBlocks.push_back(b);

211 }

212 for (Block *b : erasedBlocks) {

213

214

216 bbArg.dropAllUses();

217 b->dropAllUses();

219 }

220 }

221 }

222

223 eraseSingleOp(op);

224 };

225

226 eraseTree(op);

227 }

228

230 assert(block->use_empty() && "expected 'block' to have no uses");

231

232 for (auto &op : llvm::make_early_inc_range(llvm::reverse(*block))) {

233 assert(op.use_empty() && "expected 'op' to have no uses");

235 }

236

237

238 if (auto *rewriteListener = dyn_cast_if_present(listener))

239 rewriteListener->notifyBlockErased(block);

240

242 }

243

245

246 if (auto *rewriteListener = dyn_cast_if_present(listener))

247 rewriteListener->notifyOperationModified(op);

248 }

249

254 return !preservedUsers.contains(user);

255 });

256 }

257

260 bool *allUsesReplaced) {

261 bool allReplaced = true;

262 for (OpOperand &operand : llvm::make_early_inc_range(from.getUses())) {

263 bool replace = functor(operand);

264 if (replace)

265 modifyOpInPlace(operand.getOwner(), [&]() { operand.set(to); });

266 allReplaced &= replace;

267 }

268 if (allUsesReplaced)

269 *allUsesReplaced = allReplaced;

270 }

271

274 bool *allUsesReplaced) {

275 assert(from.size() == to.size() && "incorrect number of replacements");

276 bool allReplaced = true;

277 for (auto it : llvm::zip_equal(from, to)) {

278 bool r;

280 &r);

281 allReplaced &= r;

282 }

283 if (allUsesReplaced)

284 *allUsesReplaced = allReplaced;

285 }

286

291 "incorrect # of argument replacement values");

292

293

294

296 "expected 'source' to have no predecessors");

297

298 if (dest->end() != before) {

299

300

301

303 "expected 'source' to have no successors");

304 } else {

305

306

307

308 assert(dest->hasNoSuccessors() && "expected 'dest' to have no successors");

309 }

310

311

312 for (auto it : llvm::zip(source->getArguments(), argValues))

314

315

316

318

320 } else {

321 while (!source->empty())

323 }

324

325

326 assert(source->empty() && "expected 'source' to be empty");

328 }

329

333 }

334

338 }

339

340

341

343

346

347

349 Block *newBlock =

351

352

353 if (before == block->end())

354 return newBlock;

355

356

357

358 while (before->getBlock() != newBlock)

360

361 return newBlock;

362 }

363

364

365

366

367

370

373 return;

374 }

375

376

377 while (!region.empty())

379 }

382 }

383

386 anotherBlock->getIterator());

387 }

388

392 Region::iterator nextIterator = std::next(block->getIterator());

396 nextIterator);

397 }

398

401 }

402

406 Block::iterator nextIterator = std::next(op->getIterator());

410 op, InsertPoint(currentBlock, nextIterator));

411 }

412

415 }

416

419 assert(iterator != block->end() && "cannot move after end of block");

420 moveOpBefore(op, block, std::next(iterator));

421 }

This class represents an argument of a Block.

Block represents an ordered list of Operations.

OpListType::iterator iterator

bool hasNoSuccessors()

Returns true if this blocks has no successors.

unsigned getNumArguments()

void erase()

Unlink this Block from its parent region and delete it.

Block * splitBlock(iterator splitBefore)

Split the block into two blocks before the specified operation or iterator.

Region * getParent() const

Provide a 'getParent' method for ilist_node_with_parent methods.

OpListType & getOperations()

BlockArgListType getArguments()

void moveBefore(Block *block)

Unlink this block from its current region and insert it right before the specific block.

bool hasNoPredecessors()

Return true if this block has no predecessors.

bool use_empty() const

Returns true if this value has no uses.

MLIRContext is the top-level object for a collection of MLIR operations.

This class represents a saved insertion point.

RAII guard to reset the insertion point of the builder when destroyed.

Listener * listener

The optional listener for events of this builder.

Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes=std::nullopt, ArrayRef< Location > locs=std::nullopt)

Add new block with 'argTypes' arguments and set the insertion point to the end of it.

This class represents an operand of an operation.

Operation is the basic unit of execution within MLIR.

bool use_empty()

Returns true if this operation has no uses.

void dropAllUses()

Drop all uses of results of this operation.

Operation * getParentOp()

Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...

Block * getBlock()

Returns the operation block that contains this operation.

MutableArrayRef< Region > getRegions()

Returns the regions held by this operation.

void moveBefore(Operation *existingOp)

Unlink this operation from its current block and insert it right before existingOp which may be in th...

Region * getParentRegion()

Returns the region to which the instruction belongs.

result_range getResults()

void erase()

Remove this operation from its parent block and delete it.

unsigned getNumResults()

Return the number of results held by this operation.

This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...

bool isImpossibleToMatch() const

unsigned short getBenefit() const

If the corresponding pattern can match, return its benefit. If the.

This class contains all of the data related to a pattern, but does not contain any methods or logic f...

Pattern(StringRef rootName, PatternBenefit benefit, MLIRContext *context, ArrayRef< StringRef > generatedNames={})

Construct a pattern with a certain benefit that matches the operation with the given root name.

This class contains a list of basic blocks and a link to the parent operation it is attached to.

BlockListType & getBlocks()

BlockListType::iterator iterator

virtual void eraseBlock(Block *block)

This method erases all operations in a block.

Block * splitBlock(Block *block, Block::iterator before)

Split the operations starting at "before" (inclusive) out of the given block into a new block,...

virtual void replaceOp(Operation *op, ValueRange newValues)

Replace the results of the given (original) operation with the specified list of values (replacements...

void moveBlockBefore(Block *block, Block *anotherBlock)

Unlink this block and insert it right before existingBlock.

void replaceAllUsesWith(Value from, Value to)

Find uses of from and replace them with to.

void mergeBlocks(Block *source, Block *dest, ValueRange argValues=std::nullopt)

Inline the operations of block 'source' into the end of block 'dest'.

virtual void finalizeOpModification(Operation *op)

This method is used to signal the end of an in-place modification of the given operation.

virtual void eraseOp(Operation *op)

This method erases an operation that is known to have no uses.

void replaceUsesWithIf(Value from, Value to, function_ref< bool(OpOperand &)> functor, bool *allUsesReplaced=nullptr)

Find uses of from and replace them with to if the functor returns true.

void replaceAllUsesExcept(Value from, Value to, Operation *exceptedUser)

Find uses of from and replace them with to except if the user is exceptedUser.

void moveOpBefore(Operation *op, Operation *existingOp)

Unlink this operation from its current block and insert it right before existingOp which may be in th...

void modifyOpInPlace(Operation *root, CallableT &&callable)

This method is a utility wrapper around an in-place modification of an operation.

void moveOpAfter(Operation *op, Operation *existingOp)

Unlink this operation from its current block and insert it right after existingOp which may be in the...

void inlineRegionBefore(Region &region, Region &parent, Region::iterator before)

Move the blocks that belong to "region" before the given position in another region "parent".

virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues=std::nullopt)

Inline the operations of block 'source' into block 'dest' before the given position.

void replaceAllOpUsesWith(Operation *from, ValueRange to)

Find uses of from and replace them with to.

This class provides an efficient unique identifier for a specific C++ type.

This class provides an abstraction over the different types of ranges over Values.

This class represents an instance of an SSA value in the MLIR system, representing a computable value...

use_range getUses() const

Returns a range of all uses, which is useful for iterating over all uses.

Operation * getOwner() const

Return the owner of this operand.

Include the generated interface declarations.

bool mayBeGraphRegion(Region &region)

Return "true" if the given region may be a graph region without SSA dominance.

@ RewriterBaseListener

RewriterBase::Listener or user-derived class.

This class represents a listener that may be used to hook into various actions within an OpBuilder.

virtual void notifyBlockInserted(Block *block, Region *previous, Region::iterator previousIt)

Notify the listener that the specified block was inserted.

virtual void notifyOperationInserted(Operation *op, InsertPoint previous)

Notify the listener that the specified operation was inserted.

This class acts as a special tag that makes the desire to match "any" operation type explicit.

This class acts as a special tag that makes the desire to match any operation that implements a given...

This class acts as a special tag that makes the desire to match any operation that implements a given...

static constexpr auto makeIterable(RangeT &&range)

static bool classof(const OpBuilder::Listener *base)