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