19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/ScopeExit.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/ErrorHandling.h"
24 #define DEBUG_TYPE "transform-dialect"
25 #define DEBUG_TYPE_FULL "transform-dialect-full"
26 #define DEBUG_PRINT_AFTER_ALL "transform-dialect-print-top-level-after-all"
27 #define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE "] ")
28 #define LDBG(X) LLVM_DEBUG(DBGS() << (X))
29 #define FULL_LDBG(X) DEBUG_WITH_TYPE(DEBUG_TYPE_FULL, (DBGS() << (X)))
37 constexpr
const Value transform::TransformState::kTopLevelValue;
39 transform::TransformState::TransformState(
42 const TransformOptions &
options)
44 topLevelMappedValues.reserve(extraMappings.
size());
46 topLevelMappedValues.push_back(mapping);
49 mappings.insert(std::make_pair(region, std::make_unique<Mappings>()));
50 assert(result.second &&
"the region scope is already present");
52 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
53 regionStack.push_back(region);
57 Operation *transform::TransformState::getTopLevel()
const {
return topLevel; }
60 transform::TransformState::getPayloadOpsView(
Value value)
const {
61 const TransformOpMapping &operationMapping = getMapping(value).direct;
62 auto iter = operationMapping.find(value);
64 iter != operationMapping.end() &&
65 "cannot find mapping for payload handle (param/value handle provided?)");
66 return iter->getSecond();
71 auto iter = mapping.find(value);
72 assert(iter != mapping.end() &&
"cannot find mapping for param handle "
73 "(operation/value handle provided?)");
74 return iter->getSecond();
78 transform::TransformState::getPayloadValuesView(
Value handleValue)
const {
79 const ValueMapping &mapping = getMapping(handleValue).values;
80 auto iter = mapping.find(handleValue);
81 assert(iter != mapping.end() &&
"cannot find mapping for value handle "
82 "(param/operation handle provided?)");
83 return iter->getSecond();
88 bool includeOutOfScope)
const {
90 for (
const auto &[region, mapping] : llvm::reverse(mappings)) {
91 auto iterator = mapping->reverse.find(op);
92 if (iterator != mapping->reverse.end()) {
93 llvm::append_range(handles, iterator->getSecond());
97 if (!includeOutOfScope &&
107 bool includeOutOfScope)
const {
109 for (
const auto &[region, mapping] : llvm::reverse(mappings)) {
110 auto iterator = mapping->reverseValues.find(payloadValue);
111 if (iterator != mapping->reverseValues.end()) {
112 llvm::append_range(handles, iterator->getSecond());
116 if (!includeOutOfScope &&
131 if (llvm::isa<transform::TransformHandleTypeInterface>(handle.
getType())) {
133 operations.reserve(values.size());
135 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(value)) {
136 operations.push_back(op);
140 <<
"wrong kind of value provided for top-level operation handle";
142 if (
failed(operationsFn(operations)))
147 if (llvm::isa<transform::TransformValueHandleTypeInterface>(
150 payloadValues.reserve(values.size());
152 if (
auto v = llvm::dyn_cast_if_present<Value>(value)) {
153 payloadValues.push_back(v);
157 <<
"wrong kind of value provided for the top-level value handle";
159 if (
failed(valuesFn(payloadValues)))
164 assert(llvm::isa<transform::TransformParamTypeInterface>(handle.
getType()) &&
165 "unsupported kind of block argument");
167 parameters.reserve(values.size());
169 if (
auto attr = llvm::dyn_cast_if_present<Attribute>(value)) {
170 parameters.push_back(attr);
174 <<
"wrong kind of value provided for top-level parameter";
176 if (
failed(paramsFn(parameters)))
187 return setPayloadOps(argument, operations);
190 return setParams(argument, params);
193 return setPayloadValues(argument, payloadValues);
199 transform::TransformState::setPayloadOps(
Value value,
201 assert(value != kTopLevelValue &&
202 "attempting to reset the transformation root");
203 assert(llvm::isa<TransformHandleTypeInterface>(value.
getType()) &&
204 "wrong handle type");
210 <<
"attempting to assign a null payload op to this transform value";
213 auto iface = llvm::cast<TransformHandleTypeInterface>(value.
getType());
215 iface.checkPayload(value.
getLoc(), targets);
222 Mappings &mappings = getMapping(value);
224 mappings.direct.insert({value, std::move(storedTargets)}).second;
225 assert(inserted &&
"value is already associated with another list");
229 mappings.reverse[op].push_back(value);
235 transform::TransformState::setPayloadValues(
Value handle,
237 assert(handle !=
nullptr &&
"attempting to set params for a null value");
238 assert(llvm::isa<TransformValueHandleTypeInterface>(handle.
getType()) &&
239 "wrong handle type");
241 for (
Value payload : payloadValues) {
244 return emitError(handle.
getLoc()) <<
"attempting to assign a null payload "
245 "value to this transform handle";
248 auto iface = llvm::cast<TransformValueHandleTypeInterface>(handle.
getType());
251 iface.checkPayload(handle.
getLoc(), payloadValueVector);
255 Mappings &mappings = getMapping(handle);
257 mappings.values.insert({handle, std::move(payloadValueVector)}).second;
260 "value handle is already associated with another list of payload values");
263 for (
Value payload : payloadValues)
264 mappings.reverseValues[payload].push_back(handle);
271 assert(value !=
nullptr &&
"attempting to set params for a null value");
277 <<
"attempting to assign a null parameter to this transform value";
280 auto valueType = llvm::dyn_cast<TransformParamTypeInterface>(value.
getType());
282 "cannot associate parameter with a value of non-parameter type");
284 valueType.checkPayload(value.
getLoc(), params);
288 Mappings &mappings = getMapping(value);
290 mappings.params.insert({value, llvm::to_vector(params)}).second;
291 assert(inserted &&
"value is already associated with another list of params");
296 template <
typename Mapping,
typename Key,
typename Mapped>
298 auto it = mapping.find(key);
299 if (it == mapping.end())
302 llvm::erase_value(it->getSecond(), mapped);
303 if (it->getSecond().empty())
307 void transform::TransformState::forgetMapping(
Value opHandle,
309 Mappings &mappings = getMapping(opHandle);
310 for (
Operation *op : mappings.direct[opHandle])
312 mappings.direct.erase(opHandle);
313 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
316 mappings.incrementTimestamp(opHandle);
319 for (
Value opResult : origOpFlatResults) {
321 (void)getHandlesForPayloadValue(opResult, resultHandles);
322 for (
Value resultHandle : resultHandles) {
323 Mappings &localMappings = getMapping(resultHandle);
325 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
328 mappings.incrementTimestamp(resultHandle);
335 void transform::TransformState::forgetValueMapping(
337 Mappings &mappings = getMapping(valueHandle);
338 for (
Value payloadValue : mappings.reverseValues[valueHandle])
340 mappings.values.erase(valueHandle);
341 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
344 mappings.incrementTimestamp(valueHandle);
347 for (
Operation *payloadOp : payloadOperations) {
349 (void)getHandlesForPayloadOp(payloadOp, opHandles);
350 for (
Value opHandle : opHandles) {
351 Mappings &localMappings = getMapping(opHandle);
355 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
358 localMappings.incrementTimestamp(opHandle);
365 transform::TransformState::replacePayloadOp(
Operation *op,
372 (void)getHandlesForPayloadValue(opResult, valueHandles,
374 assert(valueHandles.empty() &&
"expected no mapping to old results");
381 if (
failed(getHandlesForPayloadOp(op, opHandles,
true)))
383 for (
Value handle : opHandles) {
384 Mappings &mappings = getMapping(handle,
true);
388 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
389 if (
options.getExpensiveChecksEnabled()) {
390 auto it = cachedNames.find(op);
391 assert(it != cachedNames.end() &&
"entry not found");
392 assert(it->second == op->
getName() &&
"operation name mismatch");
393 cachedNames.erase(it);
396 cachedNames.insert({replacement, replacement->
getName()});
397 if (!insertion.second) {
398 assert(insertion.first->second == replacement->
getName() &&
399 "operation is already cached with a different name");
414 for (
Value handle : opHandles) {
415 Mappings &mappings = getMapping(handle,
true);
416 auto it = mappings.direct.find(handle);
417 if (it == mappings.direct.end())
424 mapped = replacement;
428 mappings.reverse[replacement].push_back(handle);
430 opHandlesToCompact.insert(handle);
438 transform::TransformState::replacePayloadValue(
Value value,
Value replacement) {
440 if (
failed(getHandlesForPayloadValue(value, valueHandles,
444 for (
Value handle : valueHandles) {
445 Mappings &mappings = getMapping(handle,
true);
452 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
455 mappings.incrementTimestamp(handle);
458 auto it = mappings.values.find(handle);
459 if (it == mappings.values.end())
463 for (
Value &mapped : association) {
465 mapped = replacement;
467 mappings.reverseValues[replacement].push_back(handle);
474 void transform::TransformState::recordOpHandleInvalidationOne(
481 if (invalidatedHandles.count(otherHandle) ||
482 newlyInvalidated.count(otherHandle))
485 FULL_LDBG(
"--recordOpHandleInvalidationOne\n");
488 llvm::interleaveComma(potentialAncestors,
DBGS() <<
"--ancestors: ",
489 [](
Operation *op) { llvm::dbgs() << *op; });
490 llvm::dbgs() <<
"\n");
494 for (
Operation *ancestor : potentialAncestors) {
497 { (
DBGS() <<
"----handle one ancestor: " << *ancestor <<
"\n"); });
499 { (
DBGS() <<
"----of payload with name: "
502 { (
DBGS() <<
"----of payload: " << *payloadOp <<
"\n"); });
504 if (!ancestor->isAncestor(payloadOp))
511 Location ancestorLoc = ancestor->getLoc();
513 std::optional<Location> throughValueLoc =
514 throughValue ? std::make_optional(throughValue.
getLoc()) : std::nullopt;
515 newlyInvalidated[otherHandle] = [ancestorLoc, opLoc, owner, operandNo,
517 throughValueLoc](
Location currentLoc) {
519 <<
"op uses a handle invalidated by a "
520 "previously executed transform op";
521 diag.attachNote(otherHandle.getLoc()) <<
"handle to invalidated ops";
522 diag.attachNote(owner->getLoc())
523 <<
"invalidated by this transform op that consumes its operand #"
525 <<
" and invalidates all handles to payload IR entities associated "
526 "with this operand and entities nested in them";
527 diag.attachNote(ancestorLoc) <<
"ancestor payload op";
528 diag.attachNote(opLoc) <<
"nested payload op";
529 if (throughValueLoc) {
530 diag.attachNote(*throughValueLoc)
531 <<
"consumed handle points to this payload value";
537 void transform::TransformState::recordValueHandleInvalidationByOpHandleOne(
544 if (invalidatedHandles.count(valueHandle) ||
545 newlyInvalidated.count(valueHandle))
548 for (
Operation *ancestor : potentialAncestors) {
550 std::optional<unsigned> resultNo;
554 if (
auto opResult = llvm::dyn_cast<OpResult>(payloadValue)) {
555 definingOp = opResult.getOwner();
556 resultNo = opResult.getResultNumber();
558 auto arg = llvm::cast<BlockArgument>(payloadValue);
560 argumentNo = arg.getArgNumber();
561 blockNo = std::distance(arg.getOwner()->getParent()->begin(),
562 arg.getOwner()->getIterator());
563 regionNo = arg.getOwner()->getParent()->getRegionNumber();
565 assert(definingOp &&
"expected the value to be defined by an op as result "
566 "or block argument");
567 if (!ancestor->isAncestor(definingOp))
572 Location ancestorLoc = ancestor->getLoc();
575 newlyInvalidated[valueHandle] = [valueHandle, owner, operandNo, resultNo,
576 argumentNo, blockNo, regionNo, ancestorLoc,
577 opLoc, valueLoc](
Location currentLoc) {
579 <<
"op uses a handle invalidated by a "
580 "previously executed transform op";
581 diag.attachNote(valueHandle.
getLoc()) <<
"invalidated handle";
582 diag.attachNote(owner->getLoc())
583 <<
"invalidated by this transform op that consumes its operand #"
585 <<
" and invalidates all handles to payload IR entities "
586 "associated with this operand and entities nested in them";
587 diag.attachNote(ancestorLoc)
588 <<
"ancestor op associated with the consumed handle";
590 diag.attachNote(opLoc)
591 <<
"op defining the value as result #" << *resultNo;
593 diag.attachNote(opLoc)
594 <<
"op defining the value as block argument #" << argumentNo
595 <<
" of block #" << blockNo <<
" in region #" << regionNo;
597 diag.attachNote(valueLoc) <<
"payload value";
602 void transform::TransformState::recordOpHandleInvalidation(
607 if (potentialAncestors.empty()) {
609 (
DBGS() <<
"----recording invalidation for empty handle: " << handle.
get()
615 newlyInvalidated[handle.
get()] = [owner, operandNo](
Location currentLoc) {
617 <<
"op uses a handle associated with empty "
618 "payload and invalidated by a "
619 "previously executed transform op";
620 diag.attachNote(owner->getLoc())
621 <<
"invalidated by this transform op that consumes its operand #"
634 for (
const auto &[region, mapping] : llvm::reverse(mappings)) {
641 for (
const auto &[payloadOp, otherHandles] : mapping->reverse) {
642 for (
Value otherHandle : otherHandles)
643 recordOpHandleInvalidationOne(handle, potentialAncestors, payloadOp,
644 otherHandle, throughValue,
652 for (
const auto &[payloadValue, valueHandles] : mapping->reverseValues) {
653 for (
Value valueHandle : valueHandles)
654 recordValueHandleInvalidationByOpHandleOne(handle, potentialAncestors,
655 payloadValue, valueHandle,
661 void transform::TransformState::recordValueHandleInvalidation(
665 for (
Value payloadValue : getPayloadValuesView(valueHandle.
get())) {
667 (void)getHandlesForPayloadValue(payloadValue, otherValueHandles);
668 for (
Value otherHandle : otherValueHandles) {
672 newlyInvalidated[otherHandle] = [otherHandle, owner, operandNo,
675 <<
"op uses a handle invalidated by a "
676 "previously executed transform op";
677 diag.attachNote(otherHandle.getLoc()) <<
"invalidated handle";
678 diag.attachNote(owner->getLoc())
679 <<
"invalidated by this transform op that consumes its operand #"
681 <<
" and invalidates handles to the same values as associated with "
683 diag.attachNote(valueLoc) <<
"payload value";
687 if (
auto opResult = llvm::dyn_cast<OpResult>(payloadValue)) {
688 Operation *payloadOp = opResult.getOwner();
689 recordOpHandleInvalidation(valueHandle, payloadOp, payloadValue,
692 auto arg = llvm::dyn_cast<BlockArgument>(payloadValue);
693 for (
Operation &payloadOp : *arg.getOwner())
694 recordOpHandleInvalidation(valueHandle, &payloadOp, payloadValue,
704 LogicalResult transform::TransformState::checkAndRecordHandleInvalidationImpl(
705 transform::TransformOpInterface transform,
707 FULL_LDBG(
"--Start checkAndRecordHandleInvalidation\n");
708 auto memoryEffectsIface =
709 cast<MemoryEffectOpInterface>(transform.getOperation());
711 memoryEffectsIface.getEffectsOnResource(
714 for (
OpOperand &target : transform->getOpOperands()) {
716 (
DBGS() <<
"----iterate on handle: " << target.get() <<
"\n");
722 auto it = invalidatedHandles.find(target.get());
723 auto nit = newlyInvalidated.find(target.get());
724 if (it != invalidatedHandles.end()) {
725 FULL_LDBG(
"--End checkAndRecordHandleInvalidation, found already "
726 "invalidated -> FAILURE\n");
727 return it->getSecond()(transform->getLoc()),
failure();
729 if (!transform.allowsRepeatedHandleOperands() &&
730 nit != newlyInvalidated.end()) {
731 FULL_LDBG(
"--End checkAndRecordHandleInvalidation, found newly "
732 "invalidated (by this op) -> FAILURE\n");
733 return nit->getSecond()(transform->getLoc()),
failure();
739 return isa<MemoryEffects::Free>(effect.getEffect()) &&
740 effect.getValue() == target.get();
742 if (llvm::any_of(effects, consumesTarget)) {
744 if (llvm::isa<transform::TransformHandleTypeInterface>(
745 target.get().getType())) {
746 FULL_LDBG(
"----recordOpHandleInvalidation\n");
748 llvm::to_vector(getPayloadOps(target.get()));
749 recordOpHandleInvalidation(target, payloadOps,
nullptr,
751 }
else if (llvm::isa<transform::TransformValueHandleTypeInterface>(
752 target.get().getType())) {
753 FULL_LDBG(
"----recordValueHandleInvalidation\n");
754 recordValueHandleInvalidation(target, newlyInvalidated);
756 FULL_LDBG(
"----not a TransformHandle -> SKIP AND DROP ON THE FLOOR\n");
759 FULL_LDBG(
"----no consume effect -> SKIP\n");
763 FULL_LDBG(
"--End checkAndRecordHandleInvalidation -> SUCCESS\n");
767 LogicalResult transform::TransformState::checkAndRecordHandleInvalidation(
768 transform::TransformOpInterface transform) {
769 InvalidatedHandleMap newlyInvalidated;
771 checkAndRecordHandleInvalidationImpl(transform, newlyInvalidated);
772 invalidatedHandles.insert(std::make_move_iterator(newlyInvalidated.begin()),
773 std::make_move_iterator(newlyInvalidated.end()));
777 template <
typename T>
780 transform::TransformOpInterface transform,
781 unsigned operandNumber) {
783 for (T p : payload) {
784 if (!seen.insert(p).second) {
786 transform.emitSilenceableError()
787 <<
"a handle passed as operand #" << operandNumber
788 <<
" and consumed by this operation points to a payload "
789 "entity more than once";
790 if constexpr (std::is_pointer_v<T>)
791 diag.attachNote(p->getLoc()) <<
"repeated target op";
793 diag.attachNote(p.getLoc()) <<
"repeated target value";
800 void transform::TransformState::compactOpHandles() {
801 for (
Value handle : opHandlesToCompact) {
802 Mappings &mappings = getMapping(handle,
true);
803 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
804 if (llvm::find(mappings.direct[handle],
nullptr) !=
805 mappings.direct[handle].end())
808 mappings.incrementTimestamp(handle);
810 llvm::erase_value(mappings.direct[handle],
nullptr);
812 opHandlesToCompact.clear();
818 DBGS() <<
"applying: ";
820 llvm::dbgs() <<
"\n";
823 DBGS() <<
"Top-level payload before application:\n"
824 << *getTopLevel() <<
"\n");
825 auto printOnFailureRAII = llvm::make_scope_exit([
this] {
827 LLVM_DEBUG(
DBGS() <<
"Failing Top-level payload:\n"; getTopLevel()->print(
830 if (
options.getExpensiveChecksEnabled()) {
832 if (
failed(checkAndRecordHandleInvalidation(transform)))
835 for (
OpOperand &operand : transform->getOpOperands()) {
837 (
DBGS() <<
"iterate on handle: " << operand.get() <<
"\n");
840 FULL_LDBG(
"--handle not consumed -> SKIP\n");
843 if (transform.allowsRepeatedHandleOperands()) {
844 FULL_LDBG(
"--op allows repeated handles -> SKIP\n");
849 Type operandType = operand.get().getType();
850 if (llvm::isa<TransformHandleTypeInterface>(operandType)) {
851 FULL_LDBG(
"--checkRepeatedConsumptionInOperand for Operation*\n");
853 checkRepeatedConsumptionInOperand<Operation *>(
854 getPayloadOpsView(operand.get()), transform,
855 operand.getOperandNumber());
860 }
else if (llvm::isa<TransformValueHandleTypeInterface>(operandType)) {
861 FULL_LDBG(
"--checkRepeatedConsumptionInOperand For Value\n");
863 checkRepeatedConsumptionInOperand<Value>(
864 getPayloadValuesView(operand.get()), transform,
865 operand.getOperandNumber());
871 FULL_LDBG(
"--not a TransformHandle -> SKIP AND DROP ON THE FLOOR\n");
875 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
879 for (std::unique_ptr<Mappings> &mapping :
880 llvm::make_second_range(mappings)) {
881 for (
Operation *op : llvm::make_first_range(mapping->reverse)) {
882 auto insertion = cachedNames.insert({op, op->
getName()});
883 if (!insertion.second) {
884 if (insertion.first->second != op->
getName()) {
888 <<
"expensive checks failure: operation mismatch, expected "
889 << insertion.first->second;
901 transform.getConsumedHandleOpOperands();
910 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
913 for (
OpOperand *opOperand : consumedOperands) {
914 Value operand = opOperand->get();
915 if (llvm::isa<TransformHandleTypeInterface>(operand.
getType())) {
916 for (
Operation *payloadOp : getPayloadOps(operand)) {
917 llvm::append_range(origOpFlatResults, payloadOp->
getResults());
918 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
919 if (
options.getExpensiveChecksEnabled()) {
923 [&](
Operation *op) { consumedPayloadOps.insert(op); });
929 if (llvm::isa<TransformValueHandleTypeInterface>(operand.
getType())) {
930 for (
Value payloadValue : getPayloadValuesView(operand)) {
931 if (llvm::isa<OpResult>(payloadValue)) {
937 llvm::map_range(*llvm::cast<BlockArgument>(payloadValue).getOwner(),
944 <<
"unexpectedly consumed a value that is not a handle as operand #"
945 << opOperand->getOperandNumber();
947 <<
"value defined here with type " << operand.
getType();
968 transform::TransformDialect::kSilenceTrackingFailuresAttrName)) {
972 (void)trackingFailure.
silence();
977 result = std::move(trackingFailure);
981 result.
attachNote() <<
"tracking listener also failed: "
983 (void)trackingFailure.
silence();
996 for (
OpOperand *opOperand : consumedOperands) {
997 Value operand = opOperand->get();
998 if (llvm::isa<TransformHandleTypeInterface>(operand.
getType())) {
999 forgetMapping(operand, origOpFlatResults);
1000 }
else if (llvm::isa<TransformValueHandleTypeInterface>(
1002 forgetValueMapping(operand, origAssociatedOps);
1006 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1007 if (
options.getExpensiveChecksEnabled()) {
1009 for (
Operation *op : consumedPayloadOps) {
1024 (void)getHandlesForPayloadOp(op, handles);
1025 for (
Value handle : handles)
1027 cachedNames.erase(op);
1031 for (std::unique_ptr<Mappings> &mapping :
1032 llvm::make_second_range(mappings)) {
1033 for (
Operation *op : llvm::make_first_range(mapping->reverse)) {
1037 auto cacheIt = cachedNames.find(op);
1038 if (cacheIt == cachedNames.end()) {
1041 <<
"expensive checks failure: operation not found in cache";
1042 diag.attachNote(op->
getLoc()) <<
"payload op";
1049 if (cacheIt->second != op->
getName()) {
1052 <<
"expensive checks failure: operation mismatch, expected "
1062 if (
failed(updateStateFromResults(results, transform->getResults())))
1065 printOnFailureRAII.release();
1067 DBGS() <<
"Top-level payload:\n";
1068 getTopLevel()->print(llvm::dbgs());
1073 LogicalResult transform::TransformState::updateStateFromResults(
1075 for (
OpResult result : opResults) {
1076 if (llvm::isa<TransformParamTypeInterface>(result.getType())) {
1077 assert(results.isParam(result.getResultNumber()) &&
1078 "expected parameters for the parameter-typed result");
1080 setParams(result, results.getParams(result.getResultNumber())))) {
1083 }
else if (llvm::isa<TransformValueHandleTypeInterface>(result.getType())) {
1084 assert(results.isValue(result.getResultNumber()) &&
1085 "expected values for value-type-result");
1086 if (
failed(setPayloadValues(
1087 result, results.getValues(result.getResultNumber())))) {
1091 assert(!results.isParam(result.getResultNumber()) &&
1092 "expected payload ops for the non-parameter typed result");
1094 setPayloadOps(result, results.get(result.getResultNumber())))) {
1113 return state.replacePayloadOp(op, replacement);
1118 Value replacement) {
1119 return state.replacePayloadValue(value, replacement);
1130 for (
Block &block : *region) {
1131 for (
Value handle : block.getArguments()) {
1132 state.invalidatedHandles.erase(handle);
1136 state.invalidatedHandles.erase(handle);
1141 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1145 llvm::to_vector(llvm::make_first_range(state.mappings[region]->reverse));
1148 state.mappings.erase(region);
1150 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1156 if (
succeeded(state.getHandlesForPayloadOp(op, handles)))
1158 state.cachedNames.erase(op);
1161 state.regionStack.pop_back();
1169 transform::TransformResults::TransformResults(
unsigned numSegments) {
1170 operations.appendEmptyRows(numSegments);
1171 params.appendEmptyRows(numSegments);
1172 values.appendEmptyRows(numSegments);
1178 assert(position <
static_cast<int64_t
>(this->params.size()) &&
1179 "setting params for a non-existent handle");
1180 assert(this->params[position].data() ==
nullptr &&
"params already set");
1181 assert(operations[position].data() ==
nullptr &&
1182 "another kind of results already set");
1183 assert(values[position].data() ==
nullptr &&
1184 "another kind of results already set");
1185 this->params.replace(position, params);
1193 return set(handle, operations),
success();
1196 return setParams(handle, params),
success();
1199 return setValues(handle, payloadValues),
success();
1202 if (!
diag.succeeded())
1203 llvm::dbgs() <<
diag.getStatusString() <<
"\n";
1204 assert(
diag.succeeded() &&
"incorrect mapping");
1206 (void)
diag.silence();
1210 transform::TransformOpInterface transform) {
1211 for (
OpResult opResult : transform->getResults()) {
1212 if (!isSet(opResult.getResultNumber()))
1213 setMappedValues(opResult, {});
1218 transform::TransformResults::get(
unsigned resultNumber)
const {
1219 assert(resultNumber < operations.size() &&
1220 "querying results for a non-existent handle");
1221 assert(operations[resultNumber].data() !=
nullptr &&
1222 "querying unset results (values or params expected?)");
1223 return operations[resultNumber];
1227 transform::TransformResults::getParams(
unsigned resultNumber)
const {
1228 assert(resultNumber < params.size() &&
1229 "querying params for a non-existent handle");
1230 assert(params[resultNumber].data() !=
nullptr &&
1231 "querying unset params (ops or values expected?)");
1232 return params[resultNumber];
1236 transform::TransformResults::getValues(
unsigned resultNumber)
const {
1237 assert(resultNumber < values.size() &&
1238 "querying values for a non-existent handle");
1239 assert(values[resultNumber].data() !=
nullptr &&
1240 "querying unset values (ops or params expected?)");
1241 return values[resultNumber];
1244 bool transform::TransformResults::isParam(
unsigned resultNumber)
const {
1245 assert(resultNumber < params.size() &&
1246 "querying association for a non-existent handle");
1247 return params[resultNumber].data() !=
nullptr;
1250 bool transform::TransformResults::isValue(
unsigned resultNumber)
const {
1251 assert(resultNumber < values.size() &&
1252 "querying association for a non-existent handle");
1253 return values[resultNumber].data() !=
nullptr;
1256 bool transform::TransformResults::isSet(
unsigned resultNumber)
const {
1257 assert(resultNumber < params.size() &&
1258 "querying association for a non-existent handle");
1259 return params[resultNumber].data() !=
nullptr ||
1260 operations[resultNumber].data() !=
nullptr ||
1261 values[resultNumber].data() !=
nullptr;
1269 TransformOpInterface op)
1272 for (
OpOperand *opOperand : transformOp.getConsumedHandleOpOperands()) {
1273 consumedHandles.insert(opOperand->get());
1280 for (
Value v : values) {
1285 defOp = v.getDefiningOp();
1288 if (defOp != v.getDefiningOp())
1297 "invalid number of replacement values");
1301 getTransformOp(),
"tracking listener failed to find replacement op "
1302 "during application of this transform op");
1306 Operation *defOp = getCommonDefiningOp(values);
1308 diag.attachNote() <<
"replacement values belong to different ops";
1328 if (
auto findReplacementOpInterface =
1329 dyn_cast<FindPayloadReplacementOpInterface>(defOp)) {
1330 values.assign(findReplacementOpInterface.getNextOperands());
1331 diag.attachNote(defOp->
getLoc()) <<
"using operands provided by "
1332 "'FindPayloadReplacementOpInterface'";
1337 if (isa<CastOpInterface>(defOp)) {
1340 <<
"using output of 'CastOpInterface' op";
1343 }
while (!values.empty());
1345 diag.attachNote() <<
"ran out of suitable replacement values";
1353 reasonCallback(
diag);
1354 DBGS() <<
"Match Failure : " <<
diag.str() <<
"\n";
1359 void transform::TrackingListener::notifyOperationRemoved(
Operation *op) {
1364 (
void)replacePayloadValue(value,
nullptr);
1366 (void)replacePayloadOp(op,
nullptr);
1383 void transform::TrackingListener::notifyOperationReplaced(
1386 "invalid number of replacement values");
1389 for (
auto [oldValue, newValue] : llvm::zip(op->
getResults(), newValues))
1390 (void)replacePayloadValue(oldValue, newValue);
1394 if (
failed(getTransformState().getHandlesForPayloadOp(
1395 op, opHandles,
true))) {
1409 auto handleWasConsumed = [&] {
1410 return llvm::any_of(opHandles,
1411 [&](
Value h) {
return consumedHandles.contains(h); });
1415 auto firstAliveUser = [&]() -> std::optional<OpOperand *> {
1416 for (
Value v : opHandles) {
1418 if (use.getOwner() != transformOp &&
1422 return std::nullopt;
1425 if (!firstAliveUser.has_value() || handleWasConsumed()) {
1428 (void)replacePayloadOp(op,
nullptr);
1434 findReplacementOp(replacement, op, newValues);
1437 if (!
diag.succeeded()) {
1438 diag.attachNote((*firstAliveUser)->getOwner()->getLoc())
1439 <<
"replacement is required because alive handle(s) exist "
1440 <<
"(first use in this op as operand number "
1441 << (*firstAliveUser)->getOperandNumber() <<
")";
1442 notifyPayloadReplacementNotFound(op, newValues, std::move(
diag));
1443 (void)replacePayloadOp(op,
nullptr);
1447 (void)replacePayloadOp(op, replacement);
1454 assert(status.succeeded() &&
"listener state was not checked");
1466 return !status.succeeded();
1474 diag.takeDiagnostics(diags);
1475 if (!status.succeeded())
1476 status.takeDiagnostics(diags);
1480 status.attachNote(op->
getLoc()) <<
"[" << errorCounter <<
"] replaced op";
1482 status.attachNote(value.
getLoc())
1483 <<
"[" << errorCounter <<
"] replacement value " << index;
1498 return listener->failed();
1503 if (hasTrackingFailures()) {
1511 return listener->replacePayloadOp(op, replacement);
1522 for (
Operation *child : targets.drop_front(position + 1)) {
1523 if (parent->isAncestor(child)) {
1526 <<
"transform operation consumes a handle pointing to an ancestor "
1527 "payload operation before its descendant";
1529 <<
"the ancestor is likely erased or rewritten before the "
1530 "descendant is accessed, leading to undefined behavior";
1531 diag.attachNote(parent->getLoc()) <<
"ancestor payload op";
1532 diag.attachNote(child->getLoc()) <<
"descendant payload op";
1551 diag.attachNote(payloadOpLoc) <<
"when applied to this op";
1555 if (partialResult.
size() != expectedNumResults) {
1556 auto diag =
emitDiag() <<
"application of " << transformOpName
1557 <<
" expected to produce " << expectedNumResults
1558 <<
" results (actually produced "
1559 << partialResult.
size() <<
").";
1560 diag.attachNote(transformOpLoc)
1561 <<
"if you need variadic results, consider a generic `apply` "
1562 <<
"instead of the specialized `applyToOne`.";
1567 for (
const auto &[ptr, res] :
1568 llvm::zip(partialResult, transformOp->
getResults())) {
1571 if (llvm::isa<TransformHandleTypeInterface>(res.getType()) &&
1573 return emitDiag() <<
"application of " << transformOpName
1574 <<
" expected to produce an Operation * for result #"
1575 << res.getResultNumber();
1577 if (llvm::isa<TransformParamTypeInterface>(res.getType()) &&
1579 return emitDiag() <<
"application of " << transformOpName
1580 <<
" expected to produce an Attribute for result #"
1581 << res.getResultNumber();
1583 if (llvm::isa<TransformValueHandleTypeInterface>(res.getType()) &&
1585 return emitDiag() <<
"application of " << transformOpName
1586 <<
" expected to produce a Value for result #"
1587 << res.getResultNumber();
1593 template <
typename T>
1595 return llvm::to_vector(llvm::map_range(
1605 if (llvm::any_of(partialResults,
1606 [](
MappedValue value) {
return value.isNull(); }))
1608 assert(transformOp->
getNumResults() == partialResults.size() &&
1609 "expected as many partial results as op as results");
1611 transposed[i].push_back(value);
1615 unsigned position = r.getResultNumber();
1616 if (llvm::isa<TransformParamTypeInterface>(r.getType())) {
1618 castVector<Attribute>(transposed[position]));
1619 }
else if (llvm::isa<TransformValueHandleTypeInterface>(r.getType())) {
1620 transformResults.
setValues(r, castVector<Value>(transposed[position]));
1622 transformResults.
set(r, castVector<Operation *>(transposed[position]));
1634 for (
Value operand : values) {
1636 if (llvm::isa<TransformHandleTypeInterface>(operand.getType())) {
1637 llvm::append_range(mapped, state.getPayloadOps(operand));
1638 }
else if (llvm::isa<TransformValueHandleTypeInterface>(
1639 operand.getType())) {
1640 llvm::append_range(mapped, state.getPayloadValues(operand));
1642 assert(llvm::isa<TransformParamTypeInterface>(operand.getType()) &&
1643 "unsupported kind of transform dialect value");
1644 llvm::append_range(mapped, state.getParams(operand));
1652 for (
auto &&[terminatorOperand, result] :
1655 if (llvm::isa<transform::TransformHandleTypeInterface>(result.getType())) {
1656 results.
set(result, state.getPayloadOps(terminatorOperand));
1657 }
else if (llvm::isa<transform::TransformValueHandleTypeInterface>(
1658 result.getType())) {
1659 results.
setValues(result, state.getPayloadValues(terminatorOperand));
1662 llvm::isa<transform::TransformParamTypeInterface>(result.getType()) &&
1663 "unhandled transform type interface");
1664 results.
setParams(result, state.getParams(terminatorOperand));
1685 iface.getEffectsOnValue(source, nestedEffects);
1686 for (
const auto &effect : nestedEffects)
1687 effects.emplace_back(effect.getEffect(), target, effect.getResource());
1696 auto iface = dyn_cast<MemoryEffectOpInterface>(&op);
1700 for (
auto &&[source, target] : llvm::zip(block.
getArguments(), operands)) {
1707 llvm::append_range(effects, nestedEffects);
1719 auto iface = dyn_cast<MemoryEffectOpInterface>(&op);
1724 iface.getEffects(effects);
1739 llvm::append_range(targets, state.getPayloadOps(op->
getOperand(0)));
1742 if (state.getNumTopLevelMappings() !=
1746 <<
" extra value bindings, but " << state.getNumTopLevelMappings()
1747 <<
" were provided to the interpreter";
1756 if (
auto bbArgType = dyn_cast<transform::OperationType>(bbArg.
getType())) {
1759 targets.push_back(op);
1765 targets.push_back(state.getTopLevel());
1768 for (
unsigned i = 0, e = state.getNumTopLevelMappings(); i < e; ++i)
1769 extraMappings.push_back(llvm::to_vector(state.getTopLevelMapping(i)));
1776 if (
failed(state.mapBlockArgument(
1777 argument, extraMappings[argument.getArgNumber() - 1])))
1789 assert(isa<TransformOpInterface>(op) &&
1790 "should implement TransformOpInterface to have "
1791 "PossibleTopLevelTransformOpTrait");
1794 return op->
emitOpError() <<
"expects at least one region";
1797 if (!llvm::hasNItems(*bodyRegion, 1))
1798 return op->
emitOpError() <<
"expects a single-block region";
1803 <<
"expects the entry block to have at least one argument";
1805 if (!llvm::isa<TransformHandleTypeInterface>(
1808 <<
"expects the first entry block argument to be of type "
1809 "implementing TransformHandleTypeInterface";
1815 <<
"expects the type of the block argument to match "
1816 "the type of the operand";
1820 if (llvm::isa<TransformHandleTypeInterface, TransformParamTypeInterface,
1821 TransformValueHandleTypeInterface>(arg.
getType()))
1826 <<
"expects trailing entry block arguments to be of type implementing "
1827 "TransformHandleTypeInterface, TransformValueHandleTypeInterface or "
1828 "TransformParamTypeInterface";
1838 <<
"expects operands to be provided for a nested op";
1839 diag.attachNote(parent->getLoc())
1840 <<
"nested in another possible top-level op";
1855 bool hasPayloadOperands =
false;
1858 if (llvm::isa<TransformHandleTypeInterface,
1859 TransformValueHandleTypeInterface>(operand.getType()))
1860 hasPayloadOperands =
true;
1862 if (hasPayloadOperands)
1871 llvm::report_fatal_error(
1872 Twine(
"ParamProducerTransformOpTrait must be attached to an op that "
1873 "implements MemoryEffectsOpInterface, found on ") +
1877 if (llvm::isa<TransformParamTypeInterface>(result.getType()))
1880 <<
"ParamProducerTransformOpTrait attached to this op expects "
1881 "result types to implement TransformParamTypeInterface";
1893 for (
Value handle : handles) {
1903 template <
typename EffectTy,
typename ResourceTy,
typename Range>
1906 return isa<EffectTy>(effect.
getEffect()) &&
1912 transform::TransformOpInterface transform) {
1913 auto iface = cast<MemoryEffectOpInterface>(transform.getOperation());
1915 iface.getEffectsOnValue(handle, effects);
1916 return ::hasEffect<MemoryEffects::Read, TransformMappingResource>(effects) &&
1917 ::hasEffect<MemoryEffects::Free, TransformMappingResource>(effects);
1923 for (
Value handle : handles) {
1934 for (
Value handle : handles) {
1952 auto iface = cast<MemoryEffectOpInterface>(transform.getOperation());
1954 iface.getEffects(effects);
1955 return ::hasEffect<MemoryEffects::Write, PayloadIRResource>(effects);
1959 auto iface = cast<MemoryEffectOpInterface>(transform.getOperation());
1961 iface.getEffects(effects);
1962 return ::hasEffect<MemoryEffects::Read, PayloadIRResource>(effects);
1966 Block &block, llvm::SmallDenseSet<unsigned int> &consumedArguments) {
1969 auto iface = dyn_cast<MemoryEffectOpInterface>(nested);
1974 iface.getEffects(effects);
1977 dyn_cast_or_null<BlockArgument>(effect.getValue());
1978 if (!argument || argument.
getOwner() != &block ||
1979 !isa<MemoryEffects::Free>(effect.getEffect()) ||
1993 TransformOpInterface transformOp) {
1995 consumedOperands.reserve(transformOp->getNumOperands());
1996 auto memEffectInterface =
1997 cast<MemoryEffectOpInterface>(transformOp.getOperation());
1999 for (
OpOperand &target : transformOp->getOpOperands()) {
2001 memEffectInterface.getEffectsOnValue(target.get(), effects);
2003 return isa<transform::TransformMappingResource>(
2005 isa<MemoryEffects::Free>(effect.
getEffect());
2007 consumedOperands.push_back(&target);
2010 return consumedOperands;
2014 auto iface = cast<MemoryEffectOpInterface>(op);
2016 iface.getEffects(effects);
2018 auto effectsOn = [&](
Value value) {
2019 return llvm::make_filter_range(
2021 return instance.
getValue() == value;
2025 std::optional<unsigned> firstConsumedOperand;
2027 auto range = effectsOn(operand.get());
2028 if (range.empty()) {
2030 op->
emitError() <<
"TransformOpInterface requires memory effects "
2031 "on operands to be specified";
2032 diag.attachNote() <<
"no effects specified for operand #"
2033 << operand.getOperandNumber();
2036 if (::hasEffect<MemoryEffects::Allocate, TransformMappingResource>(range)) {
2038 <<
"TransformOpInterface did not expect "
2039 "'allocate' memory effect on an operand";
2040 diag.attachNote() <<
"specified for operand #"
2041 << operand.getOperandNumber();
2044 if (!firstConsumedOperand &&
2045 ::hasEffect<MemoryEffects::Free, TransformMappingResource>(range)) {
2046 firstConsumedOperand = operand.getOperandNumber();
2050 if (firstConsumedOperand &&
2051 !::hasEffect<MemoryEffects::Write, PayloadIRResource>(effects)) {
2054 <<
"TransformOpInterface expects ops consuming operands to have a "
2055 "'write' effect on the payload resource";
2056 diag.attachNote() <<
"consumes operand #" << *firstConsumedOperand;
2061 auto range = effectsOn(result);
2062 if (!::hasEffect<MemoryEffects::Allocate, TransformMappingResource>(
2065 op->
emitError() <<
"TransformOpInterface requires 'allocate' memory "
2066 "effect to be specified for results";
2067 diag.attachNote() <<
"no 'allocate' effect specified for result #"
2068 << result.getResultNumber();
2082 TransformOpInterface transform,
2087 transform->getNumOperands() != 0) {
2088 transform->emitError()
2089 <<
"expected transform to start at the top-level transform op";
2090 llvm::report_fatal_error(
"could not run transforms",
2095 TransformState state(transform->getParentRegion(), payloadRoot, extraMapping,
2097 return state.applyTransform(transform).checkAndReport();
2104 #include "mlir/Dialect/Transform/IR/TransformInterfaces.cpp.inc"
static InFlightDiagnostic emitDiag(Location location, DiagnosticSeverity severity, const Twine &message)
Helper function used to emit a diagnostic with an optionally empty twine message.
static std::string diag(const llvm::Value &value)
static llvm::ManagedStatic< PassManagerOptions > options
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block * getOwner() const
Returns the block that owns this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
Operation * findAncestorOpInBlock(Operation &op)
Returns 'op' if 'op' lies in this block, or otherwise finds the ancestor operation of 'op' that lies ...
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
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.
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the last diagnostic.
std::string getMessage() const
Returns the diagnostic message without emitting it.
bool isDefiniteFailure() const
Returns true if this is a definite failure.
LogicalResult checkAndReport()
Converts all kinds of failure into a LogicalResult failure, emitting the diagnostic if necessary.
static DiagnosedSilenceableFailure silenceableFailure(Diagnostic &&diag)
Constructs a DiagnosedSilenceableFailure in the silenceable failure state, ready to emit the given di...
bool succeeded() const
Returns true if this is a success.
static DiagnosedSilenceableFailure definiteFailure()
Constructs a DiagnosedSilenceableFailure in the failure state.
bool isSilenceableFailure() const
Returns true if this is a silenceable failure.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
IRValueT get() const
Return the current value being used by this operand.
This class represents a diagnostic that is inflight and set to be reported.
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.
void setListener(Listener *newListener)
Sets the listener of this builder to the one provided.
This class represents an operand of an operation.
unsigned getOperandNumber()
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.
This is a value defined by a result of an operation.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for a sub-set of ops that are known to be constant-like.
This class provides the API for ops that are known to be isolated from above.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
StringAttr getIdentifier() const
Return the name of this operation as a StringAttr.
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this operat...
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
OperationName getName()
The name of an operation is the key identifier for it.
MutableArrayRef< OpOperand > getOpOperands()
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getOpResults()
result_range getResults()
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
A 2D array where each row may have different length.
size_t size() const
Returns the number of rows in the 2D array.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
This class implements the result iterators for the Operation class.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
This class represents a specific instance of an effect.
Resource * getResource() const
Return the resource that the effect applies to.
EffectT * getEffect() const
Return the effect being applied.
Value getValue() const
Return the value the effect is applied on, or nullptr if there isn't a known value being affected.
static DerivedEffect * get()
Returns a unique instance for the derived effect class.
static TransformMappingResource * get()
Returns a unique instance for the given effect class.
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.
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.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static WalkResult advance()
Operation * getOwner() const
Return the owner of this operand.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
bool hasEffect(Operation *op, Value value=nullptr)
Returns true if op has an effect of type EffectTy on value.
DiagnosedSilenceableFailure emitSilenceableFailure(Location loc, const Twine &message={})
Emits a silenceable failure with the given message.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message={})
Emits a definite failure with the given message.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...