10813700dSMatthias Springer //===- StaticValueUtils.cpp - Utilities for dealing with static values ----===// 20813700dSMatthias Springer // 30813700dSMatthias Springer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40813700dSMatthias Springer // See https://llvm.org/LICENSE.txt for license information. 50813700dSMatthias Springer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60813700dSMatthias Springer // 70813700dSMatthias Springer //===----------------------------------------------------------------------===// 80813700dSMatthias Springer 90813700dSMatthias Springer #include "mlir/Dialect/Utils/StaticValueUtils.h" 100813700dSMatthias Springer #include "mlir/IR/Matchers.h" 110813700dSMatthias Springer #include "mlir/Support/LLVM.h" 120813700dSMatthias Springer #include "llvm/ADT/APSInt.h" 1398e838a8SMax191 #include "llvm/ADT/STLExtras.h" 140fb216fbSRamkumar Ramachandra #include "llvm/Support/MathExtras.h" 150813700dSMatthias Springer 160813700dSMatthias Springer namespace mlir { 170813700dSMatthias Springer 1896179dffSNicolas Vasilache bool isZeroIndex(OpFoldResult v) { 1996179dffSNicolas Vasilache if (!v) 2096179dffSNicolas Vasilache return false; 21da2c98b5SThomas Preud'homme std::optional<int64_t> constint = getConstantIntValue(v); 22da2c98b5SThomas Preud'homme if (!constint) 2396179dffSNicolas Vasilache return false; 24da2c98b5SThomas Preud'homme return *constint == 0; 2596179dffSNicolas Vasilache } 2696179dffSNicolas Vasilache 27f4a478cdSChristopher Bate std::tuple<SmallVector<OpFoldResult>, SmallVector<OpFoldResult>, 28f4a478cdSChristopher Bate SmallVector<OpFoldResult>> 29f4a478cdSChristopher Bate getOffsetsSizesAndStrides(ArrayRef<Range> ranges) { 30f4a478cdSChristopher Bate SmallVector<OpFoldResult> offsets, sizes, strides; 31f4a478cdSChristopher Bate offsets.reserve(ranges.size()); 32f4a478cdSChristopher Bate sizes.reserve(ranges.size()); 33f4a478cdSChristopher Bate strides.reserve(ranges.size()); 34f4a478cdSChristopher Bate for (const auto &[offset, size, stride] : ranges) { 35f4a478cdSChristopher Bate offsets.push_back(offset); 36f4a478cdSChristopher Bate sizes.push_back(size); 37f4a478cdSChristopher Bate strides.push_back(stride); 38f4a478cdSChristopher Bate } 39f4a478cdSChristopher Bate return std::make_tuple(offsets, sizes, strides); 40f4a478cdSChristopher Bate } 41f4a478cdSChristopher Bate 42a08b750cSNicolas Vasilache /// Helper function to dispatch an OpFoldResult into `staticVec` if: 43a08b750cSNicolas Vasilache /// a) it is an IntegerAttr 44a08b750cSNicolas Vasilache /// In other cases, the OpFoldResult is dispached to the `dynamicVec`. 45a08b750cSNicolas Vasilache /// In such dynamic cases, a copy of the `sentinel` value is also pushed to 460813700dSMatthias Springer /// `staticVec`. This is useful to extract mixed static and dynamic entries that 470813700dSMatthias Springer /// come from an AttrSizedOperandSegments trait. 480813700dSMatthias Springer void dispatchIndexOpFoldResult(OpFoldResult ofr, 490813700dSMatthias Springer SmallVectorImpl<Value> &dynamicVec, 50ded75a28SAliia Khasanova SmallVectorImpl<int64_t> &staticVec) { 5168f58812STres Popp auto v = llvm::dyn_cast_if_present<Value>(ofr); 52a08b750cSNicolas Vasilache if (!v) { 53129f1001SKazu Hirata APInt apInt = cast<IntegerAttr>(cast<Attribute>(ofr)).getValue(); 54a08b750cSNicolas Vasilache staticVec.push_back(apInt.getSExtValue()); 550813700dSMatthias Springer return; 560813700dSMatthias Springer } 57a08b750cSNicolas Vasilache dynamicVec.push_back(v); 58ded75a28SAliia Khasanova staticVec.push_back(ShapedType::kDynamic); 590813700dSMatthias Springer } 600813700dSMatthias Springer 61e9bafa35SAndrzej Warzyński std::pair<int64_t, OpFoldResult> 62e9bafa35SAndrzej Warzyński getSimplifiedOfrAndStaticSizePair(OpFoldResult tileSizeOfr, Builder &b) { 63e9bafa35SAndrzej Warzyński int64_t tileSizeForShape = 64e9bafa35SAndrzej Warzyński getConstantIntValue(tileSizeOfr).value_or(ShapedType::kDynamic); 65e9bafa35SAndrzej Warzyński 66e9bafa35SAndrzej Warzyński OpFoldResult tileSizeOfrSimplified = 67e9bafa35SAndrzej Warzyński (tileSizeForShape != ShapedType::kDynamic) 68e9bafa35SAndrzej Warzyński ? b.getIndexAttr(tileSizeForShape) 69e9bafa35SAndrzej Warzyński : tileSizeOfr; 70e9bafa35SAndrzej Warzyński 71e9bafa35SAndrzej Warzyński return std::pair<int64_t, OpFoldResult>(tileSizeForShape, 72e9bafa35SAndrzej Warzyński tileSizeOfrSimplified); 73e9bafa35SAndrzej Warzyński } 74e9bafa35SAndrzej Warzyński 750813700dSMatthias Springer void dispatchIndexOpFoldResults(ArrayRef<OpFoldResult> ofrs, 760813700dSMatthias Springer SmallVectorImpl<Value> &dynamicVec, 77ded75a28SAliia Khasanova SmallVectorImpl<int64_t> &staticVec) { 780813700dSMatthias Springer for (OpFoldResult ofr : ofrs) 79ded75a28SAliia Khasanova dispatchIndexOpFoldResult(ofr, dynamicVec, staticVec); 800813700dSMatthias Springer } 810813700dSMatthias Springer 82d624c1b5SMatthias Springer /// Given a value, try to extract a constant Attribute. If this fails, return 83d624c1b5SMatthias Springer /// the original value. 84d624c1b5SMatthias Springer OpFoldResult getAsOpFoldResult(Value val) { 85e99fae89SAlex Zinenko if (!val) 86e99fae89SAlex Zinenko return OpFoldResult(); 87d624c1b5SMatthias Springer Attribute attr; 88d624c1b5SMatthias Springer if (matchPattern(val, m_Constant(&attr))) 89d624c1b5SMatthias Springer return attr; 90d624c1b5SMatthias Springer return val; 91d624c1b5SMatthias Springer } 92d624c1b5SMatthias Springer 93d624c1b5SMatthias Springer /// Given an array of values, try to extract a constant Attribute from each 94d624c1b5SMatthias Springer /// value. If this fails, return the original value. 956f03a10eSMahesh Ravishankar SmallVector<OpFoldResult> getAsOpFoldResult(ValueRange values) { 96aafb52d7SNicolas Vasilache return llvm::to_vector( 97d624c1b5SMatthias Springer llvm::map_range(values, [](Value v) { return getAsOpFoldResult(v); })); 98d624c1b5SMatthias Springer } 99d624c1b5SMatthias Springer 10018b92c66SNicolas Vasilache /// Convert `arrayAttr` to a vector of OpFoldResult. 10118b92c66SNicolas Vasilache SmallVector<OpFoldResult> getAsOpFoldResult(ArrayAttr arrayAttr) { 10218b92c66SNicolas Vasilache SmallVector<OpFoldResult> res; 10318b92c66SNicolas Vasilache res.reserve(arrayAttr.size()); 10418b92c66SNicolas Vasilache for (Attribute a : arrayAttr) 10518b92c66SNicolas Vasilache res.push_back(a); 10618b92c66SNicolas Vasilache return res; 10718b92c66SNicolas Vasilache } 10818b92c66SNicolas Vasilache 1098afe6f7bSNicolas Vasilache OpFoldResult getAsIndexOpFoldResult(MLIRContext *ctx, int64_t val) { 1108afe6f7bSNicolas Vasilache return IntegerAttr::get(IndexType::get(ctx), val); 1118afe6f7bSNicolas Vasilache } 1128afe6f7bSNicolas Vasilache 1138afe6f7bSNicolas Vasilache SmallVector<OpFoldResult> getAsIndexOpFoldResult(MLIRContext *ctx, 1148afe6f7bSNicolas Vasilache ArrayRef<int64_t> values) { 115aafb52d7SNicolas Vasilache return llvm::to_vector(llvm::map_range( 1168afe6f7bSNicolas Vasilache values, [ctx](int64_t v) { return getAsIndexOpFoldResult(ctx, v); })); 1178afe6f7bSNicolas Vasilache } 1188afe6f7bSNicolas Vasilache 1190813700dSMatthias Springer /// If ofr is a constant integer or an IntegerAttr, return the integer. 12022426110SRamkumar Ramachandra std::optional<int64_t> getConstantIntValue(OpFoldResult ofr) { 1210813700dSMatthias Springer // Case 1: Check for Constant integer. 12268f58812STres Popp if (auto val = llvm::dyn_cast_if_present<Value>(ofr)) { 1230813700dSMatthias Springer APSInt intVal; 1240813700dSMatthias Springer if (matchPattern(val, m_ConstantInt(&intVal))) 1250813700dSMatthias Springer return intVal.getSExtValue(); 1261a36588eSKazu Hirata return std::nullopt; 1270813700dSMatthias Springer } 1280813700dSMatthias Springer // Case 2: Check for IntegerAttr. 12968f58812STres Popp Attribute attr = llvm::dyn_cast_if_present<Attribute>(ofr); 1305550c821STres Popp if (auto intAttr = dyn_cast_or_null<IntegerAttr>(attr)) 1310813700dSMatthias Springer return intAttr.getValue().getSExtValue(); 1321a36588eSKazu Hirata return std::nullopt; 1330813700dSMatthias Springer } 1340813700dSMatthias Springer 13590ecfa2aSNicolas Vasilache std::optional<SmallVector<int64_t>> 13690ecfa2aSNicolas Vasilache getConstantIntValues(ArrayRef<OpFoldResult> ofrs) { 13790ecfa2aSNicolas Vasilache bool failed = false; 13890ecfa2aSNicolas Vasilache SmallVector<int64_t> res = llvm::map_to_vector(ofrs, [&](OpFoldResult ofr) { 13990ecfa2aSNicolas Vasilache auto cv = getConstantIntValue(ofr); 14090ecfa2aSNicolas Vasilache if (!cv.has_value()) 14190ecfa2aSNicolas Vasilache failed = true; 142b52885bcSKazu Hirata return cv.value_or(0); 14390ecfa2aSNicolas Vasilache }); 14490ecfa2aSNicolas Vasilache if (failed) 14590ecfa2aSNicolas Vasilache return std::nullopt; 14690ecfa2aSNicolas Vasilache return res; 14790ecfa2aSNicolas Vasilache } 14890ecfa2aSNicolas Vasilache 149f3676c32SIvan Butygin bool isConstantIntValue(OpFoldResult ofr, int64_t value) { 150f3676c32SIvan Butygin auto val = getConstantIntValue(ofr); 151f3676c32SIvan Butygin return val && *val == value; 152f3676c32SIvan Butygin } 153f3676c32SIvan Butygin 15498e838a8SMax191 bool areAllConstantIntValue(ArrayRef<OpFoldResult> ofrs, int64_t value) { 15598e838a8SMax191 return llvm::all_of( 15698e838a8SMax191 ofrs, [&](OpFoldResult ofr) { return isConstantIntValue(ofr, value); }); 15798e838a8SMax191 } 15898e838a8SMax191 15998e838a8SMax191 bool areConstantIntValues(ArrayRef<OpFoldResult> ofrs, 16098e838a8SMax191 ArrayRef<int64_t> values) { 16198e838a8SMax191 if (ofrs.size() != values.size()) 16298e838a8SMax191 return false; 16398e838a8SMax191 std::optional<SmallVector<int64_t>> constOfrs = getConstantIntValues(ofrs); 16498e838a8SMax191 return constOfrs && llvm::equal(constOfrs.value(), values); 16598e838a8SMax191 } 16698e838a8SMax191 1670813700dSMatthias Springer /// Return true if ofr1 and ofr2 are the same integer constant attribute values 1680813700dSMatthias Springer /// or the same SSA value. 1690813700dSMatthias Springer /// Ignore integer bitwidth and type mismatch that come from the fact there is 1700813700dSMatthias Springer /// no IndexAttr and that IndexType has no bitwidth. 1710813700dSMatthias Springer bool isEqualConstantIntOrValue(OpFoldResult ofr1, OpFoldResult ofr2) { 1720813700dSMatthias Springer auto cst1 = getConstantIntValue(ofr1), cst2 = getConstantIntValue(ofr2); 1730813700dSMatthias Springer if (cst1 && cst2 && *cst1 == *cst2) 1740813700dSMatthias Springer return true; 17568f58812STres Popp auto v1 = llvm::dyn_cast_if_present<Value>(ofr1), 17668f58812STres Popp v2 = llvm::dyn_cast_if_present<Value>(ofr2); 1770813700dSMatthias Springer return v1 && v1 == v2; 1780813700dSMatthias Springer } 1794db3a649SLorenzo Chelini 1804521b113SNicolas Vasilache bool isEqualConstantIntOrValueArray(ArrayRef<OpFoldResult> ofrs1, 1814521b113SNicolas Vasilache ArrayRef<OpFoldResult> ofrs2) { 1824521b113SNicolas Vasilache if (ofrs1.size() != ofrs2.size()) 1834521b113SNicolas Vasilache return false; 1844521b113SNicolas Vasilache for (auto [ofr1, ofr2] : llvm::zip_equal(ofrs1, ofrs2)) 1854521b113SNicolas Vasilache if (!isEqualConstantIntOrValue(ofr1, ofr2)) 1864521b113SNicolas Vasilache return false; 1874521b113SNicolas Vasilache return true; 1884521b113SNicolas Vasilache } 1894521b113SNicolas Vasilache 190a9733b8aSLorenzo Chelini /// Return a vector of OpFoldResults with the same size a staticValues, but all 191a9733b8aSLorenzo Chelini /// elements for which ShapedType::isDynamic is true, will be replaced by 192a9733b8aSLorenzo Chelini /// dynamicValues. 193a9733b8aSLorenzo Chelini SmallVector<OpFoldResult> getMixedValues(ArrayRef<int64_t> staticValues, 194*092372daSMaheshRavishankar ValueRange dynamicValues, 195*092372daSMaheshRavishankar MLIRContext *context) { 196a9733b8aSLorenzo Chelini SmallVector<OpFoldResult> res; 197a9733b8aSLorenzo Chelini res.reserve(staticValues.size()); 198a9733b8aSLorenzo Chelini unsigned numDynamic = 0; 199a9733b8aSLorenzo Chelini unsigned count = static_cast<unsigned>(staticValues.size()); 200a9733b8aSLorenzo Chelini for (unsigned idx = 0; idx < count; ++idx) { 201a9733b8aSLorenzo Chelini int64_t value = staticValues[idx]; 202a9733b8aSLorenzo Chelini res.push_back(ShapedType::isDynamic(value) 203a9733b8aSLorenzo Chelini ? OpFoldResult{dynamicValues[numDynamic++]} 204*092372daSMaheshRavishankar : OpFoldResult{IntegerAttr::get( 205*092372daSMaheshRavishankar IntegerType::get(context, 64), staticValues[idx])}); 206a9733b8aSLorenzo Chelini } 207a9733b8aSLorenzo Chelini return res; 208a9733b8aSLorenzo Chelini } 209*092372daSMaheshRavishankar SmallVector<OpFoldResult> getMixedValues(ArrayRef<int64_t> staticValues, 210*092372daSMaheshRavishankar ValueRange dynamicValues, Builder &b) { 211*092372daSMaheshRavishankar return getMixedValues(staticValues, dynamicValues, b.getContext()); 212*092372daSMaheshRavishankar } 213a9733b8aSLorenzo Chelini 214a9733b8aSLorenzo Chelini /// Decompose a vector of mixed static or dynamic values into the corresponding 215a9733b8aSLorenzo Chelini /// pair of arrays. This is the inverse function of `getMixedValues`. 21697069a86SGaurav Shukla std::pair<SmallVector<int64_t>, SmallVector<Value>> 21797069a86SGaurav Shukla decomposeMixedValues(const SmallVectorImpl<OpFoldResult> &mixedValues) { 218a9733b8aSLorenzo Chelini SmallVector<int64_t> staticValues; 219a9733b8aSLorenzo Chelini SmallVector<Value> dynamicValues; 220a9733b8aSLorenzo Chelini for (const auto &it : mixedValues) { 221129f1001SKazu Hirata if (auto attr = dyn_cast<Attribute>(it)) { 222129f1001SKazu Hirata staticValues.push_back(cast<IntegerAttr>(attr).getInt()); 223a9733b8aSLorenzo Chelini } else { 224a9733b8aSLorenzo Chelini staticValues.push_back(ShapedType::kDynamic); 225129f1001SKazu Hirata dynamicValues.push_back(cast<Value>(it)); 226a9733b8aSLorenzo Chelini } 227a9733b8aSLorenzo Chelini } 22897069a86SGaurav Shukla return {staticValues, dynamicValues}; 229a9733b8aSLorenzo Chelini } 230a9733b8aSLorenzo Chelini 231aafb52d7SNicolas Vasilache /// Helper to sort `values` according to matching `keys`. 232aafb52d7SNicolas Vasilache template <typename K, typename V> 233aafb52d7SNicolas Vasilache static SmallVector<V> 234aafb52d7SNicolas Vasilache getValuesSortedByKeyImpl(ArrayRef<K> keys, ArrayRef<V> values, 235aafb52d7SNicolas Vasilache llvm::function_ref<bool(K, K)> compare) { 236aafb52d7SNicolas Vasilache if (keys.empty()) 237aafb52d7SNicolas Vasilache return SmallVector<V>{values}; 238aafb52d7SNicolas Vasilache assert(keys.size() == values.size() && "unexpected mismatching sizes"); 239aafb52d7SNicolas Vasilache auto indices = llvm::to_vector(llvm::seq<int64_t>(0, values.size())); 240aafb52d7SNicolas Vasilache std::sort(indices.begin(), indices.end(), 241aafb52d7SNicolas Vasilache [&](int64_t i, int64_t j) { return compare(keys[i], keys[j]); }); 242aafb52d7SNicolas Vasilache SmallVector<V> res; 243aafb52d7SNicolas Vasilache res.reserve(values.size()); 244aafb52d7SNicolas Vasilache for (int64_t i = 0, e = indices.size(); i < e; ++i) 245aafb52d7SNicolas Vasilache res.push_back(values[indices[i]]); 246aafb52d7SNicolas Vasilache return res; 247aafb52d7SNicolas Vasilache } 248aafb52d7SNicolas Vasilache 249aafb52d7SNicolas Vasilache SmallVector<Value> 250aafb52d7SNicolas Vasilache getValuesSortedByKey(ArrayRef<Attribute> keys, ArrayRef<Value> values, 251aafb52d7SNicolas Vasilache llvm::function_ref<bool(Attribute, Attribute)> compare) { 252aafb52d7SNicolas Vasilache return getValuesSortedByKeyImpl(keys, values, compare); 253aafb52d7SNicolas Vasilache } 254aafb52d7SNicolas Vasilache 255aafb52d7SNicolas Vasilache SmallVector<OpFoldResult> 256aafb52d7SNicolas Vasilache getValuesSortedByKey(ArrayRef<Attribute> keys, ArrayRef<OpFoldResult> values, 257aafb52d7SNicolas Vasilache llvm::function_ref<bool(Attribute, Attribute)> compare) { 258aafb52d7SNicolas Vasilache return getValuesSortedByKeyImpl(keys, values, compare); 259aafb52d7SNicolas Vasilache } 260aafb52d7SNicolas Vasilache 261768615bbSNicolas Vasilache SmallVector<int64_t> 262768615bbSNicolas Vasilache getValuesSortedByKey(ArrayRef<Attribute> keys, ArrayRef<int64_t> values, 263768615bbSNicolas Vasilache llvm::function_ref<bool(Attribute, Attribute)> compare) { 264768615bbSNicolas Vasilache return getValuesSortedByKeyImpl(keys, values, compare); 265768615bbSNicolas Vasilache } 266768615bbSNicolas Vasilache 2673a8f161aSAlexander Belyaev /// Return the number of iterations for a loop with a lower bound `lb`, upper 2683a8f161aSAlexander Belyaev /// bound `ub` and step `step`. 2693a8f161aSAlexander Belyaev std::optional<int64_t> constantTripCount(OpFoldResult lb, OpFoldResult ub, 2703a8f161aSAlexander Belyaev OpFoldResult step) { 2713a8f161aSAlexander Belyaev if (lb == ub) 2723a8f161aSAlexander Belyaev return 0; 2733a8f161aSAlexander Belyaev 2743a8f161aSAlexander Belyaev std::optional<int64_t> lbConstant = getConstantIntValue(lb); 2753a8f161aSAlexander Belyaev if (!lbConstant) 2763a8f161aSAlexander Belyaev return std::nullopt; 2773a8f161aSAlexander Belyaev std::optional<int64_t> ubConstant = getConstantIntValue(ub); 2783a8f161aSAlexander Belyaev if (!ubConstant) 2793a8f161aSAlexander Belyaev return std::nullopt; 2803a8f161aSAlexander Belyaev std::optional<int64_t> stepConstant = getConstantIntValue(step); 2813a8f161aSAlexander Belyaev if (!stepConstant) 2823a8f161aSAlexander Belyaev return std::nullopt; 2833a8f161aSAlexander Belyaev 2840fb216fbSRamkumar Ramachandra return llvm::divideCeilSigned(*ubConstant - *lbConstant, *stepConstant); 2853a8f161aSAlexander Belyaev } 2863a8f161aSAlexander Belyaev 28768f0bc6fSRik Huijzer bool hasValidSizesOffsets(SmallVector<int64_t> sizesOrOffsets) { 28868f0bc6fSRik Huijzer return llvm::none_of(sizesOrOffsets, [](int64_t value) { 28968f0bc6fSRik Huijzer return !ShapedType::isDynamic(value) && value < 0; 29068f0bc6fSRik Huijzer }); 29168f0bc6fSRik Huijzer } 29268f0bc6fSRik Huijzer 29368f0bc6fSRik Huijzer bool hasValidStrides(SmallVector<int64_t> strides) { 29468f0bc6fSRik Huijzer return llvm::none_of(strides, [](int64_t value) { 29568f0bc6fSRik Huijzer return !ShapedType::isDynamic(value) && value == 0; 29668f0bc6fSRik Huijzer }); 29768f0bc6fSRik Huijzer } 29868f0bc6fSRik Huijzer 29968386a74SMatthias Springer LogicalResult foldDynamicIndexList(SmallVectorImpl<OpFoldResult> &ofrs, 30068f0bc6fSRik Huijzer bool onlyNonNegative, bool onlyNonZero) { 301b2826c02SMatthias Springer bool valuesChanged = false; 302b2826c02SMatthias Springer for (OpFoldResult &ofr : ofrs) { 303129f1001SKazu Hirata if (isa<Attribute>(ofr)) 304b2826c02SMatthias Springer continue; 305b2826c02SMatthias Springer Attribute attr; 306129f1001SKazu Hirata if (matchPattern(cast<Value>(ofr), m_Constant(&attr))) { 30768386a74SMatthias Springer // Note: All ofrs have index type. 30868386a74SMatthias Springer if (onlyNonNegative && *getConstantIntValue(attr) < 0) 30968386a74SMatthias Springer continue; 31068f0bc6fSRik Huijzer if (onlyNonZero && *getConstantIntValue(attr) == 0) 31168f0bc6fSRik Huijzer continue; 312b2826c02SMatthias Springer ofr = attr; 313b2826c02SMatthias Springer valuesChanged = true; 314b2826c02SMatthias Springer } 315b2826c02SMatthias Springer } 316b2826c02SMatthias Springer return success(valuesChanged); 317b2826c02SMatthias Springer } 318b2826c02SMatthias Springer 31968f0bc6fSRik Huijzer LogicalResult 32068f0bc6fSRik Huijzer foldDynamicOffsetSizeList(SmallVectorImpl<OpFoldResult> &offsetsOrSizes) { 32168f0bc6fSRik Huijzer return foldDynamicIndexList(offsetsOrSizes, /*onlyNonNegative=*/true, 32268f0bc6fSRik Huijzer /*onlyNonZero=*/false); 32368f0bc6fSRik Huijzer } 32468f0bc6fSRik Huijzer 32568f0bc6fSRik Huijzer LogicalResult foldDynamicStrideList(SmallVectorImpl<OpFoldResult> &strides) { 32668f0bc6fSRik Huijzer return foldDynamicIndexList(strides, /*onlyNonNegative=*/false, 32768f0bc6fSRik Huijzer /*onlyNonZero=*/true); 32868f0bc6fSRik Huijzer } 32968f0bc6fSRik Huijzer 3300813700dSMatthias Springer } // namespace mlir 331