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(
103 if (!successor.
isOperation() && getOperation()->getNumOperands() == 1)
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)
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 (!llvm::hasSingleElement(typeConverterRegion.
front()))
618 <<
"expected exactly one op in default type converter region";
620 auto typeConverterOp = dyn_cast<transform::TypeConverterBuilderOpInterface>(
622 if (!typeConverterOp) {
624 <<
"expected default converter child op to "
625 "implement TypeConverterBuilderOpInterface";
626 diag.attachNote(maybeTypeConverter->
getLoc()) <<
"op without interface";
630 if (!getPatterns().empty()) {
631 for (
Operation &op : getPatterns().front()) {
633 cast<transform::ConversionPatternDescriptorOpInterface>(&op);
634 if (
failed(descriptor.verifyTypeConverter(typeConverterOp)))
642void transform::ApplyConversionPatternsOp::getEffects(
644 if (!getPreserveHandles()) {
652void transform::ApplyConversionPatternsOp::build(
662 if (patternsBodyBuilder)
663 patternsBodyBuilder(builder,
result.location);
669 if (typeConverterBodyBuilder)
670 typeConverterBodyBuilder(builder,
result.location);
678void transform::ApplyToLLVMConversionPatternsOp::populatePatterns(
681 assert(dialect &&
"expected that dialect is loaded");
682 auto *iface = cast<ConvertToLLVMPatternInterface>(dialect);
686 iface->populateConvertToLLVMConversionPatterns(
690LogicalResult transform::ApplyToLLVMConversionPatternsOp::verifyTypeConverter(
691 transform::TypeConverterBuilderOpInterface builder) {
692 if (builder.getTypeConverterType() !=
"LLVMTypeConverter")
697LogicalResult transform::ApplyToLLVMConversionPatternsOp::verify() {
700 return emitOpError(
"unknown dialect or dialect not loaded: ")
702 auto *iface = dyn_cast<ConvertToLLVMPatternInterface>(dialect);
705 "dialect does not implement ConvertToLLVMPatternInterface or "
706 "extension was not loaded: ")
716transform::ApplyLoopInvariantCodeMotionOp::applyToOne(
726void transform::ApplyLoopInvariantCodeMotionOp::getEffects(
736void transform::ApplyRegisteredPassOp::getEffects(
754 llvm::raw_string_ostream optionsStream(
options);
759 if (
auto paramOperand = dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
762 int64_t dynamicOptionIdx = paramOperand.getIndex().getInt();
763 assert(dynamicOptionIdx <
static_cast<int64_t>(dynamicOptions.size()) &&
764 "the number of ParamOperandAttrs in the options DictionaryAttr"
765 "should be the same as the number of options passed as params");
767 state.
getParams(dynamicOptions[dynamicOptionIdx]);
769 llvm::interleave(attrsAssociatedToParam, optionsStream, appendValueAttr,
771 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
773 llvm::interleave(arrayAttr, optionsStream, appendValueAttr,
",");
774 }
else if (
auto strAttr = dyn_cast<StringAttr>(valueAttr)) {
776 optionsStream << strAttr.getValue().str();
779 valueAttr.print(optionsStream,
true);
785 getOptions(), optionsStream,
786 [&](
auto namedAttribute) {
787 optionsStream << namedAttribute.getName().str();
788 optionsStream <<
"=";
789 appendValueAttr(namedAttribute.getValue());
792 optionsStream.flush();
800 <<
"unknown pass or pass pipeline: " << getPassName();
809 <<
"failed to add pass or pass pipeline to pipeline: "
826 auto diag = emitSilenceableError() <<
"pass pipeline failed";
827 diag.attachNote(
target->getLoc()) <<
"target op";
833 results.
set(llvm::cast<OpResult>(getResult()), targets);
842 size_t dynamicOptionsIdx = 0;
848 std::function<ParseResult(
Attribute &)> parseValue =
849 [&](
Attribute &valueAttr) -> ParseResult {
857 [&]() -> ParseResult { return parseValue(attrs.emplace_back()); },
858 " in options dictionary") ||
862 valueAttr = ArrayAttr::get(parser.
getContext(), attrs);
872 ParseResult parsedOperand = parser.
parseOperand(operand);
873 if (failed(parsedOperand))
879 dynamicOptions.push_back(operand);
880 auto wrappedIndex = IntegerAttr::get(
881 IntegerType::get(parser.
getContext(), 64), dynamicOptionsIdx++);
883 transform::ParamOperandAttr::get(parser.
getContext(), wrappedIndex);
884 }
else if (failed(parsedValueAttr.
value())) {
886 }
else if (isa<transform::ParamOperandAttr>(valueAttr)) {
888 <<
"the param_operand attribute is a marker reserved for "
889 <<
"indicating a value will be passed via params and is only used "
890 <<
"in the generic print format";
904 <<
"expected key to either be an identifier or a string";
908 <<
"expected '=' after key in key-value pair";
910 if (failed(parseValue(valueAttr)))
912 <<
"expected a valid attribute or operand as value associated "
913 <<
"to key '" << key <<
"'";
922 " in options dictionary"))
925 if (DictionaryAttr::findDuplicate(
926 keyValuePairs,
false)
929 <<
"duplicate keys found in options dictionary";
944 if (
auto paramOperandAttr =
945 dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
948 dynamicOptions[paramOperandAttr.getIndex().getInt()]);
949 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
952 llvm::interleaveComma(arrayAttr, printer, printOptionValue);
961 printer << namedAttribute.
getName();
963 printOptionValue(namedAttribute.
getValue());
968LogicalResult transform::ApplyRegisteredPassOp::verify() {
975 std::function<LogicalResult(
Attribute)> checkOptionValue =
976 [&](
Attribute valueAttr) -> LogicalResult {
977 if (
auto paramOperand = dyn_cast<transform::ParamOperandAttr>(valueAttr)) {
978 int64_t dynamicOptionIdx = paramOperand.getIndex().getInt();
979 if (dynamicOptionIdx < 0 ||
980 dynamicOptionIdx >=
static_cast<int64_t>(dynamicOptions.size()))
982 <<
"dynamic option index " << dynamicOptionIdx
983 <<
" is out of bounds for the number of dynamic options: "
984 << dynamicOptions.size();
985 if (dynamicOptions[dynamicOptionIdx] ==
nullptr)
986 return emitOpError() <<
"dynamic option index " << dynamicOptionIdx
987 <<
" is already used in options";
988 dynamicOptions[dynamicOptionIdx] =
nullptr;
989 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
991 for (
auto eltAttr : arrayAttr)
992 if (
failed(checkOptionValue(eltAttr)))
999 if (
failed(checkOptionValue(namedAttr.getValue())))
1003 for (
Value dynamicOption : dynamicOptions)
1005 return emitOpError() <<
"a param operand does not have a corresponding "
1006 <<
"param_operand attr in the options dict";
1019 results.push_back(
target);
1023void transform::CastOp::getEffects(
1031 assert(inputs.size() == 1 &&
"expected one input");
1032 assert(outputs.size() == 1 &&
"expected one output");
1033 return llvm::all_of(
1034 std::initializer_list<Type>{inputs.front(), outputs.front()},
1035 llvm::IsaPred<transform::TransformHandleTypeInterface>);
1055 assert(block.
getParent() &&
"cannot match using a detached block");
1062 if (!isa<transform::MatchOpInterface>(match)) {
1064 <<
"expected operations in the match part to "
1065 "implement MatchOpInterface";
1068 state.
applyTransform(cast<transform::TransformOpInterface>(match));
1069 if (
diag.succeeded())
1087template <
typename... Tys>
1089 return ((isa<Tys>(t1) && isa<Tys>(t2)) || ... ||
false);
1096 transform::TransformParamTypeInterface,
1097 transform::TransformValueHandleTypeInterface>(
1110 getOperation(), getMatcher());
1111 if (matcher.isExternal()) {
1113 <<
"unresolved external symbol " << getMatcher();
1117 rawResults.resize(getOperation()->getNumResults());
1118 std::optional<DiagnosedSilenceableFailure> maybeFailure;
1130 matcher.getFunctionBody().front(),
1133 if (
diag.isDefiniteFailure())
1135 if (
diag.isSilenceableFailure()) {
1137 <<
" failed: " <<
diag.getMessage();
1142 for (
auto &&[i, mapping] : llvm::enumerate(mappings)) {
1143 if (mapping.size() != 1) {
1144 maybeFailure.emplace(emitSilenceableError()
1145 <<
"result #" << i <<
", associated with "
1147 <<
" payload objects, expected 1");
1150 rawResults[i].push_back(mapping[0]);
1155 return std::move(*maybeFailure);
1156 assert(!maybeFailure &&
"failure set but the walk was not interrupted");
1158 for (
auto &&[opResult, rawResult] :
1159 llvm::zip_equal(getOperation()->getResults(), rawResults)) {
1166void transform::CollectMatchingOp::getEffects(
1173LogicalResult transform::CollectMatchingOp::verifySymbolUses(
1175 auto matcherSymbol = dyn_cast_or_null<FunctionOpInterface>(
1177 if (!matcherSymbol ||
1178 !isa<TransformOpInterface>(matcherSymbol.getOperation()))
1179 return emitError() <<
"unresolved matcher symbol " << getMatcher();
1182 if (argumentTypes.size() != 1 ||
1183 !isa<TransformHandleTypeInterface>(argumentTypes[0])) {
1185 <<
"expected the matcher to take one operation handle argument";
1187 if (!matcherSymbol.getArgAttr(
1188 0, transform::TransformDialect::kArgReadOnlyAttrName)) {
1189 return emitError() <<
"expected the matcher argument to be marked readonly";
1193 if (resultTypes.size() != getOperation()->getNumResults()) {
1195 <<
"expected the matcher to yield as many values as op has results ("
1196 << getOperation()->getNumResults() <<
"), got "
1197 << resultTypes.size();
1200 for (
auto &&[i, matcherType, resultType] :
1201 llvm::enumerate(resultTypes, getOperation()->getResultTypes())) {
1206 <<
"mismatching type interfaces for matcher result and op result #"
1218bool transform::ForeachMatchOp::allowsRepeatedHandleOperands() {
return true; }
1226 matchActionPairs.reserve(getMatchers().size());
1228 for (
auto &&[matcher, action] :
1229 llvm::zip_equal(getMatchers(), getActions())) {
1230 auto matcherSymbol =
1232 getOperation(), cast<SymbolRefAttr>(matcher));
1235 getOperation(), cast<SymbolRefAttr>(action));
1236 assert(matcherSymbol && actionSymbol &&
1237 "unresolved symbols not caught by the verifier");
1239 if (matcherSymbol.isExternal())
1241 if (actionSymbol.isExternal())
1244 matchActionPairs.emplace_back(matcherSymbol, actionSymbol);
1255 matchInputMapping.emplace_back();
1257 getForwardedInputs(), state);
1259 actionResultMapping.resize(getForwardedOutputs().size());
1265 if (!getRestrictRoot() && op == root)
1273 firstMatchArgument.clear();
1274 firstMatchArgument.push_back(op);
1277 for (
auto [matcher, action] : matchActionPairs) {
1279 matchBlock(matcher.getFunctionBody().front(), matchInputMapping,
1280 state, matchOutputMapping);
1281 if (
diag.isDefiniteFailure())
1283 if (
diag.isSilenceableFailure()) {
1285 <<
" failed: " <<
diag.getMessage();
1291 action.getFunctionBody().front().getArguments(),
1292 matchOutputMapping))) {
1297 action.getFunctionBody().front().without_terminator()) {
1300 if (
result.isDefiniteFailure())
1302 if (
result.isSilenceableFailure()) {
1304 overallDiag = emitSilenceableError() <<
"actions failed";
1307 <<
"failed action: " <<
result.getMessage();
1309 <<
"when applied to this matching payload";
1314 if (
failed(detail::appendValueMappings(
1316 action.getFunctionBody().front().getTerminator()->getOperands(),
1317 state, getFlattenResults()))) {
1319 <<
"action @" << action.getName()
1320 <<
" has results associated with multiple payload entities, "
1321 "but flattening was not requested";
1336 results.
set(llvm::cast<OpResult>(getUpdated()),
1338 for (
auto &&[
result, mapping] :
1339 llvm::zip_equal(getForwardedOutputs(), actionResultMapping)) {
1345void transform::ForeachMatchOp::getAsmResultNames(
1347 setNameFn(getUpdated(),
"updated_root");
1348 for (
Value v : getForwardedOutputs()) {
1349 setNameFn(v,
"yielded");
1353void transform::ForeachMatchOp::getEffects(
1356 if (getOperation()->getNumOperands() < 1 ||
1357 getOperation()->getNumResults() < 1) {
1381 matcherList.push_back(SymbolRefAttr::get(matcher));
1382 actionList.push_back(SymbolRefAttr::get(action));
1396 for (
auto &&[matcher, action, idx] : llvm::zip_equal(
1399 printer << cast<SymbolRefAttr>(matcher) <<
" -> "
1400 << cast<SymbolRefAttr>(action);
1408LogicalResult transform::ForeachMatchOp::verify() {
1409 if (getMatchers().size() != getActions().size())
1410 return emitOpError() <<
"expected the same number of matchers and actions";
1411 if (getMatchers().empty())
1412 return emitOpError() <<
"expected at least one match/action pair";
1416 if (matcherNames.insert(name).second)
1419 <<
" is used more than once, only the first match will apply";
1430 bool alsoVerifyInternal =
false) {
1431 auto transformOp = cast<transform::TransformOpInterface>(op.getOperation());
1432 llvm::SmallDenseSet<unsigned> consumedArguments;
1433 if (!op.isExternal()) {
1437 for (
unsigned i = 0, e = op.getNumArguments(); i < e; ++i) {
1439 op.getArgAttr(i, transform::TransformDialect::kArgConsumedAttrName) !=
1442 op.getArgAttr(i, transform::TransformDialect::kArgReadOnlyAttrName) !=
1444 if (isConsumed && isReadOnly) {
1445 return transformOp.emitSilenceableError()
1446 <<
"argument #" << i <<
" cannot be both readonly and consumed";
1448 if ((op.isExternal() || alsoVerifyInternal) && !isConsumed && !isReadOnly) {
1449 return transformOp.emitSilenceableError()
1450 <<
"must provide consumed/readonly status for arguments of "
1451 "external or called ops";
1453 if (op.isExternal())
1456 if (consumedArguments.contains(i) && !isConsumed && isReadOnly) {
1457 return transformOp.emitSilenceableError()
1458 <<
"argument #" << i
1459 <<
" is consumed in the body but is not marked as such";
1461 if (emitWarnings && !consumedArguments.contains(i) && isConsumed) {
1465 <<
"op argument #" << i
1466 <<
" is not consumed in the body but is marked as consumed";
1472LogicalResult transform::ForeachMatchOp::verifySymbolUses(
1474 assert(getMatchers().size() == getActions().size());
1476 StringAttr::get(
getContext(), TransformDialect::kArgConsumedAttrName);
1477 for (
auto &&[matcher, action] :
1478 llvm::zip_equal(getMatchers(), getActions())) {
1480 auto matcherSymbol = dyn_cast_or_null<FunctionOpInterface>(
1482 cast<SymbolRefAttr>(matcher)));
1483 auto actionSymbol = dyn_cast_or_null<FunctionOpInterface>(
1485 cast<SymbolRefAttr>(action)));
1486 if (!matcherSymbol ||
1487 !isa<TransformOpInterface>(matcherSymbol.getOperation()))
1488 return emitError() <<
"unresolved matcher symbol " << matcher;
1489 if (!actionSymbol ||
1490 !isa<TransformOpInterface>(actionSymbol.getOperation()))
1491 return emitError() <<
"unresolved action symbol " << action;
1496 .checkAndReport())) {
1502 .checkAndReport())) {
1507 TypeRange operandTypes = getOperandTypes();
1508 TypeRange matcherArguments = matcherSymbol.getArgumentTypes();
1509 if (operandTypes.size() != matcherArguments.size()) {
1511 emitError() <<
"the number of operands (" << operandTypes.size()
1512 <<
") doesn't match the number of matcher arguments ("
1513 << matcherArguments.size() <<
") for " << matcher;
1514 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1517 for (
auto &&[i, operand, argument] :
1518 llvm::enumerate(operandTypes, matcherArguments)) {
1519 if (matcherSymbol.getArgAttr(i, consumedAttr)) {
1522 <<
"does not expect matcher symbol to consume its operand #" << i;
1523 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1532 <<
"mismatching type interfaces for operand and matcher argument #"
1533 << i <<
" of matcher " << matcher;
1534 diag.attachNote(matcherSymbol->getLoc()) <<
"symbol declaration";
1539 TypeRange matcherResults = matcherSymbol.getResultTypes();
1540 TypeRange actionArguments = actionSymbol.getArgumentTypes();
1541 if (matcherResults.size() != actionArguments.size()) {
1542 return emitError() <<
"mismatching number of matcher results and "
1543 "action arguments between "
1544 << matcher <<
" (" << matcherResults.size() <<
") and "
1545 << action <<
" (" << actionArguments.size() <<
")";
1547 for (
auto &&[i, matcherType, actionType] :
1548 llvm::enumerate(matcherResults, actionArguments)) {
1552 return emitError() <<
"mismatching type interfaces for matcher result "
1553 "and action argument #"
1554 << i <<
"of matcher " << matcher <<
" and action "
1559 TypeRange actionResults = actionSymbol.getResultTypes();
1560 auto resultTypes =
TypeRange(getResultTypes()).drop_front();
1561 if (actionResults.size() != resultTypes.size()) {
1563 emitError() <<
"the number of action results ("
1564 << actionResults.size() <<
") for " << action
1565 <<
" doesn't match the number of extra op results ("
1566 << resultTypes.size() <<
")";
1567 diag.attachNote(actionSymbol->getLoc()) <<
"symbol declaration";
1570 for (
auto &&[i, resultType, actionType] :
1571 llvm::enumerate(resultTypes, actionResults)) {
1576 emitError() <<
"mismatching type interfaces for action result #" << i
1577 <<
" of action " << action <<
" and op result";
1578 diag.attachNote(actionSymbol->getLoc()) <<
"symbol declaration";
1596 detail::prepareValueMappings(payloads, getTargets(), state);
1597 size_t numIterations = payloads.empty() ? 0 : payloads.front().size();
1598 bool withZipShortest = getWithZipShortest();
1602 if (withZipShortest) {
1606 return a.size() <
b.size();
1609 for (
auto &payload : payloads)
1610 payload.resize(numIterations);
1616 for (
size_t argIdx = 1; !withZipShortest && argIdx < payloads.size();
1618 if (payloads[argIdx].size() != numIterations) {
1619 return emitSilenceableError()
1620 <<
"prior targets' payload size (" << numIterations
1621 <<
") differs from payload size (" << payloads[argIdx].size()
1622 <<
") of target " << getTargets()[argIdx];
1631 for (
size_t iterIdx = 0; iterIdx < numIterations; iterIdx++) {
1634 for (
auto &&[argIdx, blockArg] : llvm::enumerate(blockArguments)) {
1645 llvm::cast<transform::TransformOpInterface>(
transform));
1651 OperandRange yieldOperands = getYieldOp().getOperands();
1652 for (
auto &&[
result, yieldOperand, resTuple] :
1653 llvm::zip_equal(getResults(), yieldOperands, zippedResults))
1655 if (isa<TransformHandleTypeInterface>(
result.getType()))
1656 llvm::append_range(resTuple, state.
getPayloadOps(yieldOperand));
1657 else if (isa<TransformValueHandleTypeInterface>(
result.getType()))
1659 else if (isa<TransformParamTypeInterface>(
result.getType()))
1660 llvm::append_range(resTuple, state.
getParams(yieldOperand));
1662 assert(
false &&
"unhandled handle type");
1666 for (
auto &&[
result, resPayload] : zip_equal(getResults(), zippedResults))
1672void transform::ForeachOp::getEffects(
1676 for (
auto &&[
target, blockArg] :
1677 llvm::zip(getTargetsMutable(), getBody().front().getArguments())) {
1679 if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1681 cast<TransformOpInterface>(&op));
1689 if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1693 }
else if (any_of(getBody().front().without_terminator(), [&](
Operation &op) {
1702void transform::ForeachOp::getSuccessorRegions(
1704 Region *bodyRegion = &getBody();
1706 regions.emplace_back(bodyRegion);
1713 "unexpected region index");
1714 regions.emplace_back(bodyRegion);
1724transform::ForeachOp::getEntrySuccessorOperands(
RegionSuccessor successor) {
1727 assert(successor.
getSuccessor() == &getBody() &&
"unexpected region index");
1728 return getOperation()->getOperands();
1731transform::YieldOp transform::ForeachOp::getYieldOp() {
1732 return cast<transform::YieldOp>(getBody().front().getTerminator());
1735LogicalResult transform::ForeachOp::verify() {
1736 for (
auto [targetOpt, bodyArgOpt] :
1737 llvm::zip_longest(getTargets(), getBody().front().getArguments())) {
1738 if (!targetOpt || !bodyArgOpt)
1739 return emitOpError() <<
"expects the same number of targets as the body "
1740 "has block arguments";
1741 if (targetOpt.value().getType() != bodyArgOpt.value().getType())
1743 "expects co-indexed targets and the body's "
1744 "block arguments to have the same op/value/param type");
1747 for (
auto [resultOpt, yieldOperandOpt] :
1748 llvm::zip_longest(getResults(), getYieldOp().getOperands())) {
1749 if (!resultOpt || !yieldOperandOpt)
1750 return emitOpError() <<
"expects the same number of results as the "
1751 "yield terminator has operands";
1752 if (resultOpt.value().getType() != yieldOperandOpt.value().getType())
1753 return emitOpError(
"expects co-indexed results and yield "
1754 "operands to have the same op/value/param type");
1772 for (
int64_t i = 0, e = getNthParent(); i < e; ++i) {
1775 bool checkIsolatedFromAbove =
1776 !getIsolatedFromAbove() ||
1778 bool checkOpName = !getOpName().has_value() ||
1780 if (checkIsolatedFromAbove && checkOpName)
1785 if (getAllowEmptyResults()) {
1786 results.
set(llvm::cast<OpResult>(getResult()), parents);
1790 emitSilenceableError()
1791 <<
"could not find a parent op that matches all requirements";
1792 diag.attachNote(
target->getLoc()) <<
"target op";
1796 if (getDeduplicate()) {
1797 if (resultSet.insert(parent).second)
1798 parents.push_back(parent);
1800 parents.push_back(parent);
1803 results.
set(llvm::cast<OpResult>(getResult()), parents);
1815 int64_t resultNumber = getResultNumber();
1817 if (std::empty(payloadOps)) {
1818 results.
set(cast<OpResult>(getResult()), {});
1821 if (!llvm::hasSingleElement(payloadOps))
1823 <<
"handle must be mapped to exactly one payload op";
1826 if (
target->getNumResults() <= resultNumber)
1828 results.
set(llvm::cast<OpResult>(getResult()),
1829 llvm::to_vector(
target->getResult(resultNumber).getUsers()));
1843 if (llvm::isa<BlockArgument>(v)) {
1845 emitSilenceableError() <<
"cannot get defining op of block argument";
1846 diag.attachNote(v.getLoc()) <<
"target value";
1849 definingOps.push_back(v.getDefiningOp());
1851 results.
set(llvm::cast<OpResult>(getResult()), definingOps);
1863 int64_t operandNumber = getOperandNumber();
1867 target->getNumOperands() <= operandNumber
1869 :
target->getOperand(operandNumber).getDefiningOp();
1872 emitSilenceableError()
1873 <<
"could not find a producer for operand number: " << operandNumber
1875 diag.attachNote(
target->getLoc()) <<
"target op";
1878 producers.push_back(producer);
1880 results.
set(llvm::cast<OpResult>(getResult()), producers);
1896 getLoc(), getIsAll(), getIsInverted(), getRawPositionList(),
1897 target->getNumOperands(), operandPositions);
1898 if (
diag.isSilenceableFailure()) {
1900 <<
"while considering positions of this payload operation";
1903 llvm::append_range(operands,
1904 llvm::map_range(operandPositions, [&](
int64_t pos) {
1905 return target->getOperand(pos);
1908 results.
setValues(cast<OpResult>(getResult()), operands);
1912LogicalResult transform::GetOperandOp::verify() {
1914 getIsInverted(), getIsAll());
1929 getLoc(), getIsAll(), getIsInverted(), getRawPositionList(),
1930 target->getNumResults(), resultPositions);
1931 if (
diag.isSilenceableFailure()) {
1933 <<
"while considering positions of this payload operation";
1936 llvm::append_range(opResults,
1937 llvm::map_range(resultPositions, [&](
int64_t pos) {
1938 return target->getResult(pos);
1941 results.
setValues(cast<OpResult>(getResult()), opResults);
1945LogicalResult transform::GetResultOp::verify() {
1947 getIsInverted(), getIsAll());
1954void transform::GetTypeOp::getEffects(
1967 Type type = value.getType();
1968 if (getElemental()) {
1969 if (
auto shaped = dyn_cast<ShapedType>(type)) {
1970 type = shaped.getElementType();
1973 params.push_back(TypeAttr::get(type));
1975 results.
setParams(cast<OpResult>(getResult()), params);
1993 if (
result.isDefiniteFailure())
1996 if (
result.isSilenceableFailure()) {
1997 if (mode == transform::FailurePropagationMode::Propagate) {
2017 getOperation(), getTarget());
2018 assert(callee &&
"unverified reference to unknown symbol");
2020 if (callee.isExternal())
2025 detail::prepareValueMappings(mappings, getOperands(), state);
2027 for (
auto &&[arg, map] :
2028 llvm::zip_equal(callee.getBody().front().getArguments(), mappings)) {
2034 callee.getBody().front(), getFailurePropagationMode(), state, results);
2040 detail::prepareValueMappings(
2041 mappings, callee.getBody().front().getTerminator()->getOperands(), state);
2042 for (
auto &&[
result, mapping] : llvm::zip_equal(getResults(), mappings))
2050void transform::IncludeOp::getEffects(
2065 auto defaultEffects = [&] {
2072 getOperation()->getAttrOfType<SymbolRefAttr>(getTargetAttrName());
2074 return defaultEffects();
2076 getOperation(), getTarget());
2078 return defaultEffects();
2080 for (
unsigned i = 0, e = getNumOperands(); i < e; ++i) {
2081 if (callee.getArgAttr(i, TransformDialect::kArgConsumedAttrName))
2083 else if (callee.getArgAttr(i, TransformDialect::kArgReadOnlyAttrName))
2092 auto targetAttr = getOperation()->getAttrOfType<SymbolRefAttr>(
"target");
2094 return emitOpError() <<
"expects a 'target' symbol reference attribute";
2099 return emitOpError() <<
"does not reference a named transform sequence";
2101 FunctionType fnType =
target.getFunctionType();
2102 if (fnType.getNumInputs() != getNumOperands())
2103 return emitError(
"incorrect number of operands for callee");
2105 for (
unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i) {
2106 if (getOperand(i).
getType() != fnType.getInput(i)) {
2107 return emitOpError(
"operand type mismatch: expected operand type ")
2108 << fnType.getInput(i) <<
", but provided "
2109 << getOperand(i).getType() <<
" for operand number " << i;
2113 if (fnType.getNumResults() != getNumResults())
2114 return emitError(
"incorrect number of results for callee");
2116 for (
unsigned i = 0, e = fnType.getNumResults(); i != e; ++i) {
2117 Type resultType = getResult(i).getType();
2118 Type funcType = fnType.getResult(i);
2121 <<
" must implement the same transform dialect "
2122 "interface as the corresponding callee result";
2127 cast<FunctionOpInterface>(*
target),
false,
2137 ::std::optional<::mlir::Operation *> maybeCurrent,
2139 if (!maybeCurrent.has_value()) {
2144 return emitSilenceableError() <<
"operation is not empty";
2155 for (
auto acceptedAttr : getOpNames().getAsRange<StringAttr>()) {
2156 if (acceptedAttr.getValue() == currentOpName)
2159 return emitSilenceableError() <<
"wrong operation name";
2170 auto signedAPIntAsString = [&](
const APInt &value) {
2172 llvm::raw_string_ostream os(str);
2173 value.print(os,
true);
2180 if (params.size() != references.size()) {
2181 return emitSilenceableError()
2182 <<
"parameters have different payload lengths (" << params.size()
2183 <<
" vs " << references.size() <<
")";
2186 for (
auto &&[i, param, reference] : llvm::enumerate(params, references)) {
2187 auto intAttr = llvm::dyn_cast<IntegerAttr>(param);
2188 auto refAttr = llvm::dyn_cast<IntegerAttr>(reference);
2189 if (!intAttr || !refAttr) {
2191 <<
"non-integer parameter value not expected";
2193 if (intAttr.getType() != refAttr.getType()) {
2195 <<
"mismatching integer attribute types in parameter #" << i;
2197 APInt value = intAttr.getValue();
2198 APInt refValue = refAttr.getValue();
2202 auto reportError = [&](StringRef direction) {
2204 emitSilenceableError() <<
"expected parameter to be " << direction
2205 <<
" " << signedAPIntAsString(refValue)
2206 <<
", got " << signedAPIntAsString(value);
2207 diag.attachNote(getParam().getLoc())
2208 <<
"value # " << position
2209 <<
" associated with the parameter defined here";
2213 switch (getPredicate()) {
2214 case MatchCmpIPredicate::eq:
2215 if (value.eq(refValue))
2217 return reportError(
"equal to");
2218 case MatchCmpIPredicate::ne:
2219 if (value.ne(refValue))
2221 return reportError(
"not equal to");
2222 case MatchCmpIPredicate::lt:
2223 if (value.slt(refValue))
2225 return reportError(
"less than");
2226 case MatchCmpIPredicate::le:
2227 if (value.sle(refValue))
2229 return reportError(
"less than or equal to");
2230 case MatchCmpIPredicate::gt:
2231 if (value.sgt(refValue))
2233 return reportError(
"greater than");
2234 case MatchCmpIPredicate::ge:
2235 if (value.sge(refValue))
2237 return reportError(
"greater than or equal to");
2243void transform::MatchParamCmpIOp::getEffects(
2257 results.
setParams(cast<OpResult>(getParam()), {getValue()});
2270 if (isa<TransformHandleTypeInterface>(handles.front().
getType())) {
2272 for (
Value operand : handles)
2273 llvm::append_range(operations, state.
getPayloadOps(operand));
2274 if (!getDeduplicate()) {
2275 results.
set(llvm::cast<OpResult>(getResult()), operations);
2280 results.
set(llvm::cast<OpResult>(getResult()), uniqued.getArrayRef());
2284 if (llvm::isa<TransformParamTypeInterface>(handles.front().getType())) {
2286 for (
Value attribute : handles)
2287 llvm::append_range(attrs, state.
getParams(attribute));
2288 if (!getDeduplicate()) {
2289 results.
setParams(cast<OpResult>(getResult()), attrs);
2294 results.
setParams(cast<OpResult>(getResult()), uniqued.getArrayRef());
2299 llvm::isa<TransformValueHandleTypeInterface>(handles.front().getType()) &&
2300 "expected value handle type");
2302 for (
Value value : handles)
2304 if (!getDeduplicate()) {
2305 results.
setValues(cast<OpResult>(getResult()), payloadValues);
2310 results.
setValues(cast<OpResult>(getResult()), uniqued.getArrayRef());
2314bool transform::MergeHandlesOp::allowsRepeatedHandleOperands() {
2316 return getDeduplicate();
2319void transform::MergeHandlesOp::getEffects(
2328OpFoldResult transform::MergeHandlesOp::fold(FoldAdaptor adaptor) {
2329 if (getDeduplicate() || getHandles().size() != 1)
2334 return getHandles().front();
2353 if (
failed(detail::mapPossibleTopLevelTransformOpBlockArguments(
2354 state, this->getOperation(), getBody())))
2358 FailurePropagationMode::Propagate, state, results);
2361void transform::NamedSequenceOp::getEffects(
2364ParseResult transform::NamedSequenceOp::parse(
OpAsmParser &parser,
2368 getFunctionTypeAttrName(
result.name),
2371 std::string &) { return builder.getFunctionType(inputs, results); },
2372 getArgAttrsAttrName(
result.name), getResAttrsAttrName(
result.name));
2375void transform::NamedSequenceOp::print(
OpAsmPrinter &printer) {
2377 printer, cast<FunctionOpInterface>(getOperation()),
false,
2378 getFunctionTypeAttrName().getValue(), getArgAttrsAttrName(),
2379 getResAttrsAttrName());
2389 if (
auto parent = op->
getParentOfType<transform::TransformOpInterface>()) {
2392 <<
"cannot be defined inside another transform op";
2393 diag.attachNote(parent.
getLoc()) <<
"ancestor transform op";
2397 if (op.isExternal() || op.getFunctionBody().empty()) {
2404 if (op.getFunctionBody().front().empty())
2407 Operation *terminator = &op.getFunctionBody().front().back();
2408 if (!isa<transform::YieldOp>(terminator)) {
2411 << transform::YieldOp::getOperationName()
2412 <<
"' as terminator";
2413 diag.attachNote(terminator->
getLoc()) <<
"terminator";
2417 if (terminator->
getNumOperands() != op.getResultTypes().size()) {
2419 <<
"expected terminator to have as many operands as the parent op "
2422 for (
auto [i, operandType, resultType] : llvm::zip_equal(
2425 if (operandType == resultType)
2428 <<
"the type of the terminator operand #" << i
2429 <<
" must match the type of the corresponding parent op result ("
2430 << operandType <<
" vs " << resultType <<
")";
2443 transform::TransformDialect::kWithNamedSequenceAttrName)) {
2446 <<
"expects the parent symbol table to have the '"
2447 << transform::TransformDialect::kWithNamedSequenceAttrName
2449 diag.attachNote(parent->
getLoc()) <<
"symbol table operation";
2454 if (
auto parent = op->
getParentOfType<transform::TransformOpInterface>()) {
2457 <<
"cannot be defined inside another transform op";
2458 diag.attachNote(parent.
getLoc()) <<
"ancestor transform op";
2462 if (op.isExternal() || op.getBody().empty())
2466 if (op.getBody().front().empty())
2470 for (
Operation &child : op.getBody().front().without_terminator()) {
2471 if (!isa<transform::TransformOpInterface>(child)) {
2474 <<
"expected children ops to implement TransformOpInterface";
2475 diag.attachNote(child.getLoc()) <<
"op without interface";
2480 Operation *terminator = &op.getBody().front().back();
2481 if (!isa<transform::YieldOp>(terminator)) {
2484 << transform::YieldOp::getOperationName()
2485 <<
"' as terminator";
2486 diag.attachNote(terminator->
getLoc()) <<
"terminator";
2490 if (terminator->
getNumOperands() != op.getFunctionType().getNumResults()) {
2492 <<
"expected terminator to have as many operands as the parent op "
2495 for (
auto [i, operandType, resultType] :
2496 llvm::zip_equal(llvm::seq<unsigned>(0, terminator->
getNumOperands()),
2498 op.getFunctionType().getResults())) {
2499 if (operandType == resultType)
2502 <<
"the type of the terminator operand #" << i
2503 <<
" must match the type of the corresponding parent op result ("
2504 << operandType <<
" vs " << resultType <<
")";
2507 auto funcOp = cast<FunctionOpInterface>(*op);
2510 if (!
diag.succeeded())
2517LogicalResult transform::NamedSequenceOp::verify() {
2522template <
typename FnTy>
2527 types.reserve(1 + extraBindingTypes.size());
2528 types.push_back(bbArgType);
2529 llvm::append_range(types, extraBindingTypes);
2539 if constexpr (llvm::function_traits<FnTy>::num_args == 3) {
2547void transform::NamedSequenceOp::build(
OpBuilder &builder,
2550 SequenceBodyBuilderFn bodyBuilder,
2556 TypeAttr::get(FunctionType::get(builder.
getContext(),
2557 rootType, resultTypes)));
2573 size_t numAssociations =
2575 .Case([&](TransformHandleTypeInterface opHandle) {
2578 .Case([&](TransformValueHandleTypeInterface valueHandle) {
2581 .Case([&](TransformParamTypeInterface param) {
2582 return llvm::range_size(state.
getParams(getHandle()));
2584 .DefaultUnreachable(
"unknown kind of transform dialect type");
2585 results.
setParams(cast<OpResult>(getNum()),
2590LogicalResult transform::NumAssociationsOp::verify() {
2592 auto resultType = cast<TransformParamTypeInterface>(getNum().
getType());
2612 results.
set(cast<OpResult>(getResult()),
result);
2632 .Case([&](TransformHandleTypeInterface x) {
2635 .Case([&](TransformValueHandleTypeInterface x) {
2638 .Case([&](TransformParamTypeInterface x) {
2639 return llvm::range_size(state.
getParams(getHandle()));
2641 .DefaultUnreachable(
"unknown transform dialect type interface");
2643 auto produceNumOpsError = [&]() {
2644 return emitSilenceableError()
2645 << getHandle() <<
" expected to contain " << this->getNumResults()
2646 <<
" payloads but it contains " << numPayloads <<
" payloads";
2651 if (numPayloads > getNumResults() && !getOverflowResult().has_value())
2652 return produceNumOpsError();
2657 if (numPayloads < getNumResults() && getFailOnPayloadTooSmall() &&
2658 (numPayloads != 0 || !getPassThroughEmptyHandle()))
2659 return produceNumOpsError();
2663 if (getOverflowResult())
2664 resultHandles[*getOverflowResult()].reserve(numPayloads - getNumResults());
2666 auto container = [&]() {
2667 if (isa<TransformHandleTypeInterface>(getHandle().
getType())) {
2668 return llvm::map_to_vector(
2670 [](
Operation *op) -> MappedValue {
return op; });
2672 if (isa<TransformValueHandleTypeInterface>(getHandle().
getType())) {
2674 [](
Value v) -> MappedValue {
return v; });
2676 assert(isa<TransformParamTypeInterface>(getHandle().
getType()) &&
2677 "unsupported kind of transform dialect type");
2678 return llvm::map_to_vector(state.
getParams(getHandle()),
2679 [](
Attribute a) -> MappedValue {
return a; });
2682 for (
auto &&en : llvm::enumerate(container)) {
2683 int64_t resultNum = en.index();
2684 if (resultNum >= getNumResults())
2685 resultNum = *getOverflowResult();
2686 resultHandles[resultNum].push_back(en.value());
2690 for (
auto &&it : llvm::enumerate(resultHandles))
2697void transform::SplitHandleOp::getEffects(
2705LogicalResult transform::SplitHandleOp::verify() {
2706 if (getOverflowResult().has_value() &&
2707 !(*getOverflowResult() < getNumResults()))
2708 return emitOpError(
"overflow_result is not a valid result index");
2710 for (
Type resultType : getResultTypes()) {
2714 return emitOpError(
"expects result types to implement the same transform "
2715 "interface as the operand type");
2725void transform::PayloadOp::getCheckedNormalForms(
2727 llvm::append_range(normalForms,
2728 getNormalForms().getAsRange<NormalFormAttrInterface>());
2739 unsigned numRepetitions = llvm::range_size(state.
getPayloadOps(getPattern()));
2740 for (
const auto &en : llvm::enumerate(getHandles())) {
2741 Value handle = en.value();
2742 if (isa<TransformHandleTypeInterface>(handle.getType())) {
2746 payload.reserve(numRepetitions * current.size());
2747 for (
unsigned i = 0; i < numRepetitions; ++i)
2748 llvm::append_range(payload, current);
2749 results.
set(llvm::cast<OpResult>(getReplicated()[en.index()]), payload);
2751 assert(llvm::isa<TransformParamTypeInterface>(handle.getType()) &&
2752 "expected param type");
2755 params.reserve(numRepetitions * current.size());
2756 for (
unsigned i = 0; i < numRepetitions; ++i)
2757 llvm::append_range(params, current);
2758 results.
setParams(llvm::cast<OpResult>(getReplicated()[en.index()]),
2765void transform::ReplicateOp::getEffects(
2782 if (
failed(mapBlockArguments(state)))
2790 OpAsmParser &parser, std::optional<OpAsmParser::UnresolvedOperand> &root,
2797 root = std::nullopt;
2800 if (failed(hasRoot.
value()))
2814 if (failed(parser.
parseType(rootType))) {
2818 if (!extraBindings.empty()) {
2823 if (extraBindingTypes.size() != extraBindings.size()) {
2825 "expected types to be provided for all operands");
2841 bool hasExtras = !extraBindings.empty();
2851 printer << rootType;
2853 printer <<
", " << llvm::interleaved(extraBindingTypes) <<
')';
2860 auto iface = dyn_cast<transform::TransformOpInterface>(use.
getOwner());
2864 return isHandleConsumed(use.
get(), iface);
2875 if (!potentialConsumer) {
2876 potentialConsumer = &use;
2881 <<
" has more than one potential consumer";
2884 diag.attachNote(use.getOwner()->getLoc())
2885 <<
"used here as operand #" << use.getOperandNumber();
2892LogicalResult transform::SequenceOp::verify() {
2893 assert(getBodyBlock()->getNumArguments() >= 1 &&
2894 "the number of arguments must have been verified to be more than 1 by "
2895 "PossibleTopLevelTransformOpTrait");
2897 if (!getRoot() && !getExtraBindings().empty()) {
2899 <<
"does not expect extra operands when used as top-level";
2905 return (
emitOpError() <<
"block argument #" << arg.getArgNumber());
2912 for (
Operation &child : *getBodyBlock()) {
2913 if (!isa<TransformOpInterface>(child) &&
2914 &child != &getBodyBlock()->back()) {
2917 <<
"expected children ops to implement TransformOpInterface";
2918 diag.attachNote(child.getLoc()) <<
"op without interface";
2923 auto report = [&]() {
2924 return (child.emitError() <<
"result #" <<
result.getResultNumber());
2931 if (!getBodyBlock()->mightHaveTerminator())
2932 return emitOpError() <<
"expects to have a terminator in the body";
2934 if (getBodyBlock()->getTerminator()->getOperandTypes() !=
2935 getOperation()->getResultTypes()) {
2937 <<
"expects the types of the terminator operands "
2938 "to match the types of the result";
2939 diag.attachNote(getBodyBlock()->getTerminator()->getLoc()) <<
"terminator";
2945void transform::SequenceOp::getEffects(
2951transform::SequenceOp::getEntrySuccessorOperands(
RegionSuccessor successor) {
2952 assert(successor.
getSuccessor() == &getBody() &&
"unexpected region index");
2953 if (getOperation()->getNumOperands() > 0)
2954 return getOperation()->getOperands();
2956 getOperation()->operand_end());
2959void transform::SequenceOp::getSuccessorRegions(
2962 Region *bodyRegion = &getBody();
2963 regions.emplace_back(bodyRegion);
2969 "unexpected region index");
2975 if (getNumOperands() == 0)
2978 return getResults();
2979 return getBody().getArguments();
2982void transform::SequenceOp::getRegionInvocationBounds(
2985 bounds.emplace_back(1, 1);
2990 FailurePropagationMode failurePropagationMode,
2992 SequenceBodyBuilderFn bodyBuilder) {
2993 build(builder, state, resultTypes, failurePropagationMode, root,
3002 FailurePropagationMode failurePropagationMode,
3004 SequenceBodyBuilderArgsFn bodyBuilder) {
3005 build(builder, state, resultTypes, failurePropagationMode, root,
3013 FailurePropagationMode failurePropagationMode,
3015 SequenceBodyBuilderFn bodyBuilder) {
3016 build(builder, state, resultTypes, failurePropagationMode,
Value(),
3024 FailurePropagationMode failurePropagationMode,
3026 SequenceBodyBuilderArgsFn bodyBuilder) {
3027 build(builder, state, resultTypes, failurePropagationMode,
Value(),
3045 build(builder,
result, name);
3052 llvm::outs() <<
"[[[ IR printer: ";
3053 if (getName().has_value())
3054 llvm::outs() << *getName() <<
" ";
3057 if (getAssumeVerified().value_or(
false))
3059 if (getUseLocalScope().value_or(
false))
3061 if (getSkipRegions().value_or(
false))
3065 llvm::outs() <<
"top-level ]]]\n";
3067 llvm::outs() <<
"\n";
3068 llvm::outs().flush();
3072 llvm::outs() <<
"]]]\n";
3074 target->print(llvm::outs(), printFlags);
3075 llvm::outs() <<
"\n";
3078 llvm::outs().flush();
3082void transform::PrintOp::getEffects(
3087 if (!getTargetMutable().empty())
3107 <<
"failed to verify payload op";
3108 diag.attachNote(
target->getLoc()) <<
"payload op";
3114void transform::VerifyOp::getEffects(
3123void transform::YieldOp::getEffects(
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
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 std::string diag(const llvm::Value &value)
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(const ContainerType &container)
Print a comma separated list of operands.
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 StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
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.
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.