33#include <mlir/IR/BuiltinOps.h>
34#include <mlir/Pass/PassManager.h>
35#include <mlir/Transforms/DialectConversion.h>
36#include <mlir/Transforms/GreedyPatternRewriteDriver.h>
37#include <mlir/Transforms/WalkPatternRewriteDriver.h>
41#define GEN_PASS_DEF_WILDCARDARRAYSPECIALIZATIONPASS
45#define DEBUG_TYPE "llzk-specialize-wildcard-arrays"
59class ConversionTracker {
60 bool modified =
false;
61 DenseMap<StructType, SmallVector<StructType>> structSpecializations;
62 DenseMap<StructType, StructType> reverseSpecializations;
63 DenseSet<SymbolRefAttr> funcInstantiations;
66 bool isModified()
const {
return modified; }
67 void resetModifiedFlag() { modified =
false; }
68 void updateModifiedFlag(
bool currStepModified) { modified |= currStepModified; }
70 void recordInstantiation(SymbolRefAttr funcName) {
71 funcInstantiations.insert(funcName);
77 SmallVector<StructType> &specializations = structSpecializations[oldType];
78 if (llvm::is_contained(specializations, newType)) {
79 assert(reverseSpecializations.lookup(newType) == oldType);
82 specializations.push_back(newType);
83 auto [it, inserted] = reverseSpecializations.try_emplace(newType, oldType);
86 assert(inserted || it->second == oldType);
90 DenseSet<SymbolRefAttr> getInstantiatedDefinitionNames()
const {
91 DenseSet<SymbolRefAttr> instantiatedNames = funcInstantiations;
92 for (
const auto &[origRemoteTy, _] : structSpecializations) {
93 instantiatedNames.insert(origRemoteTy.getNameRef());
95 return instantiatedNames;
98 bool isLegalConversion(Type oldType, Type newType,
const char *patName)
const {
99 std::function<bool(Type, Type)> checkSpecializations = [&](Type oTy, Type nTy) {
100 if (
StructType oldStructType = llvm::dyn_cast<StructType>(oTy)) {
101 auto specializationIt = structSpecializations.find(oldStructType);
102 if (specializationIt != structSpecializations.end() &&
103 llvm::is_contained(specializationIt->second, nTy)) {
107 if (
StructType newStructType = llvm::dyn_cast<StructType>(nTy)) {
108 if (
StructType preImage = reverseSpecializations.lookup(newStructType)) {
119 llvm::dbgs() <<
'[' << patName <<
"] invalid type conversion from " << oldType <<
" to "
127 bool areLegalConversions(TypeRange oldTypes, TypeRange newTypes,
const char *patName)
const {
128 return oldTypes.size() == newTypes.size() &&
129 llvm::all_of(llvm::zip_equal(oldTypes, newTypes), [&](
auto pair) {
130 return isLegalConversion(std::get<0>(pair), std::get<1>(pair), patName);
136struct MatchFailureListener :
public RewriterBase::Listener {
137 bool hadFailure =
false;
139 void notifyMatchFailure(Location loc, function_ref<
void(Diagnostic &)> reasonCallback)
override {
140 InFlightDiagnostic diag = emitError(loc);
141 reasonCallback(*diag.getUnderlyingDiagnostic());
148applyAndFoldGreedily(ModuleOp modOp, ConversionTracker &tracker, RewritePatternSet &&patterns) {
149 bool currStepModified =
false;
150 MatchFailureListener failureListener;
151 LogicalResult result = applyPatternsGreedily(
152 modOp->getRegion(0), std::move(patterns),
153 GreedyRewriteConfig {.maxIterations = 20, .listener = &failureListener, .fold = true},
156 tracker.updateModifiedFlag(currStepModified);
157 return failure(result.failed() || failureListener.hadFailure);
161struct WildcardArraySpecializationInfo {
162 DenseMap<ArrayType, ArrayType> replacements;
163 SmallVector<std::pair<ArrayType, ArrayType>> ordered;
164 bool hasConflictingReplacements =
false;
166 bool empty()
const {
return ordered.empty(); }
169 ordered.emplace_back(oldTy, newTy);
170 auto it = replacements.find(oldTy);
171 if (it == replacements.end()) {
172 replacements.try_emplace(oldTy, newTy);
175 hasConflictingReplacements |= it->second != newTy;
179 SmallVector<Attribute> getConcreteTypeAttrs()
const {
180 SmallVector<Attribute> attrs;
181 attrs.reserve(ordered.size());
182 for (
const auto &[_, newTy] : ordered) {
183 attrs.push_back(TypeAttr::get(newTy));
189static void updateFuncSignature(
FuncDefOp func, FunctionType newFuncTy) {
191 if (oldFuncTy == newFuncTy) {
196 Region &body = func.getFunctionBody();
201 Block &entryBlock = body.front();
202 assert(entryBlock.getNumArguments() == newFuncTy.getNumInputs() &&
"function arity changed");
203 for (
auto [arg, newTy] : llvm::zip_equal(entryBlock.getArguments(), newFuncTy.getInputs())) {
210static bool containsWildcardArrayDims(Type type) {
211 if (
ArrayType arrTy = llvm::dyn_cast<ArrayType>(type)) {
212 if (llvm::any_of(arrTy.getDimensionSizes(), [](Attribute dim) {
213 if (IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(dim)) {
214 return isDynamic(intAttr);
220 return containsWildcardArrayDims(arrTy.getElementType());
222 if (
StructType structTy = llvm::dyn_cast<StructType>(type)) {
223 if (ArrayAttr params = structTy.getParams()) {
224 return llvm::any_of(params.getValue(), [](Attribute attr) {
225 if (TypeAttr typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
226 return containsWildcardArrayDims(typeAttr.getValue());
232 if (FunctionType funcTy = llvm::dyn_cast<FunctionType>(type)) {
233 return llvm::any_of(funcTy.getInputs(), containsWildcardArrayDims) ||
234 llvm::any_of(funcTy.getResults(), containsWildcardArrayDims);
241static LogicalResult collectWildcardArraySpecializations(
242 Type oldTy, Type newTy, WildcardArraySpecializationInfo &out,
243 std::optional<StructType> ignoredStructType = std::nullopt
245 if (ignoredStructType.has_value() && oldTy == *ignoredStructType &&
246 llvm::isa<StructType>(newTy)) {
252 if (FunctionType oldFuncTy = llvm::dyn_cast<FunctionType>(oldTy)) {
253 FunctionType newFuncTy = llvm::dyn_cast<FunctionType>(newTy);
254 if (!newFuncTy || oldFuncTy.getNumInputs() != newFuncTy.getNumInputs() ||
255 oldFuncTy.getNumResults() != newFuncTy.getNumResults()) {
258 for (
auto [oldInput, newInput] :
259 llvm::zip_equal(oldFuncTy.getInputs(), newFuncTy.getInputs())) {
260 if (failed(collectWildcardArraySpecializations(oldInput, newInput, out, ignoredStructType))) {
264 for (
auto [oldResult, newResult] :
265 llvm::zip_equal(oldFuncTy.getResults(), newFuncTy.getResults())) {
267 collectWildcardArraySpecializations(oldResult, newResult, out, ignoredStructType)
274 if (
StructType oldStructTy = llvm::dyn_cast<StructType>(oldTy)) {
275 StructType newStructTy = llvm::dyn_cast<StructType>(newTy);
279 ArrayAttr oldParams = oldStructTy.getParams();
280 ArrayAttr newParams = newStructTy.
getParams();
281 ArrayRef<Attribute> oldAttrs = oldParams ? oldParams.getValue() : ArrayRef<Attribute> {};
282 ArrayRef<Attribute> newAttrs = newParams ? newParams.getValue() : ArrayRef<Attribute> {};
283 if (oldAttrs.size() != newAttrs.size()) {
286 for (
auto [oldAttr, newAttr] : llvm::zip_equal(oldAttrs, newAttrs)) {
287 if (TypeAttr oldTypeAttr = llvm::dyn_cast<TypeAttr>(oldAttr)) {
288 TypeAttr newTypeAttr = llvm::dyn_cast<TypeAttr>(newAttr);
290 failed(collectWildcardArraySpecializations(
291 oldTypeAttr.getValue(), newTypeAttr.getValue(), out, ignoredStructType
299 ArrayType oldArrTy = llvm::dyn_cast<ArrayType>(oldTy);
300 ArrayType newArrTy = llvm::dyn_cast<ArrayType>(newTy);
301 if (!oldArrTy || !newArrTy) {
305 failed(collectWildcardArraySpecializations(
311 bool changed =
false;
312 for (
auto [oldDim, newDim] :
314 if (
auto oldInt = llvm::dyn_cast<IntegerAttr>(oldDim); oldInt &&
isDynamic(oldInt)) {
315 if (
auto newInt = llvm::dyn_cast<IntegerAttr>(newDim); newInt && !
isDynamic(newInt)) {
323 return out.record(oldArrTy, newArrTy);
326static bool functionTypeIsMoreConcrete(
327 FunctionType oldTy, FunctionType newTy,
const ConversionTracker &tracker,
const char *patName,
328 std::optional<StructType> ignoredStructType = std::nullopt
330 auto isCompatible = [&](Type oldType, Type newType) {
331 if (ignoredStructType.has_value() && oldType == *ignoredStructType &&
332 llvm::isa<StructType>(newType)) {
335 return tracker.isLegalConversion(oldType, newType, patName);
338 return oldTy.getNumInputs() == newTy.getNumInputs() &&
339 oldTy.getNumResults() == newTy.getNumResults() &&
340 llvm::all_of(llvm::zip_equal(oldTy.getInputs(), newTy.getInputs()), [&](
auto pair) {
341 return isCompatible(std::get<0>(pair), std::get<1>(pair));
342 }) && llvm::all_of(llvm::zip_equal(oldTy.getResults(), newTy.getResults()), [&](
auto pair) {
343 return isCompatible(std::get<0>(pair), std::get<1>(pair));
349class WildcardArrayTypeConverter :
public TypeConverter {
350 const DenseMap<ArrayType, ArrayType> &arrayReplacements_;
351 std::optional<StructType> oldStructType_;
352 std::optional<StructType> newStructType_;
355 WildcardArrayTypeConverter(
356 const DenseMap<ArrayType, ArrayType> &arrayReplacements,
357 std::optional<StructType> oldStructType = std::nullopt,
358 std::optional<StructType> newStructType = std::nullopt
360 : TypeConverter(), arrayReplacements_(arrayReplacements), oldStructType_(oldStructType),
361 newStructType_(newStructType) {
362 addConversion([](Type inputTy) {
return inputTy; });
364 addConversion([
this](
ArrayType inputTy) -> Type {
366 auto it = arrayReplacements_.find(inputTy);
367 if (it != arrayReplacements_.end()) {
380 addConversion([
this](
StructType inputTy) -> Type {
381 if (oldStructType_.has_value() && newStructType_.has_value() && inputTy == *oldStructType_) {
382 return *newStructType_;
384 if (ArrayAttr params = inputTy.
getParams()) {
385 SmallVector<Attribute> updated;
386 bool changed =
false;
387 for (Attribute attr : params.getValue()) {
388 if (TypeAttr typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
389 Type newTy = this->convertType(typeAttr.getValue());
390 updated.push_back(TypeAttr::get(newTy));
391 changed |= newTy != typeAttr.getValue();
393 updated.push_back(attr);
398 inputTy.
getNameRef(), ArrayAttr::get(inputTy.getContext(), updated)
409static std::optional<Type> refineCastResultArrayWildcards(Type resultTy, Type inputTy) {
410 ArrayType resultArrTy = llvm::dyn_cast<ArrayType>(resultTy);
411 ArrayType inputArrTy = llvm::dyn_cast<ArrayType>(inputTy);
412 if (!resultArrTy || !inputArrTy) {
420 SmallVector<Attribute> refinedDims;
421 bool changed =
false;
422 for (
auto [resultDim, inputDim] :
424 if (
auto resultInt = llvm::dyn_cast<IntegerAttr>(resultDim);
426 if (
auto inputInt = llvm::dyn_cast<IntegerAttr>(inputDim); inputInt && !
isDynamic(inputInt)) {
427 refinedDims.push_back(inputDim);
432 refinedDims.push_back(resultDim);
443static bool calleeReferencesTemplateParam(
CallOp op) {
445 if (!callee || callee.getNestedReferences().size() != 1) {
449 if (!parentTemplate) {
455static LogicalResult erasePreimageOfInstantiations(
456 ModuleOp rootMod,
const ConversionTracker &tracker,
const SymbolDefTree &symDefTree,
459 FromEraseSet cleaner(rootMod, symDefTree, symUseGraph, tracker.getInstantiatedDefinitionNames());
460 LogicalResult res = cleaner.eraseUnusedDefinitions();
464 rootMod->walk([&cleaner, &symUseGraph](Operation *walkedOp) {
465 SymbolOpInterface op = llvm::dyn_cast<SymbolOpInterface>(walkedOp);
466 if (!op || !cleaner.getTryToEraseSet().contains(op)) {
471 op.emitWarning(
"Parameterized definition still has uses!").report();
480class RemoveIdentityUnifiableCast final :
public OpRewritePattern<UnifiableCastOp> {
482 RemoveIdentityUnifiableCast(MLIRContext *ctx) : OpRewritePattern(ctx, 4) {}
488 void rewrite(
UnifiableCastOp op, PatternRewriter &rewriter)
const override {
489 rewriter.replaceOp(op, op.
getInput());
495class UpdateUnifiableCastResultType final :
public OpRewritePattern<UnifiableCastOp> {
496 ConversionTracker &tracker_;
499 UpdateUnifiableCastResultType(MLIRContext *ctx, ConversionTracker &tracker)
500 : OpRewritePattern(ctx, 3), tracker_(tracker) {}
502 LogicalResult matchAndRewrite(
UnifiableCastOp op, PatternRewriter &rewriter)
const override {
503 std::optional<Type> refinedResultTy =
504 refineCastResultArrayWildcards(op.
getResult().getType(), op.
getInput().getType());
505 if (!refinedResultTy.has_value() || *refinedResultTy == op.
getResult().getType()) {
508 if (!tracker_.isLegalConversion(
509 op.
getResult().getType(), *refinedResultTy,
"UpdateUnifiableCastResultType"
513 rewriter.modifyOpInPlace(op, [&]() { op.
getResult().setType(*refinedResultTy); });
518LogicalResult run(ModuleOp modOp, ConversionTracker &tracker) {
519 MLIRContext *ctx = modOp.getContext();
520 RewritePatternSet patterns(ctx);
521 patterns.add<RemoveIdentityUnifiableCast>(ctx);
522 patterns.add<UpdateUnifiableCastResultType>(ctx, tracker);
523 return applyAndFoldGreedily(modOp, tracker, std::move(patterns));
530static SymbolRefAttr replaceLeafReference(SymbolRefAttr symRef, StringRef newLeafName) {
531 SmallVector<FlatSymbolRefAttr> pieces =
getPieces(symRef);
532 assert(!pieces.empty() &&
"symbol reference must have at least one piece");
533 pieces.back() = FlatSymbolRefAttr::get(StringAttr::get(symRef.getContext(), newLeafName));
538buildWildcardSpecializationName(StringRef baseName,
const WildcardArraySpecializationInfo &info) {
544class CallStructFuncPattern :
public OpConversionPattern<CallOp> {
546 CallStructFuncPattern(TypeConverter &converter, MLIRContext *ctx)
547 : OpConversionPattern<CallOp>(converter, ctx, 1) {}
549 LogicalResult matchAndRewrite(
550 CallOp op, OpAdaptor adapter, ConversionPatternRewriter &rewriter
552 SmallVector<Type> newResultTypes;
553 if (failed(getTypeConverter()->convertTypes(op.getResultTypes(), newResultTypes))) {
554 return op->emitError(
"Could not convert Op result types.");
560 calleeAttr =
appendLeaf(newStTy.getNameRef(), calleeAttr.getLeafReference());
564 calleeAttr =
appendLeaf(newStTy.getNameRef(), calleeAttr.getLeafReference());
569 rewriter, op, newResultTypes, calleeAttr, adapter.
getMapOperands(),
578class MemberDefOpPattern :
public OpConversionPattern<MemberDefOp> {
580 MemberDefOpPattern(TypeConverter &converter, MLIRContext *ctx)
581 : OpConversionPattern<MemberDefOp>(converter, ctx, 1) {}
584 matchAndRewrite(
MemberDefOp op, OpAdaptor, ConversionPatternRewriter &rewriter)
const override {
585 Type oldMemberType = op.
getType();
586 Type newMemberType = getTypeConverter()->convertType(oldMemberType);
587 if (oldMemberType == newMemberType) {
590 rewriter.modifyOpInPlace(op, [&op, &newMemberType]() { op.
setType(newMemberType); });
595static LogicalResult verifyNestedCallSymbols(
FuncDefOp func) {
596 SymbolTableCollection tables;
597 WalkResult result = func.walk([&tables](
CallOp nestedCall) {
600 return failure(result.wasInterrupted());
603static LogicalResult applyWildcardSpecializationConversions(
604 FuncDefOp newFunc,
const WildcardArraySpecializationInfo &info
606 MLIRContext *ctx = newFunc.getContext();
607 WildcardArrayTypeConverter tyConv(info.replacements);
610 if (failed(applyFullConversion(newFunc, target, std::move(patterns)))) {
613 return verifyNestedCallSymbols(newFunc);
616static LogicalResult applyWildcardSpecializationConversions(
617 FuncDefOp newFunc, FunctionType newFuncTy,
const WildcardArraySpecializationInfo &info
619 updateFuncSignature(newFunc, newFuncTy);
620 if (!info.hasConflictingReplacements) {
621 return applyWildcardSpecializationConversions(newFunc, info);
623 return verifyNestedCallSymbols(newFunc);
626static LogicalResult applyWildcardSpecializationConversions(
628 const WildcardArraySpecializationInfo &info
630 MLIRContext *ctx = newStruct.getContext();
631 WildcardArrayTypeConverter tyConv(info.replacements, oldStructType, newStructType);
634 patterns.add<CallStructFuncPattern, MemberDefOpPattern>(tyConv, ctx);
635 return applyFullConversion(newStruct, target, std::move(patterns));
638static FailureOr<SymbolRefAttr> getOrCreateSpecializedFreeFunc(
639 CallOp op, PatternRewriter &rewriter, SymbolTableCollection &symTables,
FuncDefOp targetFunc,
640 const WildcardArraySpecializationInfo &info, FunctionType callSig
643 assert(parentModule &&
"free function must be nested in a module");
645 std::string newFuncName = buildWildcardSpecializationName(targetFunc.
getSymName(), info);
647 if (Operation *existing = symTables.getSymbolTable(parentModule).lookup(newFuncName)) {
648 newFunc = llvm::dyn_cast<FuncDefOp>(existing);
650 return rewriter.notifyMatchFailure(op, [&](Diagnostic &diag) {
651 diag.append(
"specialized function name collision for '", newFuncName,
'\'');
655 newFunc = targetFunc.
clone();
657 symTables.getSymbolTable(parentModule).insert(newFunc, Block::iterator(targetFunc));
658 if (failed(applyWildcardSpecializationConversions(newFunc, callSig, info))) {
660 return rewriter.notifyMatchFailure(op, [&](Diagnostic &diag) {
661 diag.append(
"failure while creating wildcard-specialized function '", newFuncName,
'\'');
669static FailureOr<StructType> getOrCreateSpecializedStruct(
670 CallOp op, PatternRewriter &rewriter, SymbolTableCollection &symTables,
671 StructDefOp targetStruct,
const WildcardArraySpecializationInfo &info,
672 ConversionTracker &tracker
675 assert(parentModule &&
"struct definition must be nested in a module");
678 std::string newStructName = buildWildcardSpecializationName(targetStruct.
getSymName(), info);
680 if (Operation *existing = symTables.getSymbolTable(parentModule).lookup(newStructName)) {
681 newStruct = llvm::dyn_cast<StructDefOp>(existing);
683 return rewriter.notifyMatchFailure(op, [&](Diagnostic &diag) {
684 diag.append(
"specialized struct name collision for '", newStructName,
'\'');
688 newStruct = targetStruct.clone();
690 symTables.getSymbolTable(parentModule).insert(newStruct, Block::iterator(targetStruct));
693 applyWildcardSpecializationConversions(newStruct, oldStructType, newStructType, info)
696 return rewriter.notifyMatchFailure(op, [&](Diagnostic &diag) {
697 diag.append(
"failure while creating wildcard-specialized struct '", newStructName,
'\'');
703 tracker.recordSpecialization(oldStructType, newStructType);
704 return newStructType;
709class SpecializeWildcardCallOp final :
public OpRewritePattern<CallOp> {
710 ConversionTracker &tracker_;
713 SpecializeWildcardCallOp(MLIRContext *ctx, ConversionTracker &tracker)
714 : OpRewritePattern<CallOp>(ctx), tracker_(tracker) {}
716 LogicalResult matchAndRewrite(
CallOp op, PatternRewriter &rewriter)
const override {
717 if (calleeReferencesTemplateParam(op)) {
721 SymbolTableCollection symTables;
722 FailureOr<SymbolLookupResult<FuncDefOp>> targetRes = op.
getCalleeTarget(symTables);
723 if (failed(targetRes)) {
727 if (llvm::isa<TemplateOp>(targetFunc->getParentOp())) {
735 std::optional<StructType> ignoredStructType =
736 targetStruct ? std::optional<StructType>(targetStruct.
getType()) : std::nullopt;
737 if (!containsWildcardArrayDims(targetSig) ||
738 !functionTypeIsMoreConcrete(
739 targetSig, callSig, tracker_,
"SpecializeWildcardCallOp", ignoredStructType
744 WildcardArraySpecializationInfo info;
745 if (failed(collectWildcardArraySpecializations(targetSig, callSig, info, ignoredStructType)) ||
751 FailureOr<SymbolRefAttr> newCalleeAttr =
752 getOrCreateSpecializedFreeFunc(op, rewriter, symTables, targetFunc, info, callSig);
753 if (failed(newCalleeAttr)) {
756 SmallVector<Type> newResultTypes;
757 FailureOr<SymbolLookupResult<FuncDefOp>> specializedFuncRes =
759 if (failed(specializedFuncRes)) {
762 newResultTypes.append(
763 specializedFuncRes->get().getFunctionType().getResults().begin(),
764 specializedFuncRes->get().getFunctionType().getResults().end()
766 if (!tracker_.areLegalConversions(
767 op.getResultTypes(), newResultTypes,
"SpecializeWildcardCallOp"
772 tracker_.updateModifiedFlag(
true);
774 rewriter, op, TypeRange(newResultTypes), *newCalleeAttr,
781 assert(targetStruct &&
"struct function must have a parent struct");
782 if (llvm::isa<TemplateOp>(targetStruct->getParentOp())) {
787 SmallVector<Type> newResultTypes;
794 std::string newStructName = buildWildcardSpecializationName(targetStruct.
getSymName(), info);
795 SymbolRefAttr expectedSelfNameRef =
796 replaceLeafReference(targetStructType.
getNameRef(), newStructName);
797 if (selfType.
getNameRef() != expectedSelfNameRef) {
802 FailureOr<StructType> newStructTypeRes =
803 getOrCreateSpecializedStruct(op, rewriter, symTables, targetStruct, info, tracker_);
804 if (failed(newStructTypeRes)) {
810 WildcardArrayTypeConverter tyConv(info.replacements, targetStructType, newStructType);
811 if (failed(tyConv.convertTypes(op.getResultTypes(), newResultTypes))) {
814 if (!tracker_.areLegalConversions(
815 op.getResultTypes(), newResultTypes,
"SpecializeWildcardCallOp"
821 tracker_.updateModifiedFlag(
true);
822 SymbolRefAttr newCalleeAttr =
825 rewriter, op, TypeRange(newResultTypes), newCalleeAttr,
835class RetargetStructConstrainCall final :
public OpRewritePattern<CallOp> {
836 ConversionTracker &tracker_;
839 RetargetStructConstrainCall(MLIRContext *ctx, ConversionTracker &tracker)
840 : OpRewritePattern<CallOp>(ctx), tracker_(tracker) {}
842 LogicalResult matchAndRewrite(
CallOp op, PatternRewriter &rewriter)
const override {
852 SymbolTableCollection symTables;
853 FailureOr<SymbolLookupResult<FuncDefOp>> targetRes = op.
getCalleeTarget(symTables);
854 if (failed(targetRes)) {
859 if (!targetStruct || selfType == targetStruct.
getType()) {
863 SymbolRefAttr newCalleeAttr =
865 FailureOr<SymbolLookupResult<FuncDefOp>> specializedRes =
867 if (failed(specializedRes)) {
871 tracker_.updateModifiedFlag(
true);
873 rewriter, op, TypeRange(op.getResultTypes()), newCalleeAttr,
881LogicalResult run(ModuleOp modOp, ConversionTracker &tracker) {
882 MLIRContext *ctx = modOp.getContext();
883 RewritePatternSet patterns(ctx);
884 patterns.add<RetargetStructConstrainCall>(ctx, tracker);
885 patterns.add<SpecializeWildcardCallOp>(ctx, tracker);
886 MatchFailureListener failureListener;
887 walkAndApplyPatterns(modOp, std::move(patterns), &failureListener);
888 return failure(failureListener.hadFailure);
897 using Base = WildcardArraySpecializationPassBase<PassImpl>;
901 void runOnOperation()
override {
902 ModuleOp modOp = getOperation();
903 ConversionTracker tracker;
904 unsigned loopCount = 0;
907 if (loopCount > iterationLimit) {
908 llvm::errs() <<
DEBUG_TYPE <<
" exceeded the limit of " << iterationLimit
913 tracker.resetModifiedFlag();
915 if (failed(CastRefinement::run(modOp, tracker))) {
916 llvm::errs() <<
DEBUG_TYPE <<
" failed while refining wildcard array cast results\n";
920 if (failed(WildcardFunctionSpecialization::run(modOp, tracker))) {
922 <<
" failed while specializing wildcard-array function signatures\n";
926 }
while (tracker.isModified());
928 if (failed(erasePreimageOfInstantiations(
929 modOp, tracker, getAnalysis<SymbolDefTree>(), getAnalysis<SymbolUseGraph>()
Common private implementation for poly dialect passes.
This file defines methods symbol lookup across LLZK operations and included files.
Reusable MLIR dialect conversion functions for LLZK StructType replacement.
static std::string from(mlir::Type type)
Return a brief string representation of the given LLZK type.
Builds a tree structure representing the symbol table structure.
bool hasPredecessor() const
Return true if this node has any predecessors.
Builds a graph structure representing the relationships between symbols and their uses.
const SymbolUseGraphNode * lookupNode(mlir::ModuleOp pathRoot, mlir::SymbolRefAttr path) const
Return the existing node for the symbol reference relative to the given module, else nullptr.
ArrayType cloneWith(std::optional<::llvm::ArrayRef< int64_t > > shape, ::mlir::Type elementType) const
Clone this type with the given shape and element type.
::mlir::Type getElementType() const
::llvm::ArrayRef<::mlir::Attribute > getDimensionSizes() const
void setType(::mlir::Type attrValue)
StructType getType(::std::optional<::mlir::ArrayAttr > constParams={})
Gets the StructType representing this struct.
::llvm::StringRef getSymName()
void setSymName(::llvm::StringRef attrValue)
::mlir::SymbolRefAttr getNameRef() const
static StructType get(::mlir::SymbolRefAttr structName)
::mlir::ArrayAttr getParams() const
bool calleeIsStructConstrain()
Return true iff the callee function name is FUNC_NAME_CONSTRAIN within a StructDefOp.
::mlir::SymbolRefAttr getCalleeAttr()
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
bool calleeIsStructCompute()
Return true iff the callee function name is FUNC_NAME_COMPUTE within a StructDefOp.
::mlir::SymbolRefAttr getCallee()
::mlir::FunctionType getTypeSignature()
Return the FunctionType inferred from the arg operands and result types of this CallOp.
::mlir::Operation::operand_range getArgOperands()
::mlir::OperandRangeRange getMapOperands()
static ::llvm::SmallVector<::mlir::ValueRange > toVectorOfValueRange(::mlir::OperandRangeRange)
Allocate consecutive storage of the ValueRange instances in the parameter so it can be passed to the ...
::mlir::FailureOr<::llzk::SymbolLookupResult<::llzk::function::FuncDefOp > > getCalleeTarget(::mlir::SymbolTableCollection &tables)
Resolve and return the target FuncDefOp for this CallOp.
::mlir::DenseI32ArrayAttr getNumDimsPerMapAttr()
FuncDefOp clone(::mlir::IRMapping &mapper)
Create a deep copy of this function and all of its blocks, remapping any operands that use values out...
::mlir::FunctionType getFunctionType()
::llvm::StringRef getSymName()
bool nameIsConstrain()
Return true iff the function name is FUNC_NAME_CONSTRAIN (if needed, a check that this FuncDefOp is l...
bool isInStruct()
Return true iff the function is within a StructDefOp.
void setFunctionType(::mlir::FunctionType attrValue)
void setSymName(::llvm::StringRef attrValue)
bool hasConstNamed(::mlir::StringRef find)
Return true if there is an op of type OpT with the given name within the body region.
::mlir::TypedValue<::mlir::Type > getInput()
::mlir::TypedValue<::mlir::Type > getResult()
Removes parameterized definitions whose instantiated replacements now cover every remaining use.
mlir::ConversionTarget newConverterDefinedTarget(mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, AdditionalChecks &&...checks)
Return a new ConversionTarget allowing all LLZK-required dialects and defining Op legality based on t...
OpClass replaceOpWithNewOp(Rewriter &rewriter, mlir::Operation *op, Args &&...args)
Wrapper for PatternRewriter::replaceOpWithNewOp() that automatically copies discardable attributes (i...
mlir::FailureOr< SymbolLookupResultUntyped > lookupTopLevelSymbol(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin, bool reportMissing=true)
TypeClass getIfSingleton(mlir::TypeRange types)
bool isNullOrEmpty(mlir::ArrayAttr a)
SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
OpClass getParentOfType(mlir::Operation *op)
Return the closest surrounding parent/ancestor operation that is of type 'OpClass'.
TypeClass getAtIndex(mlir::TypeRange types, size_t index)
mlir::RewritePatternSet newGeneralRewritePatternSet(mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, mlir::ConversionTarget &target)
Return a new RewritePatternSet covering all LLZK op types that may contain a StructType.
bool isDynamic(IntegerAttr intAttr)
mlir::SymbolRefAttr asSymbolRefAttr(mlir::StringAttr root, mlir::SymbolRefAttr tail)
Build a SymbolRefAttr that prepends tail with root, i.e., root::tail.
bool typesUnify(Type lhs, Type rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
bool isMoreConcreteUnification(Type oldTy, Type newTy, llvm::function_ref< bool(Type oldTy, Type newTy)> knownOldToNew)
llvm::SmallVector< FlatSymbolRefAttr > getPieces(SymbolRefAttr ref)