MLIR: lib/Transforms/Utils/FoldUtils.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

15

19

20 using namespace mlir;

21

22

23

26 Block *insertionBlock) {

28

29

30

33 !parentOp->getBlock())

34 return region;

35

36

37 auto *interface = interfaces.getInterfaceFor(parentOp);

38 if (LLVM_UNLIKELY(interface && interface->shouldMaterializeInto(region)))

39 return region;

40

41

42 insertionBlock = parentOp->getBlock();

43 }

44 llvm_unreachable("expected valid insertion region");

45 }

46

47

48

49

54 (void)insertPt;

55

56

57 if (auto *constOp = dialect->materializeConstant(builder, value, type, loc)) {

60 return constOp;

61 }

62

63 return nullptr;

64 }

65

66

67

68

69

71 if (inPlaceUpdate)

72 *inPlaceUpdate = false;

73

74

75

76 if (isFolderOwnedConstant(op)) {

77

78

80 if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode())) {

82 op->setLoc(erasedFoldedLocation);

83 }

84 return failure();

85 }

86

87

89 if (failed(tryToFold(op, results)))

90 return failure();

91

92

93 if (results.empty()) {

94 if (inPlaceUpdate)

95 *inPlaceUpdate = true;

96 if (auto *rewriteListener = dyn_cast_if_presentRewriterBase::Listener(

98

99 rewriteListener->notifyOperationModified(op);

100 }

101 return success();

102 }

103

104

105

108 return success();

109 }

110

113

114

115

116 if (isFolderOwnedConstant(op)) {

117 if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode())) {

119 op->setLoc(erasedFoldedLocation);

120 }

121 return true;

122 }

123

124

125 if (!constValue) {

127 assert(constValue && "expected `op` to be a constant");

128 } else {

129

130 #ifndef NDEBUG

133 assert(

134 expectedValue == constValue &&

135 "provided constant value was not the expected value of the constant");

136 #endif

137 }

138

139

141 auto &uniquedConstants = foldScopes[insertRegion];

142 Operation *&folderConstOp = uniquedConstants[std::make_tuple(

144

145

146 if (folderConstOp) {

149 folderConstOp->setLoc(erasedFoldedLocation);

150 return false;

151 }

152

153

154

155

156

157 Block *insertBlock = &insertRegion->front();

158 if (opBlock != insertBlock || (&insertBlock->front() != op &&

159 !isFolderOwnedConstant(op->getPrevNode()))) {

161 op->setLoc(erasedFoldedLocation);

162 }

163

164 folderConstOp = op;

165 referencedDialects[op].push_back(op->getDialect());

166 return true;

167 }

168

169

170

172

173 auto it = referencedDialects.find(op);

174 if (it == referencedDialects.end())

175 return;

176

177

178

181 assert(constValue);

182

183

184 auto &uniquedConstants =

186

187

189 for (auto *dialect : it->second)

190 uniquedConstants.erase(std::make_tuple(dialect, constValue, type));

191 referencedDialects.erase(it);

192 }

193

194

196 foldScopes.clear();

197 referencedDialects.clear();

198 }

199

200

201

204

206 auto &entry = insertRegion->front();

208

209

210

211 auto &uniquedConstants = foldScopes[insertRegion];

212 Operation *constOp = tryGetOrCreateConstant(uniquedConstants, dialect, value,

213 type, erasedFoldedLocation);

215 }

216

217 bool OperationFolder::isFolderOwnedConstant(Operation *op) const {

218 return referencedDialects.count(op);

219 }

220

221

222

226 if (failed(op->fold(foldResults)) ||

227 failed(processFoldResults(op, results, foldResults)))

228 return failure();

229 return success();

230 }

231

232 LogicalResult

233 OperationFolder::processFoldResults(Operation *op,

236

237 if (foldResults.empty())

238 return success();

239 assert(foldResults.size() == op->getNumResults());

240

241

242

244 auto &entry = insertRegion->front();

246

247

248 auto &uniquedConstants = foldScopes[insertRegion];

249

250

252 for (unsigned i = 0, e = op->getNumResults(); i != e; ++i) {

253 assert(!foldResults[i].isNull() && "expected valid OpFoldResult");

254

255

256 if (auto repl = llvm::dyn_cast_if_present(foldResults[i])) {

257 results.emplace_back(repl);

258 continue;

259 }

260

261

263 Attribute attrRepl = cast(foldResults[i]);

264 if (auto *constOp =

265 tryGetOrCreateConstant(uniquedConstants, dialect, attrRepl,

266 res.getType(), erasedFoldedLocation)) {

267

268

269

271 if (opBlock == constOp->getBlock() && &opBlock->front() != constOp)

273

274 results.push_back(constOp->getResult(0));

275 continue;

276 }

277

278

279 for (Operation &op : llvm::make_early_inc_range(

280 llvm::make_range(entry.begin(), rewriter.getInsertionPoint()))) {

283 }

284

285 results.clear();

286 return failure();

287 }

288

289 return success();

290 }

