90#include <mlir/Dialect/SCF/IR/SCF.h>
91#include <mlir/IR/BuiltinOps.h>
92#include <mlir/Pass/PassManager.h>
93#include <mlir/Transforms/DialectConversion.h>
94#include <mlir/Transforms/Passes.h>
96#include <llvm/Support/Debug.h>
102#define GEN_PASS_DEF_ARRAYTOSCALARPASS
113#define DEBUG_TYPE "llzk-array-to-scalar"
119 return at.hasStaticShape() && !llvm::isa<NoneType>(at.
getElementType()) ? at :
nullptr;
123inline ArrayType splittableArray(Type t) {
124 if (
ArrayType at = dyn_cast<ArrayType>(t)) {
125 return splittableArray(at);
133inline bool containsSplittableArrayType(ArrayRef<Type> types) {
134 for (Type t : types) {
135 if (splittableArray(t)) {
143template <
typename T>
bool containsSplittableArrayType(ValueTypeRange<T> types) {
144 for (Type t : types) {
145 if (splittableArray(t)) {
154size_t splitArrayTypeTo(Type t, SmallVector<Type> &collect) {
160 collect.push_back(t);
166template <
typename TypeCollection>
167inline void splitArrayTypeTo(
168 TypeCollection types, SmallVector<Type> &collect, SmallVector<size_t> *originalIdxToSize
170 for (Type t : types) {
171 size_t count = splitArrayTypeTo(t, collect);
172 if (originalIdxToSize) {
173 originalIdxToSize->push_back(count);
180template <
typename TypeCollection>
181inline SmallVector<Type>
182splitArrayType(TypeCollection types, SmallVector<size_t> *originalIdxToSize =
nullptr) {
183 SmallVector<Type> collect;
184 splitArrayTypeTo(types, collect, originalIdxToSize);
189static std::string formatSplitArrayIndexSuffix(ArrayAttr index) {
191 llvm::raw_string_ostream os(suffix);
192 for (Attribute attr : index) {
194 attr.print(os,
true);
201static SmallVector<std::string> getSplitArrayIndexSuffixes(Type type) {
202 SmallVector<std::string> suffixes;
203 if (
ArrayType at = splittableArray(type)) {
205 assert(indices.has_value() &&
"static-shape arrays must provide subelement indices");
206 suffixes.reserve(indices->size());
207 for (ArrayAttr index : *indices) {
208 suffixes.push_back(formatSplitArrayIndexSuffix(index));
215CallOp newCallOpWithSplitResults(
218 OpBuilder::InsertionGuard guard(rewriter);
219 rewriter.setInsertionPointAfter(oldCall);
221 Operation::result_range oldResults = oldCall.getResults();
223 oldCall.getLoc(), splitArrayType(oldResults.getTypes()), oldCall, adaptor.
getMapOperands(),
227 auto newResults = newCall.getResults().begin();
228 for (Value oldVal : oldResults) {
229 if (
ArrayType at = splittableArray(oldVal.getType())) {
230 Location loc = oldVal.getLoc();
233 rewriter.replaceAllUsesWith(oldVal, newArray);
239 assert(std::cmp_equal(allIndices->size(), at.getNumElements()));
240 for (ArrayAttr subIdx : allIndices.value()) {
245 rewriter.replaceAllUsesWith(oldVal, *newResults);
250 rewriter.eraseOp(oldCall);
257void processInputOperand(
258 Location loc, Value operand, SmallVector<Value> &newOperands,
259 ConversionPatternRewriter &rewriter
261 if (
ArrayType at = splittableArray(operand.getType())) {
263 assert(indices.has_value() &&
"passed earlier hasStaticShape() check");
264 for (ArrayAttr index : indices.value()) {
268 newOperands.push_back(operand);
273void processInputOperands(
274 ValueRange operands, MutableOperandRange outputOpRef, Operation *op,
275 ConversionPatternRewriter &rewriter
277 SmallVector<Value> newOperands;
278 for (Value v : operands) {
279 processInputOperand(op->getLoc(), v, newOperands, rewriter);
281 rewriter.modifyOpInPlace(op, [&outputOpRef, &newOperands]() {
282 outputOpRef.assign(ValueRange(newOperands));
288enum Direction : std::uint8_t {
297template <Direction dir>
298inline void rewriteImpl(
300 ConversionPatternRewriter &rewriter
303 Location loc = op.getLoc();
304 MLIRContext *ctx = op.getContext();
313 assert(std::cmp_equal(subIndices->size(), smallType.getNumElements()));
314 for (ArrayAttr indexingTail : subIndices.value()) {
315 SmallVector<Attribute> joined;
316 joined.append(indexAsAttr.begin(), indexAsAttr.end());
317 joined.append(indexingTail.begin(), indexingTail.end());
318 ArrayAttr fullIndex = ArrayAttr::get(ctx, joined);
320 if constexpr (dir == Direction::SMALL_TO_LARGE) {
323 }
else if constexpr (dir == Direction::LARGE_TO_SMALL) {
333class SplitInsertArrayOp :
public OpConversionPattern<InsertArrayOp> {
335 using OpConversionPattern<
InsertArrayOp>::OpConversionPattern;
338 return !containsSplittableArrayType(op.
getRvalue().getType());
341 LogicalResult match(
InsertArrayOp op)
const override {
return failure(legal(op)); }
344 rewrite(
InsertArrayOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter)
const override {
346 rewriteImpl<SMALL_TO_LARGE>(
347 llvm::cast<ArrayAccessOpInterface>(op.getOperation()), at, adaptor.getRvalue(),
348 adaptor.getArrRef(), rewriter
350 rewriter.eraseOp(op);
355class SplitExtractArrayOp :
public OpConversionPattern<ExtractArrayOp> {
360 return !containsSplittableArrayType(op.
getResult().getType());
363 LogicalResult match(
ExtractArrayOp op)
const override {
return failure(legal(op)); }
366 ExtractArrayOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter
370 auto newArray = rewriter.replaceOpWithNewOp<
CreateArrayOp>(op, at);
371 rewriteImpl<LARGE_TO_SMALL>(
372 llvm::cast<ArrayAccessOpInterface>(op.getOperation()), at, newArray, adaptor.getArrRef(),
379class SplitInitFromCreateArrayOp :
public OpConversionPattern<CreateArrayOp> {
381 using OpConversionPattern<
CreateArrayOp>::OpConversionPattern;
385 LogicalResult match(
CreateArrayOp op)
const override {
return failure(legal(op)); }
388 rewrite(
CreateArrayOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter)
const override {
392 rewriter.setInsertionPointAfter(op);
393 Location loc = op.getLoc();
395 for (
auto [i, init] : llvm::enumerate(adaptor.getElements())) {
397 std::optional<SmallVector<Value>> multiDimIdxVals =
401 assert(multiDimIdxVals.has_value());
409class SplitArrayInFuncDefOp :
public OpConversionPattern<FuncDefOp> {
411 using OpConversionPattern<
FuncDefOp>::OpConversionPattern;
418 LogicalResult match(
FuncDefOp op)
const override {
return failure(legal(op)); }
420 void rewrite(
FuncDefOp op, OpAdaptor, ConversionPatternRewriter &rewriter)
const override {
423 SmallVector<size_t> originalInputIdxToSize, originalResultIdxToSize;
428 SmallVector<Type> convertInputs(ArrayRef<Type> origTypes)
override {
429 return splitArrayType(origTypes, &originalInputIdxToSize);
431 SmallVector<Type> convertResults(ArrayRef<Type> origTypes)
override {
432 return splitArrayType(origTypes, &originalResultIdxToSize);
434 ArrayAttr convertInputAttrs(ArrayAttr origAttrs, SmallVector<Type> newTypes)
override {
441 ArrayAttr convertResultAttrs(ArrayAttr origAttrs, SmallVector<Type> newTypes)
override {
453 void processBlockArgs(Block &entryBlock, RewriterBase &rewriter)
override {
454 OpBuilder::InsertionGuard guard(rewriter);
455 rewriter.setInsertionPointToStart(&entryBlock);
457 for (
unsigned i = 0; i < entryBlock.getNumArguments();) {
458 Value oldV = entryBlock.getArgument(i);
459 if (
ArrayType at = splittableArray(oldV.getType())) {
460 Location loc = oldV.getLoc();
463 rewriter.replaceAllUsesWith(oldV, newArray);
465 entryBlock.eraseArgument(i);
470 assert(std::cmp_equal(allIndices->size(), at.getNumElements()));
471 for (ArrayAttr subIdx : allIndices.value()) {
472 BlockArgument newArg = entryBlock.insertArgument(i, at.
getElementType(), loc);
484 ArrayAttr resultAttrs = op.getAllResultAttrs();
486 return op.getArgNameAttr(i);
487 }, getSplitArrayIndexSuffixes);
489 return getAttrAtIndexWithName(resultAttrs, i, RES_NAME_ATTR_NAME);
490 }, getSplitArrayIndexSuffixes);
493 Impl(op).convert(op, rewriter);
498class SplitArrayInReturnOp :
public OpConversionPattern<ReturnOp> {
500 using OpConversionPattern<
ReturnOp>::OpConversionPattern;
502 inline static bool legal(
ReturnOp op) {
503 return !containsSplittableArrayType(op.
getOperands().getTypes());
506 LogicalResult match(
ReturnOp op)
const override {
return failure(legal(op)); }
508 void rewrite(
ReturnOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter)
const override {
514class SplitArrayInCallOp :
public OpConversionPattern<CallOp> {
516 using OpConversionPattern<
CallOp>::OpConversionPattern;
518 inline static bool legal(
CallOp op) {
519 return !containsSplittableArrayType(op.
getArgOperands().getTypes()) &&
520 !containsSplittableArrayType(op.getResultTypes());
523 LogicalResult match(
CallOp op)
const override {
return failure(legal(op)); }
525 void rewrite(
CallOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter)
const override {
527 CallOp newCall = newCallOpWithSplitResults(op, adaptor, rewriter);
528 processInputOperands(
535class ReplaceKnownArrayLengthOp :
public OpConversionPattern<ArrayLengthOp> {
537 using OpConversionPattern<
ArrayLengthOp>::OpConversionPattern;
540 static std::optional<llvm::APInt> getDimSizeIfKnown(Value dimIdx,
ArrayType baseArrType) {
541 if (baseArrType.hasStaticShape()) {
543 if (mlir::matchPattern(dimIdx, mlir::m_ConstantInt(&idxAP))) {
544 std::optional<int64_t> signedIdx = idxAP.trySExtValue();
545 if (!signedIdx || *signedIdx < 0) {
550 if (idx >= dimSizes.size()) {
553 Attribute dimSizeAttr = dimSizes[idx];
554 if (mlir::matchPattern(dimSizeAttr, mlir::m_ConstantInt(&idxAP))) {
567 LogicalResult match(
ArrayLengthOp op)
const override {
return failure(legal(op)); }
570 rewrite(
ArrayLengthOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter)
const override {
571 ArrayType arrTy = dyn_cast<ArrayType>(adaptor.getArrRef().getType());
573 std::optional<llvm::APInt> len = getDimSizeIfKnown(adaptor.getDim(), arrTy);
574 assert(len.has_value());
575 rewriter.replaceOpWithNewOp<arith::ConstantIndexOp>(op,
llzk::fromAPInt(len.value()));
580using MemberInfo = std::pair<StringAttr, Type>;
582using LocalMemberReplacementMap = DenseMap<ArrayAttr, MemberInfo>;
584using MemberReplacementMap = DenseMap<StructDefOp, DenseMap<StringAttr, LocalMemberReplacementMap>>;
587class SplitArrayInMemberDefOp :
public OpConversionPattern<MemberDefOp> {
588 SymbolTableCollection &tables;
589 MemberReplacementMap &repMapRef;
592 SplitArrayInMemberDefOp(
593 MLIRContext *ctx, SymbolTableCollection &symTables, MemberReplacementMap &memberRepMap
595 : OpConversionPattern<MemberDefOp>(ctx), tables(symTables), repMapRef(memberRepMap) {}
597 inline static bool legal(
MemberDefOp op) {
return !containsSplittableArrayType(op.
getType()); }
599 LogicalResult match(
MemberDefOp op)
const override {
return failure(legal(op)); }
601 void rewrite(
MemberDefOp op, OpAdaptor, ConversionPatternRewriter &rewriter)
const override {
604 LocalMemberReplacementMap &localRepMapRef = repMapRef[inStruct][op.
getSymNameAttr()];
609 assert(subIdxs.has_value());
612 SymbolTable &structSymbolTable = tables.getSymbolTable(inStruct);
613 for (ArrayAttr idx : subIdxs.value()) {
620 localRepMapRef[idx] = std::make_pair(structSymbolTable.insert(newMember), elemTy);
622 rewriter.eraseOp(op);
628 SplitArrayInMemberWriteOp, MemberWriteOp, void *, ArrayAttr> {
634 return !containsSplittableArrayType(op.
getVal().getType());
637 static void *genHeader(
MemberWriteOp, ConversionPatternRewriter &) {
return nullptr; }
640 Location loc,
void *, ArrayAttr idx, MemberInfo newMember, OpAdaptor adaptor,
641 ConversionPatternRewriter &rewriter
645 loc, adaptor.getComponent(), FlatSymbolRefAttr::get(newMember.first), scalarRead
652class SplitArrayInMemberReadOp
654 SplitArrayInMemberReadOp, MemberReadOp, CreateArrayOp, ArrayAttr> {
661 return !containsSplittableArrayType(op.getResult().getType());
666 rewriter.create<
CreateArrayOp>(op.getLoc(), llvm::cast<ArrayType>(op.getType()));
667 rewriter.replaceAllUsesWith(op, newArray);
672 Location loc,
CreateArrayOp newArray, ArrayAttr idx, MemberInfo newMember, OpAdaptor adaptor,
673 ConversionPatternRewriter &rewriter
676 loc, newMember.second, adaptor.getComponent(), newMember.first
683static void baseTargetSetup(ConversionTarget &target) {
684 target.addLegalDialect<
690 target.addLegalOp<ModuleOp>();
694class NondetToNewArray :
public OpConversionPattern<NonDetOp> {
695 using OpConversionPattern<
NonDetOp>::OpConversionPattern;
696 LogicalResult matchAndRewrite(
697 NonDetOp nondetOp, OpAdaptor, ConversionPatternRewriter &rewriter
699 if (
auto at = dyn_cast<ArrayType>(nondetOp.getType())) {
700 auto wildcardTy = llvm::cast<ArrayType>(replaceAffineMapArrayDimsWithWildcards(at));
701 auto newArray = rewriter.create<
CreateArrayOp>(nondetOp.getLoc(), wildcardTy);
702 if (wildcardTy == at) {
703 rewriter.replaceOp(nondetOp, newArray);
706 rewriter.replaceOp(nondetOp,
cast.getResult());
715static LogicalResult step0(ModuleOp modOp) {
716 MLIRContext *ctx = modOp.getContext();
717 RewritePatternSet patterns {ctx};
718 patterns.add<NondetToNewArray>(ctx);
719 ConversionTarget target {*ctx};
721 baseTargetSetup(target);
722 target.addDynamicallyLegalOp<
NonDetOp>([](
NonDetOp op) {
return !isa<ArrayType>(op.getType()); });
724 return applyFullConversion(modOp, target, std::move(patterns));
729step1(ModuleOp modOp, SymbolTableCollection &symTables, MemberReplacementMap &memberRepMap) {
730 MLIRContext *ctx = modOp.getContext();
732 RewritePatternSet patterns(ctx);
734 patterns.add<SplitArrayInMemberDefOp>(ctx, symTables, memberRepMap);
736 ConversionTarget target(*ctx);
737 baseTargetSetup(target);
738 target.addDynamicallyLegalOp<
MemberDefOp>(SplitArrayInMemberDefOp::legal);
740 LLVM_DEBUG(llvm::dbgs() <<
"Begin step 1: split array-type members\n";);
741 return applyFullConversion(modOp, target, std::move(patterns));
747step2(ModuleOp modOp, SymbolTableCollection &symTables,
const MemberReplacementMap &memberRepMap) {
748 MLIRContext *ctx = modOp.getContext();
750 RewritePatternSet patterns(ctx);
753 SplitInitFromCreateArrayOp,
756 SplitArrayInFuncDefOp,
757 SplitArrayInReturnOp,
759 ReplaceKnownArrayLengthOp
765 SplitArrayInMemberWriteOp,
766 SplitArrayInMemberReadOp
768 >(ctx, symTables, memberRepMap);
770 ConversionTarget target(*ctx);
771 baseTargetSetup(target);
772 target.addDynamicallyLegalOp<
CreateArrayOp>(SplitInitFromCreateArrayOp::legal);
773 target.addDynamicallyLegalOp<
InsertArrayOp>(SplitInsertArrayOp::legal);
774 target.addDynamicallyLegalOp<
ExtractArrayOp>(SplitExtractArrayOp::legal);
775 target.addDynamicallyLegalOp<
FuncDefOp>(SplitArrayInFuncDefOp::legal);
776 target.addDynamicallyLegalOp<
ReturnOp>(SplitArrayInReturnOp::legal);
777 target.addDynamicallyLegalOp<
CallOp>(SplitArrayInCallOp::legal);
778 target.addDynamicallyLegalOp<
ArrayLengthOp>(ReplaceKnownArrayLengthOp::legal);
779 target.addDynamicallyLegalOp<
MemberWriteOp>(SplitArrayInMemberWriteOp::legal);
780 target.addDynamicallyLegalOp<
MemberReadOp>(SplitArrayInMemberReadOp::legal);
782 LLVM_DEBUG(llvm::dbgs() <<
"Begin step 2: update/split other array ops\n";);
783 return applyFullConversion(modOp, target, std::move(patterns));
792static bool mayWriteToIndex(
WriteArrayOp writeOp, ArrayAttr index) {
793 ArrayAttr writeIndex = getIndexAsAttr(writeOp);
794 return !writeIndex || writeIndex == index;
798static bool hasEarlierWriteInBlock(
ReadArrayOp readOp, ArrayAttr readIndex) {
800 for (Operation &op : *readOp->getBlock()) {
801 if (&op == readOp.getOperation()) {
805 if (
auto writeOp = dyn_cast<WriteArrayOp>(&op)) {
806 if (writeOp.
getArrRef() == arrRef && mayWriteToIndex(writeOp, readIndex)) {
814 if (writeOp.getArrRef() == arrRef && mayWriteToIndex(writeOp, readIndex)) {
815 return WalkResult::interrupt();
817 return WalkResult::advance();
818 }).wasInterrupted()) {
826static std::optional<WriteArrayOp> findPrecedingWriteForIfRead(
ReadArrayOp readOp) {
827 ArrayAttr readIndex = getIndexAsAttr(readOp);
833 auto ifOp = readOp->getParentOfType<scf::IfOp>();
834 if (!ifOp || readOp->getBlock()->getParentOp() != ifOp.getOperation()) {
837 if (hasEarlierWriteInBlock(readOp, readIndex)) {
841 Block *ifBlock = ifOp->getBlock();
848 for (Operation &op : *ifBlock) {
849 if (&op == ifOp.getOperation()) {
853 if (
auto writeOp = dyn_cast<WriteArrayOp>(&op)) {
854 if (writeOp.getArrRef() != arrRef) {
858 if (mayWriteToIndex(writeOp, readIndex)) {
859 ArrayAttr writeIndex = getIndexAsAttr(writeOp);
860 replacement = writeIndex == readIndex ? writeOp :
WriteArrayOp();
866 if (op.walk([arrRef, readIndex, &replacement](
WriteArrayOp writeOp) {
867 if (writeOp.getArrRef() == arrRef && mayWriteToIndex(writeOp, readIndex)) {
868 replacement = WriteArrayOp();
869 return WalkResult::interrupt();
871 return WalkResult::advance();
872 }).wasInterrupted()) {
877 return replacement ? std::make_optional(replacement) : std::nullopt;
882static void step3(ModuleOp modOp) {
883 SmallVector<std::pair<ReadArrayOp, Value>> replacements;
885 if (std::optional<WriteArrayOp> writeOp = findPrecedingWriteForIfRead(readOp)) {
886 replacements.emplace_back(readOp, writeOp->getRvalue());
890 for (
auto [readOp, value] : replacements) {
891 readOp.
getResult().replaceAllUsesWith(value);
898 using Base = ArrayToScalarPassBase<PassImpl>;
901 void runOnOperation()
override {
902 ModuleOp module = getOperation();
904 if (failed(step0(module))) {
905 return signalPassFailure();
908 llvm::dbgs() <<
"After step 0:\n";
917 SymbolTableCollection symTables;
918 MemberReplacementMap memberRepMap;
919 if (failed(step1(module, symTables, memberRepMap))) {
920 return signalPassFailure();
923 llvm::dbgs() <<
"After step 1:\n";
927 if (failed(step2(module, symTables, memberRepMap))) {
928 return signalPassFailure();
931 llvm::dbgs() <<
"After step 2:\n";
938 llvm::dbgs() <<
"After step 3:\n";
942 OpPassManager nestedPM(ModuleOp::getOperationName());
951 RemoveUnusedDiscardableAllocationsPassOptions {
957 if (failed(runPipeline(nestedPM, module))) {
962 llvm::dbgs() <<
"After SROA+Mem2Reg pipeline:\n";
Provides SpecializedSROA<AllocOpTy> and SpecializedMem2Reg<AllocOpTy>: pass templates that replicate ...
General helper for converting a FuncDefOp by changing its input and/or result types and the associate...
Common implementation for handling MemberWriteOp and MemberReadOp while destructuring an aggregate ty...
static void genWrite(::mlir::OpBuilder &bldr, ::mlir::Location loc, ::mlir::Value arrayRef, ::mlir::ValueRange indices, ::mlir::Value value)
Create an array.write or array.insert for one concrete element or subarray.
::mlir::Value genRead(::mlir::OpBuilder &bldr, ::mlir::Location loc, ::mlir::Value arrayRef, ::mlir::ValueRange indices)
Create an array.read or array.extract for one concrete element or subarray.
::mlir::ArrayAttr indexOperandsToAttributeArray()
Returns the multi-dimensional indices of the array access as an Attribute array or a null pointer if ...
Helper for converting between linear and multi-dimensional indexing with checks to ensure indices are...
static ArrayIndexGen from(ArrayType)
Construct new ArrayIndexGen. Will assert if hasStaticShape() is false.
std::optional< llvm::SmallVector< mlir::Value > > delinearize(int64_t, mlir::Location, mlir::OpBuilder &) const
inline ::llzk::array::ArrayType getArrRefType()
Gets the type of the referenced base array.
::mlir::TypedValue<::mlir::IndexType > getDim()
std::optional<::llvm::SmallVector<::mlir::ArrayAttr > > getSubelementIndices() const
Return a list of all valid indices for this ArrayType.
::mlir::Type getElementType() const
::llvm::ArrayRef<::mlir::Attribute > getDimensionSizes() const
::mlir::TypedValue<::llzk::array::ArrayType > getResult()
static constexpr ::llvm::StringLiteral getOperationName()
::mlir::MutableOperandRange getElementsMutable()
::mlir::Operation::operand_range getElements()
::mlir::TypedValue<::llzk::array::ArrayType > getRvalue()
::mlir::TypedValue<::mlir::Type > getResult()
::mlir::TypedValue<::llzk::array::ArrayType > getArrRef()
::mlir::TypedValue<::llzk::array::ArrayType > getArrRef()
bool hasPublicAttr()
Returns whether this member is a public output.
void setPublicAttr(bool newValue=true)
Adds or removes the unit llzk.pub attribute according to newValue.
::mlir::StringAttr getSymNameAttr()
::mlir::TypedValue<::mlir::Type > getVal()
::llvm::SmallVector< RangeT > getMapOperands()
::mlir::MutableOperandRange getArgOperandsMutable()
::mlir::Operation::operand_range getArgOperands()
::llvm::ArrayRef<::mlir::Type > getArgumentTypes()
Required by FunctionOpInterface.
::llvm::ArrayRef<::mlir::Type > getResultTypes()
Required by FunctionOpInterface.
::mlir::MutableOperandRange getOperandsMutable()
::mlir::Operation::operand_range getOperands()
constexpr char ARG_NAME_ATTR_NAME[]
Attribute name for source-level function argument names.
constexpr char RES_NAME_ATTR_NAME[]
Attribute name for source-level function result names.
std::unique_ptr<::mlir::Pass > createRemoveUnusedDiscardableAllocationsPass()
std::unique_ptr< mlir::Pass > createRemoveDeadValuesWorkaroundPass()
mlir::ArrayAttr replicateFunctionNameAttrsAsNeeded(mlir::ArrayAttr origAttrs, const llvm::SmallVector< size_t > &originalIdxToSize, const llvm::SmallVector< mlir::Type > &newTypes, llvm::StringRef functionNameAttrName, llvm::ArrayRef< std::optional< llvm::StringRef > > origNames={}, llvm::ArrayRef< llvm::StringRef > existingNames={}, llvm::ArrayRef< llvm::SmallVector< std::string > > splitNameSuffixes={})
Expand function arg/result attribute arrays to match a split signature, rewriting name attrs with the...
constexpr T checkedCast(U u) noexcept
std::unique_ptr< SpecializedMem2Reg< AllocOpTy > > createSpecializedMem2RegPass()
int64_t fromAPInt(const llvm::APInt &i)
function::CallOp createCallPreservingInstantiationOperands(mlir::Location loc, mlir::TypeRange newResultTypes, function::CallOp oldCall, llvm::ArrayRef< mlir::ValueRange > mapOperands, mlir::ValueRange argOperands, mlir::ConversionPatternRewriter &rewriter)
Rebuild a function.call while preserving explicit instantiation state from oldCall.
SplitFunctionNameInfo collectSplitFunctionNameInfo(mlir::ArrayRef< mlir::Type > origTypes, GetNameAttrFn &&getNameAttr, GetSplitSuffixesFn &&getSplitSuffixes)
Collect function arg/result names and split suffixes from a list of original types.
std::unique_ptr< SpecializedSROA< AllocOpTy > > createSpecializedSROAPass()
Cached function arg/result names and split suffixes used while rewriting a function signature.
llvm::SmallVector< std::optional< llvm::StringRef > > originalNames
llvm::SmallVector< llvm::StringRef > existingNames
llvm::SmallVector< llvm::SmallVector< std::string > > splitNameSuffixes