11982afb1SRiver Riddle //===- FoldUtils.cpp ---- Fold Utilities ----------------------------------===//
21982afb1SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61982afb1SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
81982afb1SRiver Riddle //
91982afb1SRiver Riddle // This file defines various operation fold utilities. These utilities are
101982afb1SRiver Riddle // intended to be used by passes to unify and simply their logic.
111982afb1SRiver Riddle //
121982afb1SRiver Riddle //===----------------------------------------------------------------------===//
131982afb1SRiver Riddle 
141982afb1SRiver Riddle #include "mlir/Transforms/FoldUtils.h"
151982afb1SRiver Riddle 
161982afb1SRiver Riddle #include "mlir/IR/Builders.h"
171982afb1SRiver Riddle #include "mlir/IR/Matchers.h"
181982afb1SRiver Riddle #include "mlir/IR/Operation.h"
191982afb1SRiver Riddle 
201982afb1SRiver Riddle using namespace mlir;
211982afb1SRiver Riddle 
2266ed7d6dSRiver Riddle /// Given an operation, find the parent region that folded constants should be
2366ed7d6dSRiver Riddle /// inserted into.
24b28e3db8SMehdi Amini static Region *
getInsertionRegion(DialectInterfaceCollection<DialectFoldInterface> & interfaces,Block * insertionBlock)25b28e3db8SMehdi Amini getInsertionRegion(DialectInterfaceCollection<DialectFoldInterface> &interfaces,
2604f2b717SMaheshRavishankar                    Block *insertionBlock) {
2704f2b717SMaheshRavishankar   while (Region *region = insertionBlock->getParent()) {
2866ed7d6dSRiver Riddle     // Insert in this region for any of the following scenarios:
2966ed7d6dSRiver Riddle     //  * The parent is unregistered, or is known to be isolated from above.
3066ed7d6dSRiver Riddle     //  * The parent is a top-level operation.
311e429540SRiver Riddle     auto *parentOp = region->getParentOp();
32fe7c0d90SRiver Riddle     if (parentOp->mightHaveTrait<OpTrait::IsIsolatedFromAbove>() ||
33474e3541SRiver Riddle         !parentOp->getBlock())
3466ed7d6dSRiver Riddle       return region;
356563b1c4SRiver Riddle 
366563b1c4SRiver Riddle     // Otherwise, check if this region is a desired insertion region.
376563b1c4SRiver Riddle     auto *interface = interfaces.getInterfaceFor(parentOp);
386563b1c4SRiver Riddle     if (LLVM_UNLIKELY(interface && interface->shouldMaterializeInto(region)))
396563b1c4SRiver Riddle       return region;
406563b1c4SRiver Riddle 
4166ed7d6dSRiver Riddle     // Traverse up the parent looking for an insertion region.
4204f2b717SMaheshRavishankar     insertionBlock = parentOp->getBlock();
4366ed7d6dSRiver Riddle   }
4466ed7d6dSRiver Riddle   llvm_unreachable("expected valid insertion region");
4566ed7d6dSRiver Riddle }
4666ed7d6dSRiver Riddle 
4766ed7d6dSRiver Riddle /// A utility function used to materialize a constant for a given attribute and
4866ed7d6dSRiver Riddle /// type. On success, a valid constant value is returned. Otherwise, null is
4966ed7d6dSRiver Riddle /// returned
materializeConstant(Dialect * dialect,OpBuilder & builder,Attribute value,Type type,Location loc)5066ed7d6dSRiver Riddle static Operation *materializeConstant(Dialect *dialect, OpBuilder &builder,
5166ed7d6dSRiver Riddle                                       Attribute value, Type type,
5266ed7d6dSRiver Riddle                                       Location loc) {
5366ed7d6dSRiver Riddle   auto insertPt = builder.getInsertionPoint();
5466ed7d6dSRiver Riddle   (void)insertPt;
5566ed7d6dSRiver Riddle 
5666ed7d6dSRiver Riddle   // Ask the dialect to materialize a constant operation for this value.
5766ed7d6dSRiver Riddle   if (auto *constOp = dialect->materializeConstant(builder, value, type, loc)) {
5866ed7d6dSRiver Riddle     assert(insertPt == builder.getInsertionPoint());
59907403f3SRiver Riddle     assert(matchPattern(constOp, m_Constant()));
6066ed7d6dSRiver Riddle     return constOp;
6166ed7d6dSRiver Riddle   }
62444822d7SSean Silva 
6366ed7d6dSRiver Riddle   return nullptr;
6466ed7d6dSRiver Riddle }
6566ed7d6dSRiver Riddle 
669b4a02c1SRiver Riddle //===----------------------------------------------------------------------===//
679b4a02c1SRiver Riddle // OperationFolder
689b4a02c1SRiver Riddle //===----------------------------------------------------------------------===//
691982afb1SRiver Riddle 
tryToFold(Operation * op,function_ref<void (Operation *)> processGeneratedConstants,function_ref<void (Operation *)> preReplaceAction,bool * inPlaceUpdate)70bcacef1aSRiver Riddle LogicalResult OperationFolder::tryToFold(
714562e389SRiver Riddle     Operation *op, function_ref<void(Operation *)> processGeneratedConstants,
72cbcb12fdSUday Bondhugula     function_ref<void(Operation *)> preReplaceAction, bool *inPlaceUpdate) {
73cbcb12fdSUday Bondhugula   if (inPlaceUpdate)
74cbcb12fdSUday Bondhugula     *inPlaceUpdate = false;
75cbcb12fdSUday Bondhugula 
76bcacef1aSRiver Riddle   // If this is a unique'd constant, return failure as we know that it has
77bcacef1aSRiver Riddle   // already been folded.
78*af371f9fSRiver Riddle   if (isFolderOwnedConstant(op)) {
79*af371f9fSRiver Riddle     // Check to see if we should rehoist, i.e. if a non-constant operation was
80*af371f9fSRiver Riddle     // inserted before this one.
81*af371f9fSRiver Riddle     Block *opBlock = op->getBlock();
82*af371f9fSRiver Riddle     if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode()))
83*af371f9fSRiver Riddle       op->moveBefore(&opBlock->front());
84bcacef1aSRiver Riddle     return failure();
85*af371f9fSRiver Riddle   }
861982afb1SRiver Riddle 
879b4a02c1SRiver Riddle   // Try to fold the operation.
88e62a6956SRiver Riddle   SmallVector<Value, 8> results;
8904f2b717SMaheshRavishankar   OpBuilder builder(op);
9004f2b717SMaheshRavishankar   if (failed(tryToFold(builder, op, results, processGeneratedConstants)))
919b4a02c1SRiver Riddle     return failure();
929b4a02c1SRiver Riddle 
939b4a02c1SRiver Riddle   // Check to see if the operation was just updated in place.
94cbcb12fdSUday Bondhugula   if (results.empty()) {
95cbcb12fdSUday Bondhugula     if (inPlaceUpdate)
96cbcb12fdSUday Bondhugula       *inPlaceUpdate = true;
979b4a02c1SRiver Riddle     return success();
98cbcb12fdSUday Bondhugula   }
999b4a02c1SRiver Riddle 
1000ddd0439SUday Bondhugula   // Constant folding succeeded. We will start replacing this op's uses and
1010ddd0439SUday Bondhugula   // erase this op. Invoke the callback provided by the caller to perform any
1020ddd0439SUday Bondhugula   // pre-replacement action.
1030ddd0439SUday Bondhugula   if (preReplaceAction)
1040ddd0439SUday Bondhugula     preReplaceAction(op);
1050ddd0439SUday Bondhugula 
1060ddd0439SUday Bondhugula   // Replace all of the result values and erase the operation.
1079b4a02c1SRiver Riddle   for (unsigned i = 0, e = results.size(); i != e; ++i)
1082bdf33ccSRiver Riddle     op->getResult(i).replaceAllUsesWith(results[i]);
1099b4a02c1SRiver Riddle   op->erase();
1109b4a02c1SRiver Riddle   return success();
1119b4a02c1SRiver Riddle }
1129b4a02c1SRiver Riddle 
insertKnownConstant(Operation * op,Attribute constValue)113*af371f9fSRiver Riddle bool OperationFolder::insertKnownConstant(Operation *op, Attribute constValue) {
114*af371f9fSRiver Riddle   Block *opBlock = op->getBlock();
115*af371f9fSRiver Riddle 
116*af371f9fSRiver Riddle   // If this is a constant we unique'd, we don't need to insert, but we can
117*af371f9fSRiver Riddle   // check to see if we should rehoist it.
118*af371f9fSRiver Riddle   if (isFolderOwnedConstant(op)) {
119*af371f9fSRiver Riddle     if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode()))
120*af371f9fSRiver Riddle       op->moveBefore(&opBlock->front());
121*af371f9fSRiver Riddle     return true;
122*af371f9fSRiver Riddle   }
123*af371f9fSRiver Riddle 
124*af371f9fSRiver Riddle   // Get the constant value of the op if necessary.
125*af371f9fSRiver Riddle   if (!constValue) {
126*af371f9fSRiver Riddle     matchPattern(op, m_Constant(&constValue));
127*af371f9fSRiver Riddle     assert(constValue && "expected `op` to be a constant");
128*af371f9fSRiver Riddle   } else {
129*af371f9fSRiver Riddle     // Ensure that the provided constant was actually correct.
130*af371f9fSRiver Riddle #ifndef NDEBUG
131*af371f9fSRiver Riddle     Attribute expectedValue;
132*af371f9fSRiver Riddle     matchPattern(op, m_Constant(&expectedValue));
133*af371f9fSRiver Riddle     assert(
134*af371f9fSRiver Riddle         expectedValue == constValue &&
135*af371f9fSRiver Riddle         "provided constant value was not the expected value of the constant");
136*af371f9fSRiver Riddle #endif
137*af371f9fSRiver Riddle   }
138*af371f9fSRiver Riddle 
139*af371f9fSRiver Riddle   // Check for an existing constant operation for the attribute value.
140*af371f9fSRiver Riddle   Region *insertRegion = getInsertionRegion(interfaces, opBlock);
141*af371f9fSRiver Riddle   auto &uniquedConstants = foldScopes[insertRegion];
142*af371f9fSRiver Riddle   Operation *&folderConstOp = uniquedConstants[std::make_tuple(
143*af371f9fSRiver Riddle       op->getDialect(), constValue, *op->result_type_begin())];
144*af371f9fSRiver Riddle 
145*af371f9fSRiver Riddle   // If there is an existing constant, replace `op`.
146*af371f9fSRiver Riddle   if (folderConstOp) {
147*af371f9fSRiver Riddle     op->replaceAllUsesWith(folderConstOp);
148*af371f9fSRiver Riddle     op->erase();
149*af371f9fSRiver Riddle     return false;
150*af371f9fSRiver Riddle   }
151*af371f9fSRiver Riddle 
152*af371f9fSRiver Riddle   // Otherwise, we insert `op`. If `op` is in the insertion block and is either
153*af371f9fSRiver Riddle   // already at the front of the block, or the previous operation is already a
154*af371f9fSRiver Riddle   // constant we unique'd (i.e. one we inserted), then we don't need to do
155*af371f9fSRiver Riddle   // anything. Otherwise, we move the constant to the insertion block.
156*af371f9fSRiver Riddle   Block *insertBlock = &insertRegion->front();
157*af371f9fSRiver Riddle   if (opBlock != insertBlock || (&insertBlock->front() != op &&
158*af371f9fSRiver Riddle                                  !isFolderOwnedConstant(op->getPrevNode())))
159*af371f9fSRiver Riddle     op->moveBefore(&insertBlock->front());
160*af371f9fSRiver Riddle 
161*af371f9fSRiver Riddle   folderConstOp = op;
162*af371f9fSRiver Riddle   referencedDialects[op].push_back(op->getDialect());
163*af371f9fSRiver Riddle   return true;
164*af371f9fSRiver Riddle }
165*af371f9fSRiver Riddle 
166bcacef1aSRiver Riddle /// Notifies that the given constant `op` should be remove from this
167bcacef1aSRiver Riddle /// OperationFolder's internal bookkeeping.
notifyRemoval(Operation * op)168bcacef1aSRiver Riddle void OperationFolder::notifyRemoval(Operation *op) {
169bcacef1aSRiver Riddle   // Check to see if this operation is uniqued within the folder.
170bcacef1aSRiver Riddle   auto it = referencedDialects.find(op);
171bcacef1aSRiver Riddle   if (it == referencedDialects.end())
172bcacef1aSRiver Riddle     return;
173bcacef1aSRiver Riddle 
174bcacef1aSRiver Riddle   // Get the constant value for this operation, this is the value that was used
175bcacef1aSRiver Riddle   // to unique the operation internally.
176bcacef1aSRiver Riddle   Attribute constValue;
177bcacef1aSRiver Riddle   matchPattern(op, m_Constant(&constValue));
178bcacef1aSRiver Riddle   assert(constValue);
179bcacef1aSRiver Riddle 
18066ed7d6dSRiver Riddle   // Get the constant map that this operation was uniqued in.
18104f2b717SMaheshRavishankar   auto &uniquedConstants =
18204f2b717SMaheshRavishankar       foldScopes[getInsertionRegion(interfaces, op->getBlock())];
18366ed7d6dSRiver Riddle 
184bcacef1aSRiver Riddle   // Erase all of the references to this operation.
1852bdf33ccSRiver Riddle   auto type = op->getResult(0).getType();
186bcacef1aSRiver Riddle   for (auto *dialect : it->second)
187bcacef1aSRiver Riddle     uniquedConstants.erase(std::make_tuple(dialect, constValue, type));
188bcacef1aSRiver Riddle   referencedDialects.erase(it);
189bcacef1aSRiver Riddle }
190bcacef1aSRiver Riddle 
1910ddba0bdSRiver Riddle /// Clear out any constants cached inside of the folder.
clear()1920ddba0bdSRiver Riddle void OperationFolder::clear() {
1930ddba0bdSRiver Riddle   foldScopes.clear();
1940ddba0bdSRiver Riddle   referencedDialects.clear();
1950ddba0bdSRiver Riddle }
1960ddba0bdSRiver Riddle 
197152d29ccSRiver Riddle /// Get or create a constant using the given builder. On success this returns
198152d29ccSRiver Riddle /// the constant operation, nullptr otherwise.
getOrCreateConstant(OpBuilder & builder,Dialect * dialect,Attribute value,Type type,Location loc)199152d29ccSRiver Riddle Value OperationFolder::getOrCreateConstant(OpBuilder &builder, Dialect *dialect,
200152d29ccSRiver Riddle                                            Attribute value, Type type,
201152d29ccSRiver Riddle                                            Location loc) {
202152d29ccSRiver Riddle   OpBuilder::InsertionGuard foldGuard(builder);
203152d29ccSRiver Riddle 
204152d29ccSRiver Riddle   // Use the builder insertion block to find an insertion point for the
205152d29ccSRiver Riddle   // constant.
206152d29ccSRiver Riddle   auto *insertRegion =
207152d29ccSRiver Riddle       getInsertionRegion(interfaces, builder.getInsertionBlock());
208152d29ccSRiver Riddle   auto &entry = insertRegion->front();
209152d29ccSRiver Riddle   builder.setInsertionPoint(&entry, entry.begin());
210152d29ccSRiver Riddle 
211152d29ccSRiver Riddle   // Get the constant map for the insertion region of this operation.
212152d29ccSRiver Riddle   auto &uniquedConstants = foldScopes[insertRegion];
213152d29ccSRiver Riddle   Operation *constOp = tryGetOrCreateConstant(uniquedConstants, dialect,
214152d29ccSRiver Riddle                                               builder, value, type, loc);
215152d29ccSRiver Riddle   return constOp ? constOp->getResult(0) : Value();
216152d29ccSRiver Riddle }
217152d29ccSRiver Riddle 
isFolderOwnedConstant(Operation * op) const218*af371f9fSRiver Riddle bool OperationFolder::isFolderOwnedConstant(Operation *op) const {
219*af371f9fSRiver Riddle   return referencedDialects.count(op);
220*af371f9fSRiver Riddle }
221*af371f9fSRiver Riddle 
2229b4a02c1SRiver Riddle /// Tries to perform folding on the given `op`. If successful, populates
2230560f153SRiver Riddle /// `results` with the results of the folding.
tryToFold(OpBuilder & builder,Operation * op,SmallVectorImpl<Value> & results,function_ref<void (Operation *)> processGeneratedConstants)224bcacef1aSRiver Riddle LogicalResult OperationFolder::tryToFold(
22504f2b717SMaheshRavishankar     OpBuilder &builder, Operation *op, SmallVectorImpl<Value> &results,
2264562e389SRiver Riddle     function_ref<void(Operation *)> processGeneratedConstants) {
2271982afb1SRiver Riddle   SmallVector<Attribute, 8> operandConstants;
2281982afb1SRiver Riddle 
229b80a9ca8SStephen Neuendorffer   // If this is a commutative operation, move constants to be trailing operands.
230*af371f9fSRiver Riddle   bool updatedOpOperands = false;
231fe7c0d90SRiver Riddle   if (op->getNumOperands() >= 2 && op->hasTrait<OpTrait::IsCommutative>()) {
232*af371f9fSRiver Riddle     auto isNonConstant = [&](OpOperand &o) {
233*af371f9fSRiver Riddle       return !matchPattern(o.get(), m_Constant());
234*af371f9fSRiver Riddle     };
235*af371f9fSRiver Riddle     auto *firstConstantIt =
236*af371f9fSRiver Riddle         llvm::find_if_not(op->getOpOperands(), isNonConstant);
237*af371f9fSRiver Riddle     auto *newConstantIt = std::stable_partition(
238*af371f9fSRiver Riddle         firstConstantIt, op->getOpOperands().end(), isNonConstant);
239*af371f9fSRiver Riddle 
240*af371f9fSRiver Riddle     // Remember if we actually moved anything.
241*af371f9fSRiver Riddle     updatedOpOperands = firstConstantIt != newConstantIt;
242b80a9ca8SStephen Neuendorffer   }
243b80a9ca8SStephen Neuendorffer 
2441982afb1SRiver Riddle   // Check to see if any operands to the operation is constant and whether
2451982afb1SRiver Riddle   // the operation knows how to constant fold itself.
2461982afb1SRiver Riddle   operandConstants.assign(op->getNumOperands(), Attribute());
2471982afb1SRiver Riddle   for (unsigned i = 0, e = op->getNumOperands(); i != e; ++i)
2481982afb1SRiver Riddle     matchPattern(op->getOperand(i), m_Constant(&operandConstants[i]));
2491982afb1SRiver Riddle 
250*af371f9fSRiver Riddle   // Attempt to constant fold the operation. If we failed, check to see if we at
251*af371f9fSRiver Riddle   // least updated the operands of the operation. We treat this as an in-place
252*af371f9fSRiver Riddle   // fold.
253*af371f9fSRiver Riddle   SmallVector<OpFoldResult, 8> foldResults;
254*af371f9fSRiver Riddle   if (failed(op->fold(operandConstants, foldResults)) ||
255*af371f9fSRiver Riddle       failed(processFoldResults(builder, op, results, foldResults,
256*af371f9fSRiver Riddle                                 processGeneratedConstants)))
257*af371f9fSRiver Riddle     return success(updatedOpOperands);
258*af371f9fSRiver Riddle   return success();
259*af371f9fSRiver Riddle }
2601982afb1SRiver Riddle 
processFoldResults(OpBuilder & builder,Operation * op,SmallVectorImpl<Value> & results,ArrayRef<OpFoldResult> foldResults,function_ref<void (Operation *)> processGeneratedConstants)261*af371f9fSRiver Riddle LogicalResult OperationFolder::processFoldResults(
262*af371f9fSRiver Riddle     OpBuilder &builder, Operation *op, SmallVectorImpl<Value> &results,
263*af371f9fSRiver Riddle     ArrayRef<OpFoldResult> foldResults,
264*af371f9fSRiver Riddle     function_ref<void(Operation *)> processGeneratedConstants) {
2651982afb1SRiver Riddle   // Check to see if the operation was just updated in place.
2669b4a02c1SRiver Riddle   if (foldResults.empty())
2671982afb1SRiver Riddle     return success();
2689b4a02c1SRiver Riddle   assert(foldResults.size() == op->getNumResults());
2691982afb1SRiver Riddle 
27066ed7d6dSRiver Riddle   // Create a builder to insert new operations into the entry block of the
27166ed7d6dSRiver Riddle   // insertion region.
27204f2b717SMaheshRavishankar   auto *insertRegion =
27304f2b717SMaheshRavishankar       getInsertionRegion(interfaces, builder.getInsertionBlock());
2746563b1c4SRiver Riddle   auto &entry = insertRegion->front();
27504f2b717SMaheshRavishankar   OpBuilder::InsertionGuard foldGuard(builder);
27604f2b717SMaheshRavishankar   builder.setInsertionPoint(&entry, entry.begin());
27766ed7d6dSRiver Riddle 
27866ed7d6dSRiver Riddle   // Get the constant map for the insertion region of this operation.
2796563b1c4SRiver Riddle   auto &uniquedConstants = foldScopes[insertRegion];
280bcacef1aSRiver Riddle 
2811982afb1SRiver Riddle   // Create the result constants and replace the results.
282bcacef1aSRiver Riddle   auto *dialect = op->getDialect();
2831982afb1SRiver Riddle   for (unsigned i = 0, e = op->getNumResults(); i != e; ++i) {
2849b4a02c1SRiver Riddle     assert(!foldResults[i].isNull() && "expected valid OpFoldResult");
2851982afb1SRiver Riddle 
2861982afb1SRiver Riddle     // Check if the result was an SSA value.
287e62a6956SRiver Riddle     if (auto repl = foldResults[i].dyn_cast<Value>()) {
288*af371f9fSRiver Riddle       if (repl.getType() != op->getResult(i).getType()) {
289*af371f9fSRiver Riddle         results.clear();
290a1d5bdf8SMehdi Amini         return failure();
291*af371f9fSRiver Riddle       }
2929b4a02c1SRiver Riddle       results.emplace_back(repl);
2931982afb1SRiver Riddle       continue;
2941982afb1SRiver Riddle     }
2951982afb1SRiver Riddle 
296bcacef1aSRiver Riddle     // Check to see if there is a canonicalized version of this constant.
29735807bc4SRiver Riddle     auto res = op->getResult(i);
298bcacef1aSRiver Riddle     Attribute attrRepl = foldResults[i].get<Attribute>();
29966ed7d6dSRiver Riddle     if (auto *constOp =
30066ed7d6dSRiver Riddle             tryGetOrCreateConstant(uniquedConstants, dialect, builder, attrRepl,
3012bdf33ccSRiver Riddle                                    res.getType(), op->getLoc())) {
302e4635e63SRiver Riddle       // Ensure that this constant dominates the operation we are replacing it
303e4635e63SRiver Riddle       // with. This may not automatically happen if the operation being folded
304e4635e63SRiver Riddle       // was inserted before the constant within the insertion block.
30540a89da6SChris Lattner       Block *opBlock = op->getBlock();
30640a89da6SChris Lattner       if (opBlock == constOp->getBlock() && &opBlock->front() != constOp)
30740a89da6SChris Lattner         constOp->moveBefore(&opBlock->front());
308e4635e63SRiver Riddle 
309bcacef1aSRiver Riddle       results.push_back(constOp->getResult(0));
310bcacef1aSRiver Riddle       continue;
3111982afb1SRiver Riddle     }
312bcacef1aSRiver Riddle     // If materialization fails, cleanup any operations generated for the
313bcacef1aSRiver Riddle     // previous results and return failure.
314bcacef1aSRiver Riddle     for (Operation &op : llvm::make_early_inc_range(
315bcacef1aSRiver Riddle              llvm::make_range(entry.begin(), builder.getInsertionPoint()))) {
316bcacef1aSRiver Riddle       notifyRemoval(&op);
317bcacef1aSRiver Riddle       op.erase();
318bcacef1aSRiver Riddle     }
319*af371f9fSRiver Riddle     results.clear();
320bcacef1aSRiver Riddle     return failure();
321bcacef1aSRiver Riddle   }
322bcacef1aSRiver Riddle 
323bcacef1aSRiver Riddle   // Process any newly generated operations.
324bcacef1aSRiver Riddle   if (processGeneratedConstants) {
325bcacef1aSRiver Riddle     for (auto i = entry.begin(), e = builder.getInsertionPoint(); i != e; ++i)
326bcacef1aSRiver Riddle       processGeneratedConstants(&*i);
3271982afb1SRiver Riddle   }
3281982afb1SRiver Riddle 
3291982afb1SRiver Riddle   return success();
3301982afb1SRiver Riddle }
3311982afb1SRiver Riddle 
332bcacef1aSRiver Riddle /// Try to get or create a new constant entry. On success this returns the
333bcacef1aSRiver Riddle /// constant operation value, nullptr otherwise.
tryGetOrCreateConstant(ConstantMap & uniquedConstants,Dialect * dialect,OpBuilder & builder,Attribute value,Type type,Location loc)33466ed7d6dSRiver Riddle Operation *OperationFolder::tryGetOrCreateConstant(
33566ed7d6dSRiver Riddle     ConstantMap &uniquedConstants, Dialect *dialect, OpBuilder &builder,
33666ed7d6dSRiver Riddle     Attribute value, Type type, Location loc) {
337bcacef1aSRiver Riddle   // Check if an existing mapping already exists.
338bcacef1aSRiver Riddle   auto constKey = std::make_tuple(dialect, value, type);
339648f34a2SChris Lattner   Operation *&constOp = uniquedConstants[constKey];
340648f34a2SChris Lattner   if (constOp)
341648f34a2SChris Lattner     return constOp;
3421982afb1SRiver Riddle 
343bcacef1aSRiver Riddle   // If one doesn't exist, try to materialize one.
344648f34a2SChris Lattner   if (!(constOp = materializeConstant(dialect, builder, value, type, loc)))
345bcacef1aSRiver Riddle     return nullptr;
3461982afb1SRiver Riddle 
347bcacef1aSRiver Riddle   // Check to see if the generated constant is in the expected dialect.
348648f34a2SChris Lattner   auto *newDialect = constOp->getDialect();
349bcacef1aSRiver Riddle   if (newDialect == dialect) {
350648f34a2SChris Lattner     referencedDialects[constOp].push_back(dialect);
351648f34a2SChris Lattner     return constOp;
3521982afb1SRiver Riddle   }
3531982afb1SRiver Riddle 
354bcacef1aSRiver Riddle   // If it isn't, then we also need to make sure that the mapping for the new
355bcacef1aSRiver Riddle   // dialect is valid.
356bcacef1aSRiver Riddle   auto newKey = std::make_tuple(newDialect, value, type);
3571982afb1SRiver Riddle 
358bcacef1aSRiver Riddle   // If an existing operation in the new dialect already exists, delete the
359bcacef1aSRiver Riddle   // materialized operation in favor of the existing one.
360bcacef1aSRiver Riddle   if (auto *existingOp = uniquedConstants.lookup(newKey)) {
361648f34a2SChris Lattner     constOp->erase();
362bcacef1aSRiver Riddle     referencedDialects[existingOp].push_back(dialect);
363648f34a2SChris Lattner     return constOp = existingOp;
3641982afb1SRiver Riddle   }
3651982afb1SRiver Riddle 
366bcacef1aSRiver Riddle   // Otherwise, update the new dialect to the materialized operation.
367648f34a2SChris Lattner   referencedDialects[constOp].assign({dialect, newDialect});
368648f34a2SChris Lattner   auto newIt = uniquedConstants.insert({newKey, constOp});
369bcacef1aSRiver Riddle   return newIt.first->second;
3701982afb1SRiver Riddle }
371