17ceffae1SRiver Riddle //===- FunctionSupport.cpp - Utility types for function-like ops ----------===//
27ceffae1SRiver Riddle //
37ceffae1SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47ceffae1SRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
57ceffae1SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67ceffae1SRiver Riddle //
77ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
87ceffae1SRiver Riddle 
97ceffae1SRiver Riddle #include "mlir/IR/FunctionInterfaces.h"
107ceffae1SRiver Riddle 
117ceffae1SRiver Riddle using namespace mlir;
127ceffae1SRiver Riddle 
137ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
147ceffae1SRiver Riddle // Tablegen Interface Definitions
157ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
167ceffae1SRiver Riddle 
177ceffae1SRiver Riddle #include "mlir/IR/FunctionOpInterfaces.cpp.inc"
187ceffae1SRiver Riddle 
197ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
207ceffae1SRiver Riddle // Function Arguments and Results.
217ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
227ceffae1SRiver Riddle 
isEmptyAttrDict(Attribute attr)237ceffae1SRiver Riddle static bool isEmptyAttrDict(Attribute attr) {
247ceffae1SRiver Riddle   return attr.cast<DictionaryAttr>().empty();
257ceffae1SRiver Riddle }
267ceffae1SRiver Riddle 
getArgAttrDict(Operation * op,unsigned index)277ceffae1SRiver Riddle DictionaryAttr mlir::function_interface_impl::getArgAttrDict(Operation *op,
287ceffae1SRiver Riddle                                                              unsigned index) {
297ceffae1SRiver Riddle   ArrayAttr attrs = op->getAttrOfType<ArrayAttr>(getArgDictAttrName());
307ceffae1SRiver Riddle   DictionaryAttr argAttrs =
317ceffae1SRiver Riddle       attrs ? attrs[index].cast<DictionaryAttr>() : DictionaryAttr();
327ceffae1SRiver Riddle   return argAttrs;
337ceffae1SRiver Riddle }
347ceffae1SRiver Riddle 
357ceffae1SRiver Riddle DictionaryAttr
getResultAttrDict(Operation * op,unsigned index)367ceffae1SRiver Riddle mlir::function_interface_impl::getResultAttrDict(Operation *op,
377ceffae1SRiver Riddle                                                  unsigned index) {
387ceffae1SRiver Riddle   ArrayAttr attrs = op->getAttrOfType<ArrayAttr>(getResultDictAttrName());
397ceffae1SRiver Riddle   DictionaryAttr resAttrs =
407ceffae1SRiver Riddle       attrs ? attrs[index].cast<DictionaryAttr>() : DictionaryAttr();
417ceffae1SRiver Riddle   return resAttrs;
427ceffae1SRiver Riddle }
437ceffae1SRiver Riddle 
setArgResAttrDict(Operation * op,StringRef attrName,unsigned numTotalIndices,unsigned index,DictionaryAttr attrs)447ceffae1SRiver Riddle void mlir::function_interface_impl::detail::setArgResAttrDict(
457ceffae1SRiver Riddle     Operation *op, StringRef attrName, unsigned numTotalIndices, unsigned index,
467ceffae1SRiver Riddle     DictionaryAttr attrs) {
477ceffae1SRiver Riddle   ArrayAttr allAttrs = op->getAttrOfType<ArrayAttr>(attrName);
487ceffae1SRiver Riddle   if (!allAttrs) {
497ceffae1SRiver Riddle     if (attrs.empty())
507ceffae1SRiver Riddle       return;
517ceffae1SRiver Riddle 
527ceffae1SRiver Riddle     // If this attribute is not empty, we need to create a new attribute array.
537ceffae1SRiver Riddle     SmallVector<Attribute, 8> newAttrs(numTotalIndices,
547ceffae1SRiver Riddle                                        DictionaryAttr::get(op->getContext()));
557ceffae1SRiver Riddle     newAttrs[index] = attrs;
567ceffae1SRiver Riddle     op->setAttr(attrName, ArrayAttr::get(op->getContext(), newAttrs));
577ceffae1SRiver Riddle     return;
587ceffae1SRiver Riddle   }
597ceffae1SRiver Riddle   // Check to see if the attribute is different from what we already have.
607ceffae1SRiver Riddle   if (allAttrs[index] == attrs)
617ceffae1SRiver Riddle     return;
627ceffae1SRiver Riddle 
637ceffae1SRiver Riddle   // If it is, check to see if the attribute array would now contain only empty
647ceffae1SRiver Riddle   // dictionaries.
657ceffae1SRiver Riddle   ArrayRef<Attribute> rawAttrArray = allAttrs.getValue();
667ceffae1SRiver Riddle   if (attrs.empty() &&
677ceffae1SRiver Riddle       llvm::all_of(rawAttrArray.take_front(index), isEmptyAttrDict) &&
687ceffae1SRiver Riddle       llvm::all_of(rawAttrArray.drop_front(index + 1), isEmptyAttrDict)) {
697ceffae1SRiver Riddle     op->removeAttr(attrName);
707ceffae1SRiver Riddle     return;
717ceffae1SRiver Riddle   }
727ceffae1SRiver Riddle 
737ceffae1SRiver Riddle   // Otherwise, create a new attribute array with the updated dictionary.
747ceffae1SRiver Riddle   SmallVector<Attribute, 8> newAttrs(rawAttrArray.begin(), rawAttrArray.end());
757ceffae1SRiver Riddle   newAttrs[index] = attrs;
767ceffae1SRiver Riddle   op->setAttr(attrName, ArrayAttr::get(op->getContext(), newAttrs));
777ceffae1SRiver Riddle }
787ceffae1SRiver Riddle 
797ceffae1SRiver Riddle /// Set all of the argument or result attribute dictionaries for a function.
setAllArgResAttrDicts(Operation * op,StringRef attrName,ArrayRef<Attribute> attrs)807ceffae1SRiver Riddle static void setAllArgResAttrDicts(Operation *op, StringRef attrName,
817ceffae1SRiver Riddle                                   ArrayRef<Attribute> attrs) {
827ceffae1SRiver Riddle   if (llvm::all_of(attrs, isEmptyAttrDict))
837ceffae1SRiver Riddle     op->removeAttr(attrName);
847ceffae1SRiver Riddle   else
857ceffae1SRiver Riddle     op->setAttr(attrName, ArrayAttr::get(op->getContext(), attrs));
867ceffae1SRiver Riddle }
877ceffae1SRiver Riddle 
setAllArgAttrDicts(Operation * op,ArrayRef<DictionaryAttr> attrs)887ceffae1SRiver Riddle void mlir::function_interface_impl::setAllArgAttrDicts(
897ceffae1SRiver Riddle     Operation *op, ArrayRef<DictionaryAttr> attrs) {
907ceffae1SRiver Riddle   setAllArgAttrDicts(op, ArrayRef<Attribute>(attrs.data(), attrs.size()));
917ceffae1SRiver Riddle }
setAllArgAttrDicts(Operation * op,ArrayRef<Attribute> attrs)927ceffae1SRiver Riddle void mlir::function_interface_impl::setAllArgAttrDicts(
937ceffae1SRiver Riddle     Operation *op, ArrayRef<Attribute> attrs) {
947ceffae1SRiver Riddle   auto wrappedAttrs = llvm::map_range(attrs, [op](Attribute attr) -> Attribute {
957ceffae1SRiver Riddle     return !attr ? DictionaryAttr::get(op->getContext()) : attr;
967ceffae1SRiver Riddle   });
977ceffae1SRiver Riddle   setAllArgResAttrDicts(op, getArgDictAttrName(),
987ceffae1SRiver Riddle                         llvm::to_vector<8>(wrappedAttrs));
997ceffae1SRiver Riddle }
1007ceffae1SRiver Riddle 
setAllResultAttrDicts(Operation * op,ArrayRef<DictionaryAttr> attrs)1017ceffae1SRiver Riddle void mlir::function_interface_impl::setAllResultAttrDicts(
1027ceffae1SRiver Riddle     Operation *op, ArrayRef<DictionaryAttr> attrs) {
1037ceffae1SRiver Riddle   setAllResultAttrDicts(op, ArrayRef<Attribute>(attrs.data(), attrs.size()));
1047ceffae1SRiver Riddle }
setAllResultAttrDicts(Operation * op,ArrayRef<Attribute> attrs)1057ceffae1SRiver Riddle void mlir::function_interface_impl::setAllResultAttrDicts(
1067ceffae1SRiver Riddle     Operation *op, ArrayRef<Attribute> attrs) {
1077ceffae1SRiver Riddle   auto wrappedAttrs = llvm::map_range(attrs, [op](Attribute attr) -> Attribute {
1087ceffae1SRiver Riddle     return !attr ? DictionaryAttr::get(op->getContext()) : attr;
1097ceffae1SRiver Riddle   });
1107ceffae1SRiver Riddle   setAllArgResAttrDicts(op, getResultDictAttrName(),
1117ceffae1SRiver Riddle                         llvm::to_vector<8>(wrappedAttrs));
1127ceffae1SRiver Riddle }
1137ceffae1SRiver Riddle 
insertFunctionArguments(Operation * op,ArrayRef<unsigned> argIndices,TypeRange argTypes,ArrayRef<DictionaryAttr> argAttrs,ArrayRef<Location> argLocs,unsigned originalNumArgs,Type newType)1147ceffae1SRiver Riddle void mlir::function_interface_impl::insertFunctionArguments(
1157ceffae1SRiver Riddle     Operation *op, ArrayRef<unsigned> argIndices, TypeRange argTypes,
116e084679fSRiver Riddle     ArrayRef<DictionaryAttr> argAttrs, ArrayRef<Location> argLocs,
1177ceffae1SRiver Riddle     unsigned originalNumArgs, Type newType) {
1187ceffae1SRiver Riddle   assert(argIndices.size() == argTypes.size());
1197ceffae1SRiver Riddle   assert(argIndices.size() == argAttrs.size() || argAttrs.empty());
120e084679fSRiver Riddle   assert(argIndices.size() == argLocs.size());
1217ceffae1SRiver Riddle   if (argIndices.empty())
1227ceffae1SRiver Riddle     return;
1237ceffae1SRiver Riddle 
1247ceffae1SRiver Riddle   // There are 3 things that need to be updated:
1257ceffae1SRiver Riddle   // - Function type.
1267ceffae1SRiver Riddle   // - Arg attrs.
1277ceffae1SRiver Riddle   // - Block arguments of entry block.
1287ceffae1SRiver Riddle   Block &entry = op->getRegion(0).front();
1297ceffae1SRiver Riddle 
1307ceffae1SRiver Riddle   // Update the argument attributes of the function.
1317ceffae1SRiver Riddle   auto oldArgAttrs = op->getAttrOfType<ArrayAttr>(getArgDictAttrName());
1327ceffae1SRiver Riddle   if (oldArgAttrs || !argAttrs.empty()) {
1337ceffae1SRiver Riddle     SmallVector<DictionaryAttr, 4> newArgAttrs;
1347ceffae1SRiver Riddle     newArgAttrs.reserve(originalNumArgs + argIndices.size());
1357ceffae1SRiver Riddle     unsigned oldIdx = 0;
1367ceffae1SRiver Riddle     auto migrate = [&](unsigned untilIdx) {
1377ceffae1SRiver Riddle       if (!oldArgAttrs) {
1387ceffae1SRiver Riddle         newArgAttrs.resize(newArgAttrs.size() + untilIdx - oldIdx);
1397ceffae1SRiver Riddle       } else {
1407ceffae1SRiver Riddle         auto oldArgAttrRange = oldArgAttrs.getAsRange<DictionaryAttr>();
1417ceffae1SRiver Riddle         newArgAttrs.append(oldArgAttrRange.begin() + oldIdx,
1427ceffae1SRiver Riddle                            oldArgAttrRange.begin() + untilIdx);
1437ceffae1SRiver Riddle       }
1447ceffae1SRiver Riddle       oldIdx = untilIdx;
1457ceffae1SRiver Riddle     };
1467ceffae1SRiver Riddle     for (unsigned i = 0, e = argIndices.size(); i < e; ++i) {
1477ceffae1SRiver Riddle       migrate(argIndices[i]);
1487ceffae1SRiver Riddle       newArgAttrs.push_back(argAttrs.empty() ? DictionaryAttr{} : argAttrs[i]);
1497ceffae1SRiver Riddle     }
1507ceffae1SRiver Riddle     migrate(originalNumArgs);
1517ceffae1SRiver Riddle     setAllArgAttrDicts(op, newArgAttrs);
1527ceffae1SRiver Riddle   }
1537ceffae1SRiver Riddle 
1547ceffae1SRiver Riddle   // Update the function type and any entry block arguments.
1557ceffae1SRiver Riddle   op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
1567ceffae1SRiver Riddle   for (unsigned i = 0, e = argIndices.size(); i < e; ++i)
157e084679fSRiver Riddle     entry.insertArgument(argIndices[i] + i, argTypes[i], argLocs[i]);
1587ceffae1SRiver Riddle }
1597ceffae1SRiver Riddle 
insertFunctionResults(Operation * op,ArrayRef<unsigned> resultIndices,TypeRange resultTypes,ArrayRef<DictionaryAttr> resultAttrs,unsigned originalNumResults,Type newType)1607ceffae1SRiver Riddle void mlir::function_interface_impl::insertFunctionResults(
1617ceffae1SRiver Riddle     Operation *op, ArrayRef<unsigned> resultIndices, TypeRange resultTypes,
1627ceffae1SRiver Riddle     ArrayRef<DictionaryAttr> resultAttrs, unsigned originalNumResults,
1637ceffae1SRiver Riddle     Type newType) {
1647ceffae1SRiver Riddle   assert(resultIndices.size() == resultTypes.size());
1657ceffae1SRiver Riddle   assert(resultIndices.size() == resultAttrs.size() || resultAttrs.empty());
1667ceffae1SRiver Riddle   if (resultIndices.empty())
1677ceffae1SRiver Riddle     return;
1687ceffae1SRiver Riddle 
1697ceffae1SRiver Riddle   // There are 2 things that need to be updated:
1707ceffae1SRiver Riddle   // - Function type.
1717ceffae1SRiver Riddle   // - Result attrs.
1727ceffae1SRiver Riddle 
1737ceffae1SRiver Riddle   // Update the result attributes of the function.
1747ceffae1SRiver Riddle   auto oldResultAttrs = op->getAttrOfType<ArrayAttr>(getResultDictAttrName());
1757ceffae1SRiver Riddle   if (oldResultAttrs || !resultAttrs.empty()) {
1767ceffae1SRiver Riddle     SmallVector<DictionaryAttr, 4> newResultAttrs;
1777ceffae1SRiver Riddle     newResultAttrs.reserve(originalNumResults + resultIndices.size());
1787ceffae1SRiver Riddle     unsigned oldIdx = 0;
1797ceffae1SRiver Riddle     auto migrate = [&](unsigned untilIdx) {
1807ceffae1SRiver Riddle       if (!oldResultAttrs) {
1817ceffae1SRiver Riddle         newResultAttrs.resize(newResultAttrs.size() + untilIdx - oldIdx);
1827ceffae1SRiver Riddle       } else {
1837ceffae1SRiver Riddle         auto oldResultAttrsRange = oldResultAttrs.getAsRange<DictionaryAttr>();
1847ceffae1SRiver Riddle         newResultAttrs.append(oldResultAttrsRange.begin() + oldIdx,
1857ceffae1SRiver Riddle                               oldResultAttrsRange.begin() + untilIdx);
1867ceffae1SRiver Riddle       }
1877ceffae1SRiver Riddle       oldIdx = untilIdx;
1887ceffae1SRiver Riddle     };
1897ceffae1SRiver Riddle     for (unsigned i = 0, e = resultIndices.size(); i < e; ++i) {
1907ceffae1SRiver Riddle       migrate(resultIndices[i]);
1917ceffae1SRiver Riddle       newResultAttrs.push_back(resultAttrs.empty() ? DictionaryAttr{}
1927ceffae1SRiver Riddle                                                    : resultAttrs[i]);
1937ceffae1SRiver Riddle     }
1947ceffae1SRiver Riddle     migrate(originalNumResults);
1957ceffae1SRiver Riddle     setAllResultAttrDicts(op, newResultAttrs);
1967ceffae1SRiver Riddle   }
1977ceffae1SRiver Riddle 
1987ceffae1SRiver Riddle   // Update the function type.
1997ceffae1SRiver Riddle   op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
2007ceffae1SRiver Riddle }
2017ceffae1SRiver Riddle 
eraseFunctionArguments(Operation * op,const BitVector & argIndices,Type newType)2027ceffae1SRiver Riddle void mlir::function_interface_impl::eraseFunctionArguments(
203d10d49dcSRiver Riddle     Operation *op, const BitVector &argIndices, Type newType) {
2047ceffae1SRiver Riddle   // There are 3 things that need to be updated:
2057ceffae1SRiver Riddle   // - Function type.
2067ceffae1SRiver Riddle   // - Arg attrs.
2077ceffae1SRiver Riddle   // - Block arguments of entry block.
2087ceffae1SRiver Riddle   Block &entry = op->getRegion(0).front();
2097ceffae1SRiver Riddle 
2107ceffae1SRiver Riddle   // Update the argument attributes of the function.
2117ceffae1SRiver Riddle   if (auto argAttrs = op->getAttrOfType<ArrayAttr>(getArgDictAttrName())) {
2127ceffae1SRiver Riddle     SmallVector<DictionaryAttr, 4> newArgAttrs;
2137ceffae1SRiver Riddle     newArgAttrs.reserve(argAttrs.size());
214e3cd80eaSRiver Riddle     for (unsigned i = 0, e = argIndices.size(); i < e; ++i)
215e3cd80eaSRiver Riddle       if (!argIndices[i])
2167ceffae1SRiver Riddle         newArgAttrs.emplace_back(argAttrs[i].cast<DictionaryAttr>());
2177ceffae1SRiver Riddle     setAllArgAttrDicts(op, newArgAttrs);
2187ceffae1SRiver Riddle   }
2197ceffae1SRiver Riddle 
2207ceffae1SRiver Riddle   // Update the function type and any entry block arguments.
2217ceffae1SRiver Riddle   op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
2227ceffae1SRiver Riddle   entry.eraseArguments(argIndices);
2237ceffae1SRiver Riddle }
2247ceffae1SRiver Riddle 
eraseFunctionResults(Operation * op,const BitVector & resultIndices,Type newType)2257ceffae1SRiver Riddle void mlir::function_interface_impl::eraseFunctionResults(
226d10d49dcSRiver Riddle     Operation *op, const BitVector &resultIndices, Type newType) {
2277ceffae1SRiver Riddle   // There are 2 things that need to be updated:
2287ceffae1SRiver Riddle   // - Function type.
2297ceffae1SRiver Riddle   // - Result attrs.
2307ceffae1SRiver Riddle 
2317ceffae1SRiver Riddle   // Update the result attributes of the function.
2327ceffae1SRiver Riddle   if (auto resAttrs = op->getAttrOfType<ArrayAttr>(getResultDictAttrName())) {
2337ceffae1SRiver Riddle     SmallVector<DictionaryAttr, 4> newResultAttrs;
2347ceffae1SRiver Riddle     newResultAttrs.reserve(resAttrs.size());
235e3cd80eaSRiver Riddle     for (unsigned i = 0, e = resultIndices.size(); i < e; ++i)
236e3cd80eaSRiver Riddle       if (!resultIndices[i])
2377ceffae1SRiver Riddle         newResultAttrs.emplace_back(resAttrs[i].cast<DictionaryAttr>());
2387ceffae1SRiver Riddle     setAllResultAttrDicts(op, newResultAttrs);
2397ceffae1SRiver Riddle   }
2407ceffae1SRiver Riddle 
2417ceffae1SRiver Riddle   // Update the function type.
2427ceffae1SRiver Riddle   op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
2437ceffae1SRiver Riddle }
2447ceffae1SRiver Riddle 
insertTypesInto(TypeRange oldTypes,ArrayRef<unsigned> indices,TypeRange newTypes,SmallVectorImpl<Type> & storage)2457ceffae1SRiver Riddle TypeRange mlir::function_interface_impl::insertTypesInto(
2467ceffae1SRiver Riddle     TypeRange oldTypes, ArrayRef<unsigned> indices, TypeRange newTypes,
2477ceffae1SRiver Riddle     SmallVectorImpl<Type> &storage) {
2487ceffae1SRiver Riddle   assert(indices.size() == newTypes.size() &&
2497ceffae1SRiver Riddle          "mismatch between indice and type count");
2507ceffae1SRiver Riddle   if (indices.empty())
2517ceffae1SRiver Riddle     return oldTypes;
2527ceffae1SRiver Riddle 
2537ceffae1SRiver Riddle   auto fromIt = oldTypes.begin();
2547ceffae1SRiver Riddle   for (auto it : llvm::zip(indices, newTypes)) {
2557ceffae1SRiver Riddle     const auto toIt = oldTypes.begin() + std::get<0>(it);
2567ceffae1SRiver Riddle     storage.append(fromIt, toIt);
2577ceffae1SRiver Riddle     storage.push_back(std::get<1>(it));
2587ceffae1SRiver Riddle     fromIt = toIt;
2597ceffae1SRiver Riddle   }
2607ceffae1SRiver Riddle   storage.append(fromIt, oldTypes.end());
2617ceffae1SRiver Riddle   return storage;
2627ceffae1SRiver Riddle }
2637ceffae1SRiver Riddle 
filterTypesOut(TypeRange types,const BitVector & indices,SmallVectorImpl<Type> & storage)264*b7f93c28SJeff Niu TypeRange mlir::function_interface_impl::filterTypesOut(
265*b7f93c28SJeff Niu     TypeRange types, const BitVector &indices, SmallVectorImpl<Type> &storage) {
266e3cd80eaSRiver Riddle   if (indices.none())
2677ceffae1SRiver Riddle     return types;
268e3cd80eaSRiver Riddle 
269e3cd80eaSRiver Riddle   for (unsigned i = 0, e = types.size(); i < e; ++i)
270e3cd80eaSRiver Riddle     if (!indices[i])
271e3cd80eaSRiver Riddle       storage.emplace_back(types[i]);
2727ceffae1SRiver Riddle   return storage;
2737ceffae1SRiver Riddle }
2747ceffae1SRiver Riddle 
2757ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
2767ceffae1SRiver Riddle // Function type signature.
2777ceffae1SRiver Riddle //===----------------------------------------------------------------------===//
2787ceffae1SRiver Riddle 
setFunctionType(Operation * op,Type newType)2797ceffae1SRiver Riddle void mlir::function_interface_impl::setFunctionType(Operation *op,
2807ceffae1SRiver Riddle                                                     Type newType) {
2817ceffae1SRiver Riddle   FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
2827ceffae1SRiver Riddle   unsigned oldNumArgs = funcOp.getNumArguments();
2837ceffae1SRiver Riddle   unsigned oldNumResults = funcOp.getNumResults();
2847ceffae1SRiver Riddle   op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
2857ceffae1SRiver Riddle   unsigned newNumArgs = funcOp.getNumArguments();
2867ceffae1SRiver Riddle   unsigned newNumResults = funcOp.getNumResults();
2877ceffae1SRiver Riddle 
2887ceffae1SRiver Riddle   // Functor used to update the argument and result attributes of the function.
2897ceffae1SRiver Riddle   auto updateAttrFn = [&](StringRef attrName, unsigned oldCount,
2907ceffae1SRiver Riddle                           unsigned newCount, auto setAttrFn) {
2917ceffae1SRiver Riddle     if (oldCount == newCount)
2927ceffae1SRiver Riddle       return;
2937ceffae1SRiver Riddle     // The new type has no arguments/results, just drop the attribute.
2947ceffae1SRiver Riddle     if (newCount == 0) {
2957ceffae1SRiver Riddle       op->removeAttr(attrName);
2967ceffae1SRiver Riddle       return;
2977ceffae1SRiver Riddle     }
2987ceffae1SRiver Riddle     ArrayAttr attrs = op->getAttrOfType<ArrayAttr>(attrName);
2997ceffae1SRiver Riddle     if (!attrs)
3007ceffae1SRiver Riddle       return;
3017ceffae1SRiver Riddle 
3027ceffae1SRiver Riddle     // The new type has less arguments/results, take the first N attributes.
3037ceffae1SRiver Riddle     if (newCount < oldCount)
3047ceffae1SRiver Riddle       return setAttrFn(op, attrs.getValue().take_front(newCount));
3057ceffae1SRiver Riddle 
3067ceffae1SRiver Riddle     // Otherwise, the new type has more arguments/results. Initialize the new
3077ceffae1SRiver Riddle     // arguments/results with empty attributes.
3087ceffae1SRiver Riddle     SmallVector<Attribute> newAttrs(attrs.begin(), attrs.end());
3097ceffae1SRiver Riddle     newAttrs.resize(newCount);
3107ceffae1SRiver Riddle     setAttrFn(op, newAttrs);
3117ceffae1SRiver Riddle   };
3127ceffae1SRiver Riddle 
3137ceffae1SRiver Riddle   // Update the argument and result attributes.
3147ceffae1SRiver Riddle   updateAttrFn(
3157ceffae1SRiver Riddle       getArgDictAttrName(), oldNumArgs, newNumArgs,
3167ceffae1SRiver Riddle       [&](Operation *op, auto &&attrs) { setAllArgAttrDicts(op, attrs); });
3177ceffae1SRiver Riddle   updateAttrFn(
3187ceffae1SRiver Riddle       getResultDictAttrName(), oldNumResults, newNumResults,
3197ceffae1SRiver Riddle       [&](Operation *op, auto &&attrs) { setAllResultAttrDicts(op, attrs); });
3207ceffae1SRiver Riddle }
321