291

292

293

295 OperationFolder::tryGetOrCreateConstant(ConstantMap &uniquedConstants,

298

299 auto constKey = std::make_tuple(dialect, value, type);

300 Operation *&constOp = uniquedConstants[constKey];

301 if (constOp) {

302 if (loc != constOp->getLoc())

303 constOp->setLoc(erasedFoldedLocation);

304 return constOp;

305 }

306

307

308 if (!(constOp = materializeConstant(dialect, rewriter, value, type, loc)))

309 return nullptr;

310

311

312 auto *newDialect = constOp->getDialect();

313 if (newDialect == dialect) {

314 referencedDialects[constOp].push_back(dialect);

315 return constOp;

316 }

317

318

319

320 auto newKey = std::make_tuple(newDialect, value, type);

321

322

323

324 if (auto *existingOp = uniquedConstants.lookup(newKey)) {

326 rewriter.eraseOp(constOp);

327 referencedDialects[existingOp].push_back(dialect);

328 if (loc != existingOp->getLoc())

329 existingOp->setLoc(erasedFoldedLocation);

330 return constOp = existingOp;

331 }

332

333

334 referencedDialects[constOp].assign({dialect, newDialect});

335 auto newIt = uniquedConstants.insert({newKey, constOp});

336 return newIt.first->second;

337 }

static Operation * materializeConstant(Dialect *dialect, OpBuilder &builder, Attribute value, Type type, Location loc)

A utility function used to materialize a constant for a given attribute and type.

static Region * getInsertionRegion(DialectInterfaceCollection< DialectFoldInterface > &interfaces, Block *insertionBlock)

Given an operation, find the parent region that folded constants should be inserted into.

Attributes are known-constant values of operations.

Block represents an ordered list of Operations.

Region * getParent() const

Provide a 'getParent' method for ilist_node_with_parent methods.

void moveBefore(Block *block)

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

A collection of dialect interfaces within a context, for a given concrete interface type.

Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...

virtual Operation * materializeConstant(OpBuilder &builder, Attribute value, Type type, Location loc)

Registered hook to materialize a single constant operation from a given attribute value with the desi...

This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...

This class helps build Operations.

Block::iterator getInsertionPoint() const

Returns the current insertion point of the builder.

void setInsertionPointToStart(Block *block)

Sets the insertion point to the start of the specified block.

Listener * getListener() const

Returns the current listener of this builder, or nullptr if this builder doesn't have a listener.

This class provides the API for ops that are known to be isolated from above.

Value getOrCreateConstant(Block *block, Dialect *dialect, Attribute value, Type type)

Get or create a constant for use in the specified block.

void clear()

Clear out any constants cached inside of the folder.

LogicalResult tryToFold(Operation *op, bool *inPlaceUpdate=nullptr)

Tries to perform folding on the given op, including unifying deduplicated constants.

void notifyRemoval(Operation *op)

Notifies that the given constant op should be remove from this OperationFolder's internal bookkeeping...

bool insertKnownConstant(Operation *op, Attribute constValue={})

Tries to fold a pre-existing constant operation.

Operation is the basic unit of execution within MLIR.

void setLoc(Location loc)

Set the source location the operation was defined or derived from.

LogicalResult fold(ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)

Attempt to fold this operation with the specified constant operand values.

Dialect * getDialect()

Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...

OpResult getResult(unsigned idx)

Get the 'idx'th result of this operation.

Location getLoc()

The source location the operation was defined or derived from.

Block * getBlock()

Returns the operation block that contains this operation.

result_type_iterator result_type_begin()

void moveBefore(Operation *existingOp)

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

result_range getResults()

unsigned getNumResults()

Return the number of results held by this operation.

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

Operation * getParentOp()

Return the parent operation this region is attached to.

virtual void replaceOp(Operation *op, ValueRange newValues)

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

virtual void eraseOp(Operation *op)

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

Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...

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

Type getType() const

Return the type of this value.

Include the generated interface declarations.

bool matchPattern(Value value, const Pattern &pattern)

Entry point for matching a pattern over a Value.

detail::constant_op_matcher m_Constant()

Matches a constant foldable operation.