35#include "llvm/ADT/DenseSet.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/ScopeExit.h"
38#include "llvm/ADT/SmallPtrSet.h"
39#include "llvm/ADT/SmallVectorExtras.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/Debug.h"
42#include "llvm/Support/DebugLog.h"
43#include "llvm/Support/ErrorHandling.h"
44#include "llvm/Support/InterleavedRange.h"
47#define DEBUG_TYPE "transform-dialect"
48#define DEBUG_TYPE_MATCHER "transform-matcher"
60 OpAsmParser &parser, std::optional<OpAsmParser::UnresolvedOperand> &root,
81 while (transformAncestor) {
82 if (transformAncestor == payload) {
85 <<
"cannot apply transform to itself (or one of its ancestors)";
86 diag.attachNote(payload->
getLoc()) <<
"target payload op";
89 transformAncestor = transformAncestor->
getParentOp();
95#include "mlir/Dialect/Transform/IR/TransformOps.cpp.inc"
101OperandRange transform::AlternativesOp::getEntrySuccessorOperands(
104 return getOperation()->getOperands();
106 getOperation()->operand_end());
109void transform::AlternativesOp::getSuccessorRegions(
111 for (
Region &alternative : llvm::drop_begin(
116 ->getRegionNumber() +
118 regions.emplace_back(&alternative);
125transform::AlternativesOp::getSuccessorInputs(
RegionSuccessor successor) {
127 return getOperation()->getResults();
131void transform::AlternativesOp::getRegionInvocationBounds(
136 bounds.reserve(getNumRegions());
137 bounds.emplace_back(1, 1);
144 results.
set(res, {});
152 if (
Value scopeHandle = getScope())
153 llvm::append_range(originals, state.
getPayloadOps(scopeHandle));
158 if (original->isAncestor(getOperation())) {
160 <<
"scope must not contain the transforms being applied";
161 diag.attachNote(original->getLoc()) <<
"scope";
166 <<
"only isolated-from-above ops can be alternative scopes";
167 diag.attachNote(original->getLoc()) <<
"scope";
172 for (
Region ® : getAlternatives()) {
178 auto clones = llvm::map_to_vector(
180 llvm::scope_exit deleteClones([&] {
191 if (
result.isSilenceableFailure()) {
192 LDBG() <<
"alternative failed: " <<
result.getMessage();
197 if (::mlir::failed(
result.silence()))
206 deleteClones.release();
207 TrackingListener listener(state, *
this);
209 for (
const auto &kvp : llvm::zip(originals, clones)) {
216 detail::forwardTerminatorOperands(®.front(), state, results);
220 return emitSilenceableError() <<
"all alternatives failed";
223void transform::AlternativesOp::getEffects(
227 for (
Region *region : getRegions()) {
228 if (!region->empty())
234LogicalResult transform::AlternativesOp::verify() {
235 for (
Region &alternative : getAlternatives()) {
240 <<
"expects terminator operands to have the "
241 "same type as results of the operation";
242 diag.attachNote(terminator->
getLoc()) <<
"terminator";
262 if (
auto paramH = getParam()) {
264 if (params.size() != 1) {
265 if (targets.size() != params.size()) {
266 return emitSilenceableError()
267 <<
"parameter and target have different payload lengths ("
268 << params.size() <<
" vs " << targets.size() <<
")";
270 for (
auto &&[
target, attr] : llvm::zip_equal(targets, params))
271 target->setAttr(getName(), attr);
276 for (
auto *
target : targets)
277 target->setAttr(getName(), attr);
281void transform::AnnotateOp::getEffects(
293transform::ApplyCommonSubexpressionEliminationOp::applyToOne(
308void transform::ApplyCommonSubexpressionEliminationOp::getEffects(
334void transform::ApplyDeadCodeEliminationOp::getEffects(
359 if (!getRegion().empty()) {
360 for (
Operation &op : getRegion().front()) {
361 cast<transform::PatternDescriptorOpInterface>(&op)
362 .populatePatternsWithState(patterns, state);
374 : getMaxIterations());
377 : getMaxNumRewrites());
385 <<
"greedy pattern application failed";
396 static const int64_t kNumMaxIterations = 50;
398 bool cseChanged =
false;
403 ops.push_back(nestedOp);
408 <<
"greedy pattern application failed";
416 }
while (cseChanged && ++iteration < kNumMaxIterations);
418 if (iteration == kNumMaxIterations)
424LogicalResult transform::ApplyPatternsOp::verify() {
425 if (!getRegion().empty()) {
426 for (
Operation &op : getRegion().front()) {
427 if (!isa<transform::PatternDescriptorOpInterface>(&op)) {
429 <<
"expected children ops to implement "
430 "PatternDescriptorOpInterface";
431 diag.attachNote(op.
getLoc()) <<
"op without interface";
439void transform::ApplyPatternsOp::getEffects(
445void transform::ApplyPatternsOp::build(
454 bodyBuilder(builder,
result.location);
461void transform::ApplyCanonicalizationPatternsOp::populatePatterns(
465 dialect->getCanonicalizationPatterns(patterns);
467 op.getCanonicalizationPatterns(patterns, ctx);
481 std::unique_ptr<TypeConverter> defaultTypeConverter;
482 transform::TypeConverterBuilderOpInterface typeConverterBuilder =
483 getDefaultTypeConverter();
484 if (typeConverterBuilder)
485 defaultTypeConverter = typeConverterBuilder.getTypeConverter();
490 for (
Attribute attr : cast<ArrayAttr>(*getLegalOps()))
491 conversionTarget.addLegalOp(
494 for (
Attribute attr : cast<ArrayAttr>(*getIllegalOps()))
495 conversionTarget.addIllegalOp(
497 if (getLegalDialects())
498 for (
Attribute attr : cast<ArrayAttr>(*getLegalDialects()))
499 conversionTarget.addLegalDialect(cast<StringAttr>(attr).getValue());
500 if (getIllegalDialects())
501 for (
Attribute attr : cast<ArrayAttr>(*getIllegalDialects()))
502 conversionTarget.addIllegalDialect(cast<StringAttr>(attr).getValue());
510 if (!getPatterns().empty()) {
511 for (
Operation &op : getPatterns().front()) {
513 cast<transform::ConversionPatternDescriptorOpInterface>(&op);
516 std::unique_ptr<TypeConverter> typeConverter =
517 descriptor.getTypeConverter();
520 keepAliveConverters.emplace_back(std::move(typeConverter));
521 converter = keepAliveConverters.back().get();
524 if (!defaultTypeConverter) {
526 <<
"pattern descriptor does not specify type "
527 "converter and apply_conversion_patterns op has "
528 "no default type converter";
529 diag.attachNote(op.
getLoc()) <<
"pattern descriptor op";
532 converter = defaultTypeConverter.get();
538 descriptor.populateConversionTargetRules(*converter, conversionTarget);
540 descriptor.populatePatterns(*converter, patterns);
548 TrackingListenerConfig trackingConfig;
549 trackingConfig.requireMatchingReplacementOpName =
false;
550 ErrorCheckingTrackingListener trackingListener(state, *
this, trackingConfig);
551 ConversionConfig conversionConfig;
552 if (getPreserveHandles())
553 conversionConfig.listener = &trackingListener;
564 LogicalResult status = failure();
565 if (getPartialConversion()) {
566 status = applyPartialConversion(
target, conversionTarget, frozenPatterns,
569 status = applyFullConversion(
target, conversionTarget, frozenPatterns,
576 diag = emitSilenceableError() <<
"dialect conversion failed";
577 diag.attachNote(
target->getLoc()) <<
"target op";
582 trackingListener.checkAndResetError();
584 if (
diag.succeeded()) {
586 return trackingFailure;
588 diag.attachNote() <<
"tracking listener also failed: "
593 if (!
diag.succeeded())
600LogicalResult transform::ApplyConversionPatternsOp::verify() {
601 if (getNumRegions() != 1 && getNumRegions() != 2)
602 return emitOpError() <<
"expected 1 or 2 regions";
603 if (!getPatterns().empty()) {
604 for (
Operation &op : getPatterns().front()) {
605 if (!isa<transform::ConversionPatternDescriptorOpInterface>(&op)) {
607 emitOpError() <<
"expected pattern children ops to implement "
608 "ConversionPatternDescriptorOpInterface";
609 diag.attachNote(op.
getLoc()) <<
"op without interface";
614 if (getNumRegions() == 2) {
615 Region &typeConverterRegion = getRegion(1);
616 if (typeConverterRegion.
empty() ||
617 !llvm::hasSingleElement(typeConverterRegion.
front()))
619 <<
"expected exactly one op in default type converter region";
621 auto typeConverterOp = dyn_cast<transform::TypeConverterBuilderOpInterface>(
623 if (!typeConverterOp) {
625 <<
"expected default converter child op to "
626 "implement TypeConverterBuilderOpInterface";
627 diag.attachNote(maybeTypeConverter->
getLoc()) <<
"op without interface";
631 if (!getPatterns().empty()) {
632 for (
Operation &op : getPatterns().front()) {
634 cast<transform::ConversionPatternDescriptorOpInterface>(&op);
635 if (
failed(descriptor.verifyTypeConverter(typeConverterOp)))
643void transform::ApplyConversionPatternsOp::getEffects(
645 if (!getPreserveHandles()) {
653void transform::ApplyConversionPatternsOp::build(
663 if (patternsBodyBuilder)
664 patternsBodyBuilder(builder,
result.location);
670 if (typeConverterBodyBuilder)
671 typeConverterBodyBuilder(builder,
result.location);
679void transform::ApplyToLLVMConversionPatternsOp::populatePatterns(
682 assert(dialect &&
"expected that dialect is loaded");
683 auto *iface = cast<ConvertToLLVMPatternInterface>(dialect);
687 iface->populateConvertToLLVMConversionPatterns(
691LogicalResult transform::ApplyToLLVMConversionPatternsOp::verifyTypeConverter(
692 transform::TypeConverterBuilderOpInterface builder) {
693 if (builder.getTypeConverterType() !=
"LLVMTypeConverter")
694 return emitOpError(
"expected LLVMTypeConverter");
698LogicalResult transform::ApplyToLLVMConversionPatternsOp::verify() {
701 return emitOpError(
"unknown dialect or dialect not loaded: ")
703 auto *iface = dyn_cast<ConvertToLLVMPatternInterface>(dialect);
706 "dialect does not implement ConvertToLLVMPatternInterface or "
707 "extension was not loaded: ")
717transform::ApplyLoopInvariantCodeMotionOp::applyToOne(
727void transform::ApplyLoopInvariantCodeMotionOp::getEffects(
737void transform::ApplyRegisteredPassOp::getEffects(
755 llvm::raw_string_ostream optionsStream(
options);
760 if (
auto paramOperand = dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
763 int64_t dynamicOptionIdx = paramOperand.getIndex().getInt();
764 assert(dynamicOptionIdx <
static_cast<int64_t>(dynamicOptions.size()) &&
765 "the number of ParamOperandAttrs in the options DictionaryAttr"
766 "should be the same as the number of options passed as params");
768 state.
getParams(dynamicOptions[dynamicOptionIdx]);
770 llvm::interleave(attrsAssociatedToParam, optionsStream, appendValueAttr,
772 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
774 llvm::interleave(arrayAttr, optionsStream, appendValueAttr,
",");
775 }
else if (
auto strAttr = dyn_cast<StringAttr>(valueAttr)) {
777 optionsStream << strAttr.getValue().str();
780 valueAttr.print(optionsStream,
true);
786 getOptions(), optionsStream,
787 [&](
auto namedAttribute) {
788 optionsStream << namedAttribute.getName().str();
789 optionsStream <<
"=";
790 appendValueAttr(namedAttribute.getValue());
793 optionsStream.flush();
801 <<
"unknown pass or pass pipeline: " << getPassName();
810 <<
"failed to add pass or pass pipeline to pipeline: "
827 auto diag = emitSilenceableError() <<
"pass pipeline failed";
828 diag.attachNote(
target->getLoc()) <<
"target op";
834 results.
set(llvm::cast<OpResult>(getResult()), targets);
843 size_t dynamicOptionsIdx = 0;
849 std::function<ParseResult(
Attribute &)> parseValue =
850 [&](
Attribute &valueAttr) -> ParseResult {
858 [&]() -> ParseResult { return parseValue(attrs.emplace_back()); },
859 " in options dictionary") ||
863 valueAttr = ArrayAttr::get(parser.
getContext(), attrs);
873 ParseResult parsedOperand = parser.
parseOperand(operand);
874 if (failed(parsedOperand))
880 dynamicOptions.push_back(operand);
881 auto wrappedIndex = IntegerAttr::get(
882 IntegerType::get(parser.
getContext(), 64), dynamicOptionsIdx++);
884 transform::ParamOperandAttr::get(parser.
getContext(), wrappedIndex);
885 }
else if (failed(parsedValueAttr.
value())) {
887 }
else if (isa<transform::ParamOperandAttr>(valueAttr)) {
889 <<
"the param_operand attribute is a marker reserved for "
890 <<
"indicating a value will be passed via params and is only used "
891 <<
"in the generic print format";
905 <<
"expected key to either be an identifier or a string";
909 <<
"expected '=' after key in key-value pair";
911 if (failed(parseValue(valueAttr)))
913 <<
"expected a valid attribute or operand as value associated "
914 <<
"to key '" << key <<
"'";
923 " in options dictionary"))
926 if (DictionaryAttr::findDuplicate(
927 keyValuePairs,
false)
930 <<
"duplicate keys found in options dictionary";
945 if (
auto paramOperandAttr =
946 dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
949 dynamicOptions[paramOperandAttr.getIndex().getInt()]);
950 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
953 llvm::interleaveComma(arrayAttr, printer, printOptionValue);
962 printer << namedAttribute.
getName();
964 printOptionValue(namedAttribute.
getValue());
969LogicalResult transform::ApplyRegisteredPassOp::verify() {
976 std::function<LogicalResult(
Attribute)> checkOptionValue =
977 [&](
Attribute valueAttr) -> LogicalResult {
978 if (
auto paramOperand = dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
979 int64_t dynamicOptionIdx = paramOperand.getIndex().getInt();
980 if (dynamicOptionIdx < 0 ||
981 dynamicOptionIdx >=
static_cast<int64_t>(dynamicOptions.size()))
983 <<
"dynamic option index " << dynamicOptionIdx
984 <<
" is out of bounds for the number of dynamic options: "
985 << dynamicOptions.size();
986 if (dynamicOptions[dynamicOptionIdx] ==
nullptr)
987 return emitOpError() <<
"dynamic option index " << dynamicOptionIdx
988 <<
" is already used in options";
989 dynamicOptions[dynamicOptionIdx] =
nullptr;
990 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
992 for (
auto eltAttr : arrayAttr)
993 if (
failed(checkOptionValue(eltAttr)))
1000 if (
failed(checkOptionValue(namedAttr.getValue())))
1004 for (
Value dynamicOption : dynamicOptions)
1006 return emitOpError() <<
"a param operand does not have a corresponding "
1007 <<
"param_operand attr in the options dict";
1020 results.push_back(
target);
1024void transform::CastOp::getEffects(
1032 assert(inputs.size() == 1 &&
"expected one input");
1033 assert(outputs.size() == 1 &&
"expected one output");
1034 return llvm::all_of(
1035 std::initializer_list<Type>{inputs.front(), outputs.front()},
1036 llvm::IsaPred<transform::TransformHandleTypeInterface>);
1056 assert(block.
getParent() &&
"cannot match using a detached block");
1063 if (!isa<transform::MatchOpInterface>(match)) {
1065 <<
"expected operations in the match part to "
1066 "implement MatchOpInterface";
1069 state.
applyTransform(cast<transform::TransformOpInterface>(match));
1070 if (
diag.succeeded())
1088template <
typename... Tys>
1090 return ((isa<Tys>(t1) && isa<Tys>(t2)) || ... ||
false);
1097 transform::TransformParamTypeInterface,
1098 transform::TransformValueHandleTypeInterface>(
1111 getOperation(), getMatcher());
1112 if (matcher.isExternal()) {
1114 <<
"unresolved external symbol " << getMatcher();
1118 rawResults.resize(getOperation()->getNumResults());
1119 std::optional<DiagnosedSilenceableFailure> maybeFailure;
1131 matcher.getFunctionBody().front(),
1134 if (
diag.isDefiniteFailure())
1136 if (
diag.isSilenceableFailure()) {
1138 <<
" failed: " <<
diag.getMessage();
1143 for (
auto &&[i, mapping] : llvm::enumerate(mappings)) {
1144 if (mapping.size() != 1) {
1145 maybeFailure.emplace(emitSilenceableError()
1146 <<
"result #" << i <<
", associated with "
1148 <<
" payload objects, expected 1");
1151 rawResults[i].push_back(mapping[0]);
1156 return std::move(*maybeFailure);
1157 assert(!maybeFailure &&
"failure set but the walk was not interrupted");
1159 for (
auto &&[opResult, rawResult] :
1160 llvm::zip_equal(getOperation()->getResults(), rawResults)) {
1167void transform::CollectMatchingOp::getEffects(
1174LogicalResult transform::CollectMatchingOp::verifySymbolUses(
1176 auto matcherSymbol = dyn_cast_or_null<FunctionOpInterface>(
1178 if (!matcherSymbol ||
1179 !isa<TransformOpInterface>(matcherSymbol.getOperation()))
1180 return emitError() <<
"unresolved matcher symbol " << getMatcher();
1183 if (argumentTypes.size() != 1 ||
1184 !isa<TransformHandleTypeInterface>(argumentTypes[0])) {
1186 <<
"expected the matcher to take one operation handle argument";
1188 if (!matcherSymbol.getArgAttr(
1189 0, transform::TransformDialect::kArgReadOnlyAttrName)) {
1190 return emitError() <<
"expected the matcher argument to be marked readonly";
1194 if (resultTypes.size() != getOperation()->getNumResults()) {
1196 <<
"expected the matcher to yield as many values as op has results ("
1197 << getOperation()->getNumResults() <<
"), got "
1198 << resultTypes.size();
1201 for (
auto &&[i, matcherType, resultType] :
1202 llvm::enumerate(resultTypes, getOperation()->getResultTypes())) {
1207 <<
"mismatching type interfaces for matcher result and op result #"
1219bool transform::ForeachMatchOp::allowsRepeatedHandleOperands() {
return true; }
1227 matchActionPairs.reserve(getMatchers().size());
1229 for (
auto &&[matcher, action] :
1230 llvm::zip_equal(getMatchers(), getActions())) {
1231 auto matcherSymbol =
1233 getOperation(), cast<SymbolRefAttr>(matcher));
1236 getOperation(), cast<SymbolRefAttr>(action));
1237 assert(matcherSymbol && actionSymbol &&
1238 "unresolved symbols not caught by the verifier");
1240 if (matcherSymbol.isExternal())
1242 if (actionSymbol.isExternal())
1245 matchActionPairs.emplace_back(matcherSymbol, actionSymbol);
1256 matchInputMapping.emplace_back();
1258 getForwardedInputs(), state);
1260 actionResultMapping.resize(getForwardedOutputs().size());
1266 if (!getRestrictRoot() && op == root)
1274 firstMatchArgument.clear();
1275 firstMatchArgument.push_back(op);
1278 for (
auto [matcher, action] : matchActionPairs) {
1280 matchBlock(matcher.getFunctionBody().front(), matchInputMapping,
1281 state, matchOutputMapping);
1282 if (
diag.isDefiniteFailure())
1284 if (
diag.isSilenceableFailure()) {
1286 <<
" failed: " <<
diag.getMessage();
1292 action.getFunctionBody().front().getArguments(),
1293 matchOutputMapping))) {
1298 action.getFunctionBody().front().without_terminator()) {
1301 if (
result.isDefiniteFailure())
1303 if (
result.isSilenceableFailure()) {
1305 overallDiag = emitSilenceableError() <<
"actions failed";
1308 <<
"failed action: " <<
result.getMessage();
1310 <<
"when applied to this matching payload";
1315 if (
failed(detail::appendValueMappings(
1317 action.getFunctionBody().front().getTerminator()->getOperands(),
1318 state, getFlattenResults()))) {
1320 <<
"action @" << action.getName()
1321 <<
" has results associated with multiple payload entities, "
1322 "but flattening was not requested";
1337 results.
set(llvm::cast<OpResult>(getUpdated()),
1339 for (
auto &&[
result, mapping] :
1340 llvm::zip_equal(getForwardedOutputs(), actionResultMapping)) {
1346void transform::ForeachMatchOp::getAsmResultNames(
1348 setNameFn(getUpdated(),
"updated_root");
1349 for (
Value v : getForwardedOutputs()) {
1350 setNameFn(v,
"yielded");
1354void transform::ForeachMatchOp::getEffects(
1358 getOperation()->getNumResults() < 1) {
1382 matcherList.push_back(SymbolRefAttr::get(matcher));
1383 actionList.push_back(SymbolRefAttr::get(action));
1397 for (
auto &&[matcher, action, idx] : llvm::zip_equal(
1400 printer << cast<SymbolRefAttr>(matcher) <<
" -> "
1401 << cast<SymbolRefAttr>(action);
1409LogicalResult transform::ForeachMatchOp::verify() {
1410 if (getMatchers().size() != getActions().size())
1411 return emitOpError() <<
"expected the same number of matchers and actions";
1412 if (getMatchers().empty())
1413 return emitOpError() <<
"expected at least one match/action pair";
1417 if (matcherNames.insert(name).second)
1420 <<
" is used more than once, only the first match will apply";
1431 bool alsoVerifyInternal =
false) {
1432 auto transformOp = cast<transform::TransformOpInterface>(op.getOperation());
1433 llvm::SmallDenseSet<unsigned> consumedArguments;
1434 if (!op.isExternal()) {
1438 for (
unsigned i = 0, e = op.getNumArguments(); i < e; ++i) {
1440 op.getArgAttr(i, transform::TransformDialect::kArgConsumedAttrName) !=
1443 op.getArgAttr(i, transform::TransformDialect::kArgReadOnlyAttrName) !=
1445 if (isConsumed && isReadOnly) {
1446 return transformOp.emitSilenceableError()
1447 <<
"argument #" << i <<
" cannot be both readonly and consumed";
1449 if ((op.isExternal() || alsoVerifyInternal) && !isConsumed && !isReadOnly) {
1450 return transformOp.emitSilenceableError()
1451 <<
"must provide consumed/readonly status for arguments of "
1452 "external or called ops";
1454 if (op.isExternal())
1457 if (consumedArguments.contains(i) && !isConsumed && isReadOnly) {
1458 return transformOp.emitSilenceableError()
1459 <<
"argument #" << i
1460 <<
" is consumed in the body but is not marked as such";
1462 if (emitWarnings && !consumedArguments.contains(i) && isConsumed) {
1466 <<
"op argument #" << i
1467 <<
" is not consumed in the body but is marked as consumed";
1473LogicalResult transform::ForeachMatchOp::verifySymbolUses(
1475 assert(getMatchers().size() == getActions().size());
1477 StringAttr::get(
getContext(), TransformDialect::kArgConsumedAttrName);
1478 for (
auto &&[matcher, action] :
1479 llvm::zip_equal(getMatchers(), getActions())) {
1481 auto matcherSymbol = dyn_cast_or_null<FunctionOpInterface>(
1483 cast<SymbolRefAttr>(matcher)));
1484 auto actionSymbol = dyn_cast_or_null<FunctionOpInterface>(
1486 cast<SymbolRefAttr>(action)));
1487 if (!matcherSymbol ||
1488 !isa<TransformOpInterface>(matcherSymbol.getOperation()))
1489 return emitError() <<
"unresolved matcher symbol " << matcher;
1490 if (!actionSymbol ||
1491 !isa<TransformOpInterface>(actionSymbol.getOperation()))
1492 return emitError() <<
"unresolved action symbol " << action;
1497 .checkAndReport())) {
1503 .checkAndReport())) {
1508 TypeRange operandTypes = getOperandTypes();
1509 TypeRange matcherArguments = matcherSymbol.getArgumentTypes();
1510 if (operandTypes.size() != matcherArguments.size()) {
1512 emitError() <<
"the number of operands (" << operandTypes.size()
1513 <<
") doesn't match the number of matcher arguments ("
1514 << matcherArguments.size() <<
") for " << matcher;
1515 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1518 for (
auto &&[i, operand, argument] :
1519 llvm::enumerate(operandTypes, matcherArguments)) {
1520 if (matcherSymbol.getArgAttr(i, consumedAttr)) {
1523 <<
"does not expect matcher symbol to consume its operand #" << i;
1524 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1533 <<
"mismatching type interfaces for operand and matcher argument #"
1534 << i <<
" of matcher " << matcher;
1535 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1540 TypeRange matcherResults = matcherSymbol.getResultTypes();
1541 TypeRange actionArguments = actionSymbol.getArgumentTypes();
1542 if (matcherResults.size() != actionArguments.size()) {
1543 return emitError() <<
"mismatching number of matcher results and "
1544 "action arguments between "
1545 << matcher <<
" (" << matcherResults.size() <<
") and "
1546 << action <<
" (" << actionArguments.size() <<
")";
1548 for (
auto &&[i, matcherType, actionType] :
1549 llvm::enumerate(matcherResults, actionArguments)) {
1553 return emitError() <<
"mismatching type interfaces for matcher result "
1554 "and action argument #"
1555 << i <<
"of matcher " << matcher <<
" and action "
1560 TypeRange actionResults = actionSymbol.getResultTypes();
1561 auto resultTypes =
TypeRange(getResultTypes()).drop_front();
1562 if (actionResults.size() != resultTypes.size()) {
1564 emitError() <<
"the number of action results ("
1565 << actionResults.size() <<
") for " << action
1566 <<
" doesn't match the number of extra op results ("
1567 << resultTypes.size() <<
")";
1568 diag.attachNote(actionSymbol->getLoc()) <<
"symbol declaration";
1571 for (
auto &&[i, resultType, actionType] :
1572 llvm::enumerate(resultTypes, actionResults)) {
1577 emitError() <<
"mismatching type interfaces for action result #" << i
1578 <<
" of action " << action <<
" and op result";
1579 diag.attachNote(actionSymbol->getLoc()) <<
"symbol declaration";
1597 detail::prepareValueMappings(payloads, getTargets(), state);
1598 size_t numIterations = payloads.empty() ? 0 : payloads.front().size();
1599 bool withZipShortest = getWithZipShortest();
1603 if (withZipShortest) {
1607 return a.size() <
b.size();
1610 for (
auto &payload : payloads)
1611 payload.resize(numIterations);
1617 for (
size_t argIdx = 1; !withZipShortest && argIdx < payloads.size();
1619 if (payloads[argIdx].size() != numIterations) {
1620 return emitSilenceableError()
1621 <<
"prior targets' payload size (" << numIterations
1622 <<
") differs from payload size (" << payloads[argIdx].size()
1623 <<
") of target " << getTargets()[argIdx];
1632 for (
size_t iterIdx = 0; iterIdx < numIterations; iterIdx++) {
1635 for (
auto &&[argIdx, blockArg] : llvm::enumerate(blockArguments)) {
1646 llvm::cast<transform::TransformOpInterface>(
transform));
1652 OperandRange yieldOperands = getYieldOp().getOperands();
1653 for (
auto &&[
result, yieldOperand, resTuple] :
1654 llvm::zip_equal(getResults(), yieldOperands, zippedResults))
1656 if (isa<TransformHandleTypeInterface>(
result.getType()))
1657 llvm::append_range(resTuple, state.
getPayloadOps(yieldOperand));
1658 else if (isa<TransformValueHandleTypeInterface>(
result.getType()))
1660 else if (isa<TransformParamTypeInterface>(
result.getType()))
1661 llvm::append_range(resTuple, state.
getParams(yieldOperand));
1663 assert(
false &&
"unhandled handle type");
1667 for (
auto &&[
result, resPayload] : zip_equal(getResults(), zippedResults))
1673void transform::ForeachOp::getEffects(
1677 for (
auto &&[
target, blockArg] :
1678 llvm::zip(getTargetsMutable(), getBody().front().getArguments())) {
1680 if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1682 cast<TransformOpInterface>(&op));
1690 if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1694 }
else if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1703void transform::ForeachOp::getSuccessorRegions(
1705 Region *bodyRegion = &getBody();
1707 regions.emplace_back(bodyRegion);
1714 "unexpected region index");
1715 regions.emplace_back(bodyRegion);
1725transform::ForeachOp::getEntrySuccessorOperands(
RegionSuccessor successor) {
1728 assert(successor.
getSuccessor() == &getBody() &&
"unexpected region index");
1729 return getOperation()->getOperands();
1732transform::YieldOp transform::ForeachOp::getYieldOp() {
1733 return cast<transform::YieldOp>(getBody().front().getTerminator());
1736LogicalResult transform::ForeachOp::verify() {
1737 for (
auto [targetOpt, bodyArgOpt] :
1738 llvm::zip_longest(getTargets(), getBody().front().getArguments())) {
1739 if (!targetOpt || !bodyArgOpt)
1740 return emitOpError() <<
"expects the same number of targets as the body "
1741 "has block arguments";
1742 if (targetOpt.value().getType() != bodyArgOpt.value().getType())
1744 "expects co-indexed targets and the body's "
1745 "block arguments to have the same op/value/param type");
1748 for (
auto [resultOpt, yieldOperandOpt] :
1749 llvm::zip_longest(getResults(), getYieldOp().getOperands())) {
1750 if (!resultOpt || !yieldOperandOpt)
1751 return emitOpError() <<
"expects the same number of results as the "
1752 "yield terminator has operands";
1753 if (resultOpt.value().getType() != yieldOperandOpt.value().getType())
1754 return emitOpError(
"expects co-indexed results and yield "
1755 "operands to have the same op/value/param type");
1773 for (
int64_t i = 0, e = getNthParent(); i < e; ++i) {
1776 bool checkIsolatedFromAbove =
1777 !getIsolatedFromAbove() ||
1779 bool checkOpName = !getOpName().has_value() ||
1781 if (checkIsolatedFromAbove && checkOpName)
1786 if (getAllowEmptyResults()) {
1787 results.
set(llvm::cast<OpResult>(getResult()), parents);
1791 emitSilenceableError()
1792 <<
"could not find a parent op that matches all requirements";
1793 diag.attachNote(
target->getLoc()) <<
"target op";
1797 if (getDeduplicate()) {
1798 if (resultSet.insert(parent).second)
1799 parents.push_back(parent);
1801 parents.push_back(parent);
1804 results.
set(llvm::cast<OpResult>(getResult()), parents);
1816 int64_t resultNumber = getResultNumber();
1818 if (std::empty(payloadOps)) {
1819 results.
set(cast<OpResult>(getResult()), {});
1822 if (!llvm::hasSingleElement(payloadOps))
1824 <<
"handle must be mapped to exactly one payload op";
1827 if (
target->getNumResults() <= resultNumber)
1829 results.
set(llvm::cast<OpResult>(getResult()),
1830 llvm::to_vector(
target->getResult(resultNumber).getUsers()));
1844 if (llvm::isa<BlockArgument>(v)) {
1846 emitSilenceableError() <<
"cannot get defining op of block argument";
1847 diag.attachNote(v.getLoc()) <<
"target value";
1850 definingOps.push_back(v.getDefiningOp());
1852 results.
set(llvm::cast<OpResult>(getResult()), definingOps);
1864 int64_t operandNumber = getOperandNumber();
1868 target->getNumOperands() <= operandNumber
1870 :
target->getOperand(operandNumber).getDefiningOp();
1873 emitSilenceableError()
1874 <<
"could not find a producer for operand number: " << operandNumber
1876 diag.attachNote(
target->getLoc()) <<
"target op";
1879 producers.push_back(producer);
1881 results.
set(llvm::cast<OpResult>(getResult()), producers);
1897 getLoc(), getIsAll(), getIsInverted(), getRawPositionList(),
1898 target->getNumOperands(), operandPositions);
1899 if (
diag.isSilenceableFailure()) {
1901 <<
"while considering positions of this payload operation";
1904 llvm::append_range(operands,
1905 llvm::map_range(operandPositions, [&](
int64_t pos) {
1906 return target->getOperand(pos);
1909 results.
setValues(cast<OpResult>(getResult()), operands);
1913LogicalResult transform::GetOperandOp::verify() {
1915 getIsInverted(), getIsAll());
1930 getLoc(), getIsAll(), getIsInverted(), getRawPositionList(),
1931 target->getNumResults(), resultPositions);
1932 if (
diag.isSilenceableFailure()) {
1934 <<
"while considering positions of this payload operation";
1937 llvm::append_range(opResults,
1938 llvm::map_range(resultPositions, [&](
int64_t pos) {
1939 return target->getResult(pos);
1942 results.
setValues(cast<OpResult>(getResult()), opResults);
1946LogicalResult transform::GetResultOp::verify() {
1948 getIsInverted(), getIsAll());
1955void transform::GetTypeOp::getEffects(
1968 Type type = value.getType();
1969 if (getElemental()) {
1970 if (
auto shaped = dyn_cast<ShapedType>(type)) {
1971 type = shaped.getElementType();
1974 params.push_back(TypeAttr::get(type));
1976 results.
setParams(cast<OpResult>(getResult()), params);
1994 if (
result.isDefiniteFailure())
1997 if (
result.isSilenceableFailure()) {
1998 if (mode == transform::FailurePropagationMode::Propagate) {
2018 getOperation(), getTarget());
2019 assert(callee &&
"unverified reference to unknown symbol");
2021 if (callee.isExternal())
2026 detail::prepareValueMappings(mappings, getOperands(), state);
2028 for (
auto &&[arg, map] :
2029 llvm::zip_equal(callee.getBody().front().getArguments(), mappings)) {
2035 callee.getBody().front(), getFailurePropagationMode(), state, results);
2041 detail::prepareValueMappings(
2042 mappings, callee.getBody().front().getTerminator()->getOperands(), state);
2043 for (
auto &&[
result, mapping] : llvm::zip_equal(getResults(), mappings))
2051void transform::IncludeOp::getEffects(
2066 auto defaultEffects = [&] {
2073 getOperation()->getAttrOfType<SymbolRefAttr>(getTargetAttrName());
2075 return defaultEffects();
2077 getOperation(), getTarget());
2079 return defaultEffects();
2082 if (callee.getArgAttr(i, TransformDialect::kArgConsumedAttrName))
2084 else if (callee.getArgAttr(i, TransformDialect::kArgReadOnlyAttrName))
2093 auto targetAttr = getOperation()->getAttrOfType<SymbolRefAttr>(
"target");
2095 return emitOpError() <<
"expects a 'target' symbol reference attribute";
2100 return emitOpError() <<
"does not reference a named transform sequence";
2102 FunctionType fnType =
target.getFunctionType();
2104 return emitError(
"incorrect number of operands for callee");
2106 for (
unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i) {
2107 if (getOperand(i).
getType() != fnType.getInput(i)) {
2108 return emitOpError(
"operand type mismatch: expected operand type ")
2109 << fnType.getInput(i) <<
", but provided "
2110 << getOperand(i).getType() <<
" for operand number " << i;
2114 if (fnType.getNumResults() != getNumResults())
2115 return emitError(
"incorrect number of results for callee");
2117 for (
unsigned i = 0, e = fnType.getNumResults(); i != e; ++i) {
2118 Type resultType = getResult(i).getType();
2119 Type funcType = fnType.getResult(i);
2121 return emitOpError() <<
"type of result #" << i
2122 <<
" must implement the same transform dialect "
2123 "interface as the corresponding callee result";
2128 cast<FunctionOpInterface>(*
target),
false,
2138 ::std::optional<::mlir::Operation *> maybeCurrent,
2140 if (!maybeCurrent.has_value()) {
2145 return emitSilenceableError() <<
"operation is not empty";
2156 for (
auto acceptedAttr : getOpNames().getAsRange<StringAttr>()) {
2157 if (acceptedAttr.getValue() == currentOpName)
2160 return emitSilenceableError() <<
"wrong operation name";
2171 auto signedAPIntAsString = [&](
const APInt &value) {
2173 llvm::raw_string_ostream os(str);
2174 value.print(os,
true);
2181 if (params.size() != references.size()) {
2182 return emitSilenceableError()
2183 <<
"parameters have different payload lengths (" << params.size()
2184 <<
" vs " << references.size() <<
")";
2187 for (
auto &&[i, param, reference] : llvm::enumerate(params, references)) {
2188 auto intAttr = llvm::dyn_cast<IntegerAttr>(param);
2189 auto refAttr = llvm::dyn_cast<IntegerAttr>(reference);
2190 if (!intAttr || !refAttr) {
2192 <<
"non-integer parameter value not expected";
2194 if (intAttr.getType() != refAttr.getType()) {
2196 <<
"mismatching integer attribute types in parameter #" << i;
2198 APInt value = intAttr.getValue();
2199 APInt refValue = refAttr.getValue();
2203 auto reportError = [&](StringRef direction) {
2205 emitSilenceableError() <<
"expected parameter to be " << direction
2206 <<
" " << signedAPIntAsString(refValue)
2207 <<
", got " << signedAPIntAsString(value);
2208 diag.attachNote(getParam().getLoc())
2209 <<
"value # " << position
2210 <<
" associated with the parameter defined here";
2214 switch (getPredicate()) {
2215 case MatchCmpIPredicate::eq:
2216 if (value.eq(refValue))
2218 return reportError(
"equal to");
2219 case MatchCmpIPredicate::ne:
2220 if (value.ne(refValue))
2222 return reportError(
"not equal to");
2223 case MatchCmpIPredicate::lt:
2224 if (value.slt(refValue))
2226 return reportError(
"less than");
2227 case MatchCmpIPredicate::le:
2228 if (value.sle(refValue))
2230 return reportError(
"less than or equal to");
2231 case MatchCmpIPredicate::gt:
2232 if (value.sgt(refValue))
2234 return reportError(
"greater than");
2235 case MatchCmpIPredicate::ge:
2236 if (value.sge(refValue))
2238 return reportError(
"greater than or equal to");
2244void transform::MatchParamCmpIOp::getEffects(
2258 results.
setParams(cast<OpResult>(getParam()), {getValue()});
2271 if (isa<TransformHandleTypeInterface>(handles.front().
getType())) {
2273 for (
Value operand : handles)
2274 llvm::append_range(operations, state.
getPayloadOps(operand));
2275 if (!getDeduplicate()) {
2276 results.
set(llvm::cast<OpResult>(getResult()), operations);
2281 results.
set(llvm::cast<OpResult>(getResult()), uniqued.getArrayRef());
2285 if (llvm::isa<TransformParamTypeInterface>(handles.front().getType())) {
2287 for (
Value attribute : handles)
2288 llvm::append_range(attrs, state.
getParams(attribute));
2289 if (!getDeduplicate()) {
2290 results.
setParams(cast<OpResult>(getResult()), attrs);
2295 results.
setParams(cast<OpResult>(getResult()), uniqued.getArrayRef());
2300 llvm::isa<TransformValueHandleTypeInterface>(handles.front().getType()) &&
2301 "expected value handle type");
2303 for (
Value value : handles)
2305 if (!getDeduplicate()) {
2306 results.
setValues(cast<OpResult>(getResult()), payloadValues);
2311 results.
setValues(cast<OpResult>(getResult()), uniqued.getArrayRef());
2315bool transform::MergeHandlesOp::allowsRepeatedHandleOperands() {
2317 return getDeduplicate();
2320void transform::MergeHandlesOp::getEffects(
2329OpFoldResult transform::MergeHandlesOp::fold(FoldAdaptor adaptor) {
2330 if (getDeduplicate() || getHandles().size() != 1)
2335 return getHandles().front();
2354 if (
failed(detail::mapPossibleTopLevelTransformOpBlockArguments(
2355 state, this->getOperation(), getBody())))
2359 FailurePropagationMode::Propagate, state, results);
2362void transform::NamedSequenceOp::getEffects(
2365ParseResult transform::NamedSequenceOp::parse(
OpAsmParser &parser,
2369 getFunctionTypeAttrName(
result.name),
2372 std::string &) { return builder.getFunctionType(inputs, results); },
2373 getArgAttrsAttrName(
result.name), getResAttrsAttrName(
result.name));
2376void transform::NamedSequenceOp::print(
OpAsmPrinter &printer) {
2378 printer, cast<FunctionOpInterface>(getOperation()),
false,
2379 getFunctionTypeAttrName().getValue(), getArgAttrsAttrName(),
2380 getResAttrsAttrName());
2390 if (
auto parent = op->
getParentOfType<transform::TransformOpInterface>()) {
2393 <<
"cannot be defined inside another transform op";
2394 diag.attachNote(parent.
getLoc()) <<
"ancestor transform op";
2398 if (op.isExternal() || op.getFunctionBody().empty()) {
2405 if (op.getFunctionBody().front().empty())
2408 Operation *terminator = &op.getFunctionBody().front().back();
2409 if (!isa<transform::YieldOp>(terminator)) {
2412 << transform::YieldOp::getOperationName()
2413 <<
"' as terminator";
2414 diag.attachNote(terminator->
getLoc()) <<
"terminator";
2418 if (terminator->
getNumOperands() != op.getResultTypes().size()) {
2420 <<
"expected terminator to have as many operands as the parent op "
2423 for (
auto [i, operandType, resultType] : llvm::zip_equal(
2426 if (operandType == resultType)
2429 <<
"the type of the terminator operand #" << i
2430 <<
" must match the type of the corresponding parent op result ("
2431 << operandType <<
" vs " << resultType <<
")";
2444 transform::TransformDialect::kWithNamedSequenceAttrName)) {
2447 <<
"expects the parent symbol table to have the '"
2448 << transform::TransformDialect::kWithNamedSequenceAttrName
2450 diag.attachNote(parent->
getLoc()) <<
"symbol table operation";
2455 if (
auto parent = op->
getParentOfType<transform::TransformOpInterface>()) {
2458 <<
"cannot be defined inside another transform op";
2459 diag.attachNote(parent.
getLoc()) <<
"ancestor transform op";
2463 if (op.isExternal() || op.getBody().empty())
2467 if (op.getBody().front().empty())
2471 for (
Operation &child : op.getBody().front().without_terminator()) {
2472 if (!isa<transform::TransformOpInterface>(child)) {
2475 <<
"expected children ops to implement TransformOpInterface";
2476 diag.attachNote(child.getLoc()) <<
"op without interface";
2481 Operation *terminator = &op.getBody().front().back();
2482 if (!isa<transform::YieldOp>(terminator)) {
2485 << transform::YieldOp::getOperationName()
2486 <<
"' as terminator";
2487 diag.attachNote(terminator->
getLoc()) <<
"terminator";
2491 if (terminator->
getNumOperands() != op.getFunctionType().getNumResults()) {
2493 <<
"expected terminator to have as many operands as the parent op "
2496 for (
auto [i, operandType, resultType] :
2497 llvm::zip_equal(llvm::seq<unsigned>(0, terminator->
getNumOperands()),
2499 op.getFunctionType().getResults())) {
2500 if (operandType == resultType)
2503 <<
"the type of the terminator operand #" << i
2504 <<
" must match the type of the corresponding parent op result ("
2505 << operandType <<
" vs " << resultType <<
")";
2508 auto funcOp = cast<FunctionOpInterface>(*op);
2511 if (!
diag.succeeded())
2518LogicalResult transform::NamedSequenceOp::verify() {
2523template <
typename FnTy>
2528 types.reserve(1 + extraBindingTypes.size());
2529 types.push_back(bbArgType);
2530 llvm::append_range(types, extraBindingTypes);
2540 if constexpr (llvm::function_traits<FnTy>::num_args == 3) {
2548void transform::NamedSequenceOp::build(
OpBuilder &builder,
2551 SequenceBodyBuilderFn bodyBuilder,
2557 TypeAttr::get(FunctionType::get(builder.
getContext(),
2558 rootType, resultTypes)));
2574 size_t numAssociations =
2576 .Case([&](TransformHandleTypeInterface opHandle) {
2579 .Case([&](TransformValueHandleTypeInterface valueHandle) {
2582 .Case([&](TransformParamTypeInterface param) {
2583 return llvm::range_size(state.
getParams(getHandle()));
2585 .DefaultUnreachable(
"unknown kind of transform dialect type");
2586 results.
setParams(cast<OpResult>(getNum()),
2591LogicalResult transform::NumAssociationsOp::verify() {
2593 auto resultType = cast<TransformParamTypeInterface>(getNum().
getType());
2613 results.
set(cast<OpResult>(getResult()),
result);
2633 .Case([&](TransformHandleTypeInterface x) {
2636 .Case([&](TransformValueHandleTypeInterface x) {
2639 .Case([&](TransformParamTypeInterface x) {
2640 return llvm::range_size(state.
getParams(getHandle()));
2642 .DefaultUnreachable(
"unknown transform dialect type interface");
2644 auto produceNumOpsError = [&]() {
2645 return emitSilenceableError()
2646 << getHandle() <<
" expected to contain " << this->getNumResults()
2647 <<
" payloads but it contains " << numPayloads <<
" payloads";
2652 if (numPayloads > getNumResults() && !getOverflowResult().has_value())
2653 return produceNumOpsError();
2658 if (numPayloads < getNumResults() && getFailOnPayloadTooSmall() &&
2659 (numPayloads != 0 || !getPassThroughEmptyHandle()))
2660 return produceNumOpsError();
2664 if (getOverflowResult())
2665 resultHandles[*getOverflowResult()].reserve(numPayloads - getNumResults());
2667 auto container = [&]() {
2668 if (isa<TransformHandleTypeInterface>(getHandle().
getType())) {
2669 return llvm::map_to_vector(
2671 [](
Operation *op) -> MappedValue {
return op; });
2673 if (isa<TransformValueHandleTypeInterface>(getHandle().
getType())) {
2675 [](
Value v) -> MappedValue {
return v; });
2677 assert(isa<TransformParamTypeInterface>(getHandle().
getType()) &&
2678 "unsupported kind of transform dialect type");
2679 return llvm::map_to_vector(state.
getParams(getHandle()),
2680 [](
Attribute a) -> MappedValue {
return a; });
2683 for (
auto &&en : llvm::enumerate(container)) {
2684 int64_t resultNum = en.index();
2685 if (resultNum >= getNumResults())
2686 resultNum = *getOverflowResult();
2687 resultHandles[resultNum].push_back(en.value());
2691 for (
auto &&it : llvm::enumerate(resultHandles))
2698void transform::SplitHandleOp::getEffects(
2706LogicalResult transform::SplitHandleOp::verify() {
2707 if (getOverflowResult().has_value() &&
2708 !(*getOverflowResult() < getNumResults()))
2709 return emitOpError(
"overflow_result is not a valid result index");
2711 for (
Type resultType : getResultTypes()) {
2715 return emitOpError(
"expects result types to implement the same transform "
2716 "interface as the operand type");
2726void transform::PayloadOp::getCheckedNormalForms(
2728 llvm::append_range(normalForms,
2729 getNormalForms().getAsRange<NormalFormAttrInterface>());
2740 unsigned numRepetitions = llvm::range_size(state.
getPayloadOps(getPattern()));
2741 for (
const auto &en : llvm::enumerate(getHandles())) {
2742 Value handle = en.value();
2743 if (isa<TransformHandleTypeInterface>(handle.getType())) {
2747 payload.reserve(numRepetitions * current.size());
2748 for (
unsigned i = 0; i < numRepetitions; ++i)
2749 llvm::append_range(payload, current);
2750 results.
set(llvm::cast<OpResult>(getReplicated()[en.index()]), payload);
2752 assert(llvm::isa<TransformParamTypeInterface>(handle.getType()) &&
2753 "expected param type");
2756 params.reserve(numRepetitions * current.size());
2757 for (
unsigned i = 0; i < numRepetitions; ++i)
2758 llvm::append_range(params, current);
2759 results.
setParams(llvm::cast<OpResult>(getReplicated()[en.index()]),
2766void transform::ReplicateOp::getEffects(
2783 if (
failed(mapBlockArguments(state)))
2791 OpAsmParser &parser, std::optional<OpAsmParser::UnresolvedOperand> &root,
2798 root = std::nullopt;
2801 if (failed(hasRoot.
value()))
2815 if (failed(parser.
parseType(rootType))) {
2819 if (!extraBindings.empty()) {
2824 if (extraBindingTypes.size() != extraBindings.size()) {
2826 "expected types to be provided for all operands");
2842 bool hasExtras = !extraBindings.empty();
2852 printer << rootType;
2854 printer <<
", " << llvm::interleaved(extraBindingTypes) <<
')';
2861 auto iface = dyn_cast<transform::TransformOpInterface>(use.
getOwner());
2865 return isHandleConsumed(use.
get(), iface);
2876 if (!potentialConsumer) {
2877 potentialConsumer = &use;
2882 <<
" has more than one potential consumer";
2885 diag.attachNote(use.getOwner()->getLoc())
2886 <<
"used here as operand #" << use.getOperandNumber();
2893LogicalResult transform::SequenceOp::verify() {
2894 assert(getBodyBlock()->getNumArguments() >= 1 &&
2895 "the number of arguments must have been verified to be more than 1 by "
2896 "PossibleTopLevelTransformOpTrait");
2898 if (!getRoot() && !getExtraBindings().empty()) {
2899 return emitOpError()
2900 <<
"does not expect extra operands when used as top-level";
2906 return (emitOpError() <<
"block argument #" << arg.getArgNumber());
2913 for (
Operation &child : *getBodyBlock()) {
2914 if (!isa<TransformOpInterface>(child) &&
2915 &child != &getBodyBlock()->back()) {
2918 <<
"expected children ops to implement TransformOpInterface";
2919 diag.attachNote(child.getLoc()) <<
"op without interface";
2924 auto report = [&]() {
2925 return (child.emitError() <<
"result #" <<
result.getResultNumber());
2932 if (!getBodyBlock()->mightHaveTerminator())
2933 return emitOpError() <<
"expects to have a terminator in the body";
2935 if (getBodyBlock()->getTerminator()->getOperandTypes() !=
2936 getOperation()->getResultTypes()) {
2938 <<
"expects the types of the terminator operands "
2939 "to match the types of the result";
2940 diag.attachNote(getBodyBlock()->getTerminator()->getLoc()) <<
"terminator";
2946void transform::SequenceOp::getEffects(
2952transform::SequenceOp::getEntrySuccessorOperands(
RegionSuccessor successor) {
2953 assert(successor.
getSuccessor() == &getBody() &&
"unexpected region index");
2955 return getOperation()->getOperands();
2957 getOperation()->operand_end());
2960void transform::SequenceOp::getSuccessorRegions(
2963 Region *bodyRegion = &getBody();
2964 regions.emplace_back(bodyRegion);
2970 "unexpected region index");
2979 return getResults();
2980 return getBody().getArguments();
2983void transform::SequenceOp::getRegionInvocationBounds(
2986 bounds.emplace_back(1, 1);
2991 FailurePropagationMode failurePropagationMode,
2993 SequenceBodyBuilderFn bodyBuilder) {
2994 build(builder, state, resultTypes, failurePropagationMode, root,
3003 FailurePropagationMode failurePropagationMode,
3005 SequenceBodyBuilderArgsFn bodyBuilder) {
3006 build(builder, state, resultTypes, failurePropagationMode, root,
3014 FailurePropagationMode failurePropagationMode,
3016 SequenceBodyBuilderFn bodyBuilder) {
3017 build(builder, state, resultTypes, failurePropagationMode,
Value(),
3025 FailurePropagationMode failurePropagationMode,
3027 SequenceBodyBuilderArgsFn bodyBuilder) {
3028 build(builder, state, resultTypes, failurePropagationMode,
Value(),
3046 build(builder,
result, name);
3053 llvm::outs() <<
"[[[ IR printer: ";
3054 if (getName().has_value())
3055 llvm::outs() << *getName() <<
" ";
3058 if (getAssumeVerified().value_or(
false))
3060 if (getUseLocalScope().value_or(
false))
3062 if (getSkipRegions().value_or(
false))
3066 llvm::outs() <<
"top-level ]]]\n";
3068 llvm::outs() <<
"\n";
3069 llvm::outs().flush();
3073 llvm::outs() <<
"]]]\n";
3075 target->print(llvm::outs(), printFlags);
3076 llvm::outs() <<
"\n";
3079 llvm::outs().flush();
3083void transform::PrintOp::getEffects(
3088 if (!getTargetMutable().empty())
3108 <<
"failed to verify payload op";
3109 diag.attachNote(
target->getLoc()) <<
"payload op";
3115void transform::VerifyOp::getEffects(
3124void transform::YieldOp::getEffects(
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static ParseResult parseKeyValuePair(AsmParser &parser, DataLayoutEntryInterface &entry, bool tryType=false)
Parse an entry which can either be of the form key = value or a dlti.dl_entry attribute.
static llvm::ManagedStatic< PassManagerOptions > options
ParseResult parseSymbolName(StringAttr &result)
Parse an -identifier and store it (without the '@' symbol) in a string attribute.
@ None
Zero or more operands with no delimiters.
@ Braces
{} brackets surrounding zero or more operands.
virtual ParseResult parseOptionalKeywordOrString(std::string *result)=0
Parse an optional keyword or string.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual OptionalParseResult parseOptionalAttribute(Attribute &result, Type type={})=0
Parse an arbitrary optional attribute of a given type and return it in result.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual void decreaseIndent()
Decrease indentation.
virtual void increaseIndent()
Increase indentation.
virtual void printAttribute(Attribute attr)
virtual void printNewline()
Print a newline and indent the printer to the start of the current operation/attribute/type.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getI64IntegerAttr(int64_t value)
StringAttr getStringAttr(const Twine &bytes)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
MLIRContext * getContext() const
A compatibility class connecting InFlightDiagnostic to DiagnosedSilenceableFailure while providing an...
The result of a transform IR operation application.
LogicalResult silence()
Converts silenceable failure into LogicalResult success without reporting the diagnostic,...
static DiagnosedSilenceableFailure success()
Constructs a DiagnosedSilenceableFailure in the success state.
std::string getMessage() const
Returns the diagnostic message without emitting it.
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the last diagnostic.
LogicalResult checkAndReport()
Converts all kinds of failure into a LogicalResult failure, emitting the diagnostic if necessary.
bool succeeded() const
Returns true if this is a success.
static DiagnosedSilenceableFailure definiteFailure()
Constructs a DiagnosedSilenceableFailure in the failure state.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
A class for computing basic dominance information.
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This class allows control over how the GreedyPatternRewriteDriver works.
static constexpr int64_t kNoLimit
GreedyRewriteConfig & setListener(RewriterBase::Listener *listener)
GreedyRewriteConfig & enableCSEBetweenIterations(bool enable=true)
GreedyRewriteConfig & setMaxIterations(int64_t iterations)
GreedyRewriteConfig & setMaxNumRewrites(int64_t limit)
IRValueT get() const
Return the current value being used by this operand.
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
This class represents a diagnostic that is inflight and set to be reported.
This class represents upper and lower bounds on the number of times a region of a RegionBranchOpInter...
Conversion from types to the LLVM IR dialect.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
std::vector< Dialect * > getLoadedDialects()
Return information about all IR dialects loaded in the context.
ArrayRef< RegisteredOperationName > getRegisteredOperations()
Return a sorted array containing the information about all registered operations.
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual OptionalParseResult parseOptionalOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single operand if present.
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printOperands(OperandRange operands)
Print a comma separated range of operation operands out of line to avoid instantiating the range iter...
virtual void printOperand(Value value)=0
Print implementations for various things an operation contains.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Listener * getListener() const
Returns the current listener of this builder, or nullptr if this builder doesn't have a listener.
This class represents a single result from folding an operation.
This class represents an operand of an operation.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the Operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
OpPrintingFlags & assumeVerified(bool enable=true)
Do not verify the operation when using custom operation printers.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
This is a value defined by a result of an operation.
This class provides the API for ops that are known to be isolated from above.
A trait used to provide symbol table functionalities to a region operation.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
This class implements the operand iterators for the Operation class.
type_range getType() const
type_range getTypes() const
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Block * getBlock()
Returns the operation block that contains this operation.
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
unsigned getNumOperands()
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
OperationName getName()
The name of an operation is the key identifier for it.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getOpResults()
Operation * clone(IRMapping &mapper, const CloneOptions &options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
This class implements Optional functionality for ParseResult.
ParseResult value() const
Access the internal ParseResult value.
bool has_value() const
Returns true if we contain a valid ParseResult value.
static const PassInfo * lookup(StringRef passArg)
Returns the pass info for the specified pass class or null if unknown.
The main pass manager and pipeline builder.
static const PassPipelineInfo * lookup(StringRef pipelineArg)
Returns the pass pipeline info for the specified pass pipeline or null if unknown.
Structure to group information about a passes and pass pipelines (argument to invoke via mlir-opt,...
LogicalResult addToPipeline(OpPassManager &pm, StringRef options, function_ref< LogicalResult(const Twine &)> errorHandler) const
Adds this pass registry entry to the given pass manager.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
RegionBranchTerminatorOpInterface getTerminatorPredecessorOrNull() const
Returns the terminator if branching from a region.
This class represents a successor of a region.
Region * getSuccessor() const
Return the given region successor.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
BlockArgListType getArguments()
This is a "type erased" representation of a registered operation.
MLIRContext * getContext() const
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
static DerivedEffect * get()
This class represents a collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
bool wasInterrupted() const
Returns true if the walk was interrupted.
static WalkResult interrupt()
Operation * getOwner() const
Return the owner of this operand.
A named class for passing around the variadic flag.
void printFunctionOp(OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic, StringRef typeAttrName, StringAttr argAttrsName, StringAttr resAttrsName)
Printer implementation for function-like operations.
ParseResult parseFunctionOp(OpAsmParser &parser, OperationState &result, bool allowVariadic, StringAttr typeAttrName, FuncTypeBuilder funcTypeBuilder, StringAttr argAttrsName, StringAttr resAttrsName)
Parser implementation for function-like operations.
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
void eliminateCommonSubExpressions(RewriterBase &rewriter, DominanceInfo &domInfo, Operation *op, bool *changed=nullptr, int64_t *numCSE=nullptr, int64_t *numDCE=nullptr)
Eliminate common subexpressions within the given operation.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
A functor used to set the name of the start of a result group of an operation.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
DiagnosedSilenceableFailure emitSilenceableFailure(Location loc, const Twine &message={})
Emits a silenceable failure with the given message.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult applyOpPatternsGreedily(ArrayRef< Operation * > ops, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr, bool *allErased=nullptr)
Rewrite the specified ops by repeatedly applying the highest benefit patterns in a greedy worklist dr...
llvm::SetVector< T, Vector, Set, N > SetVector
DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message={})
Emits a definite failure with the given message.
bool eliminateTriviallyDeadOps(RewriterBase &rewriter, Region ®ion, bool includeNestedRegions=true)
Remove trivially dead operations from region.
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
llvm::function_ref< Fn > function_ref
size_t moveLoopInvariantCode(ArrayRef< Region * > regions, function_ref< bool(Value, Region *)> isDefinedOutsideRegion, function_ref< bool(Operation *, Region *)> shouldMoveOutOfRegion, function_ref< void(Operation *, Region *)> moveOutOfRegion)
Given a list of regions, perform loop-invariant code motion.
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
T & getOrAddProperties()
Get (or create) the properties of the provided type to be set on the operation on creation.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
Region * addRegion()
Create a region that should be attached to the operation.