MLIR 24.0.0git
TosaProfileCompliance.cpp
Go to the documentation of this file.
1//===--- TosaProfileCompliance.cpp - Tosa Profile Compliance Validation ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/Support/Compiler.h"
12#include "llvm/Support/raw_ostream.h"
13
14namespace mlir {
15namespace tosa {
16LLVM_ATTRIBUTE_NOINLINE
17VersionedTypeInfo::VersionedTypeInfo(std::initializer_list<TypeInfoRef> types,
18 SpecificationVersion version)
19 : second(version) {
20 first.reserve(types.size());
21 for (const TypeInfoRef &type : types)
22 first.push_back(*type.ptr);
23}
24
25LLVM_ATTRIBUTE_NOINLINE
27 SpecificationVersion version)
28 : first(std::move(types)), second(version) {}
29
30LLVM_ATTRIBUTE_NOINLINE
32
33LLVM_ATTRIBUTE_NOINLINE
35
36LLVM_ATTRIBUTE_NOINLINE
39
40LLVM_ATTRIBUTE_NOINLINE
43
44LLVM_ATTRIBUTE_NOINLINE
46
47template <typename T>
49 std::initializer_list<T> mode,
50 std::initializer_list<VersionedTypeInfo> operandTypeInfoSet,
53}
54
55template <typename T>
61
62template <typename T>
63LLVM_ATTRIBUTE_NOINLINE
65
66template <typename T>
67LLVM_ATTRIBUTE_NOINLINE
69
70template <typename T>
71LLVM_ATTRIBUTE_NOINLINE OpComplianceInfo<T> &
73
74template <typename T>
75LLVM_ATTRIBUTE_NOINLINE OpComplianceInfo<T> &
77
78template <typename T>
79LLVM_ATTRIBUTE_NOINLINE OpComplianceInfo<T>::~OpComplianceInfo() = default;
80
81template struct OpComplianceInfo<Profile>;
82template struct OpComplianceInfo<Extension>;
83
85 static const TypeInfo boolT = {mlir::IntegerType::getTypeID(), 1};
86 static const TypeInfo i4T = {mlir::IntegerType::getTypeID(), 4};
87 static const TypeInfo i8T = {mlir::IntegerType::getTypeID(), 8};
88 static const TypeInfo i16T = {mlir::IntegerType::getTypeID(), 16};
89 static const TypeInfo i32T = {mlir::IntegerType::getTypeID(), 32};
90 static const TypeInfo i48T = {mlir::IntegerType::getTypeID(), 48};
91 static const TypeInfo i64T = {mlir::IntegerType::getTypeID(), 64};
92 static const TypeInfo bf16T = {mlir::BFloat16Type::getTypeID(), 16};
93 static const TypeInfo fp16T = {mlir::Float16Type::getTypeID(), 16};
94 static const TypeInfo fp32T = {mlir::Float32Type::getTypeID(), 32};
95 static const TypeInfo fp8e4m3T = {mlir::Float8E4M3FNType::getTypeID(), 8};
96 static const TypeInfo fp8e5m2T = {mlir::Float8E5M2Type::getTypeID(), 8};
97
98 // micro-scaling formats
99 // Note: these types exist to support the deprecated block_scaled operations
100 // and can be removed once those operations are removed.
101 static const TypeInfo fp6e2m3T = {mlir::Float6E2M3FNType::getTypeID(), 6};
102 static const TypeInfo fp6e3m2T = {mlir::Float6E3M2FNType::getTypeID(), 6};
103 static const TypeInfo fp4e2m1T = {mlir::Float4E2M1FNType::getTypeID(), 4};
104 static const TypeInfo fp8ue8m0T = {mlir::Float8E8M0FNUType::getTypeID(), 8};
105 static const TypeInfo mxint8T = {mlir::MXI8Type::getTypeID(), 8};
106
107 // Block scaled formats
108 const TypeID blockScaledID = mlir::tosa::BlockScaledType::getTypeID();
109 const TypeID fp4e2m1ID = mlir::Float4E2M1FNType::getTypeID();
110 const TypeID fp6e2m3ID = mlir::Float6E2M3FNType::getTypeID();
111 const TypeID fp6e3m2ID = mlir::Float6E3M2FNType::getTypeID();
112 const TypeID fp8e4m3ID = mlir::Float8E4M3FNType::getTypeID();
113 const TypeID fp8e5m2ID = mlir::Float8E5M2Type::getTypeID();
114 const TypeID fp8ue8m0ID = mlir::Float8E8M0FNUType::getTypeID();
115 const TypeID mxint8ID = mlir::MXI8Type::getTypeID();
116
117 static const TypeInfo bs32_fp8ue8m0_fp4e2m1T = {
118 blockScaledID, 4, fp4e2m1ID, fp8ue8m0ID,
119 tosa::BlockShape::BLOCK_SHAPE_32};
120 static const TypeInfo bs32_fp8ue8m0_fp6e2m3T = {
121 blockScaledID, 6, fp6e2m3ID, fp8ue8m0ID,
122 tosa::BlockShape::BLOCK_SHAPE_32};
123 static const TypeInfo bs32_fp8ue8m0_fp6e3m2T = {
124 blockScaledID, 6, fp6e3m2ID, fp8ue8m0ID,
125 tosa::BlockShape::BLOCK_SHAPE_32};
126 static const TypeInfo bs32_fp8ue8m0_fp8e4m3T = {
127 blockScaledID, 8, fp8e4m3ID, fp8ue8m0ID,
128 tosa::BlockShape::BLOCK_SHAPE_32};
129 static const TypeInfo bs32_fp8ue8m0_fp8e5m2T = {
130 blockScaledID, 8, fp8e5m2ID, fp8ue8m0ID,
131 tosa::BlockShape::BLOCK_SHAPE_32};
132 static const TypeInfo bs32_fp8ue8m0_mxint8T = {
133 blockScaledID, 8, mxint8ID, fp8ue8m0ID, tosa::BlockShape::BLOCK_SHAPE_32};
134
135// The profile-based compliance content below is auto-generated by a script
136// in https://github.com/arm/tosa-specification
138 // End of auto-generated metadata
139}
140
141template <>
144 return profileComplianceMap;
145}
146
147template <>
150 return extensionComplianceMap;
151}
152
153// Base populating function
154LogicalResult ProfileInfoDepot::populateProfileInfo(ValueRange operands,
155 ValueRange results) {
156 for (const auto &operand : operands)
157 addValue(operand);
158 for (const auto &result : results)
160 return success();
161}
162
163template <>
164LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::ConcatOp op) {
165 addValue(op.getInput1().front());
166 addValue(op.getOutput());
167 return success();
168}
169
170template <>
171LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::AvgPool2dOp op) {
172 addValue(op.getInput());
173 addValue(op.getInputZp());
174 addValue(op.getOutputZp());
175 addType(op.getAccType());
176 addValue(op.getOutput());
177 return success();
178}
179
180template <>
181LogicalResult
182ProfileInfoDepot::populateProfileInfo(tosa::AvgPool2dAdaptiveOp op) {
183 addValue(op.getInput());
184 addValue(op.getInputZp());
185 addValue(op.getOutputZp());
186 addType(op.getAccType());
187 addValue(op.getOutput());
188 return success();
189}
190
191template <>
192LogicalResult
193ProfileInfoDepot::populateProfileInfo(tosa::MaxPool2dAdaptiveOp op) {
194 addValue(op.getInput());
195 addValue(op.getOutput());
196 return success();
197}
198
199template <typename T>
200LogicalResult ProfileInfoDepot::populateProfileInfoConv(T op) {
201 addValue(op.getInput());
202 addValue(op.getWeight());
203 addValue(op.getBias());
204 addValue(op.getInputZp());
205 addValue(op.getWeightZp());
206 addType(op.getAccType());
207 addValue(op.getOutput());
208 return success();
209}
210
211template <>
212LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::Conv2DOp op) {
213 return populateProfileInfoConv(op);
214}
215
216template <>
217LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::Conv3DOp op) {
218 return populateProfileInfoConv(op);
219}
220
221template <>
222LogicalResult
223ProfileInfoDepot::populateProfileInfo(tosa::TransposeConv2DOp op) {
224 return populateProfileInfoConv(op);
225}
226
227template <>
228LogicalResult
229ProfileInfoDepot::populateProfileInfo(tosa::DepthwiseConv2DOp op) {
230 return populateProfileInfoConv(op);
231}
232
233template <>
234LogicalResult
235ProfileInfoDepot::populateProfileInfo(tosa::Conv2DBlockScaledOp op) {
236 addValue(op.getInputData());
237 addValue(op.getInputScale());
238 addValue(op.getWeightData());
239 addValue(op.getWeightScale());
240 addValue(op.getBias());
241 addValue(op.getOutput());
242 return success();
243}
244
245template <>
246LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::PadOp op) {
247 addValue(op.getInput1());
248 addValue(op.getPadConst());
249 addValue(op.getOutput());
250 return success();
251}
252
253template <typename T>
254LogicalResult ProfileInfoDepot::populateProfileInfoDataLayout(T op) {
255 addValue(op.getInput1());
256 addValue(op.getOutput());
257 return success();
258}
259
260template <>
261LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::ReshapeOp op) {
262 return populateProfileInfoDataLayout(op);
263}
264
265template <>
266LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::SliceOp op) {
267 return populateProfileInfoDataLayout(op);
268}
269
270template <>
271LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::TileOp op) {
272 return populateProfileInfoDataLayout(op);
273}
274
275template <>
276LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::TransposeOp op) {
277 return populateProfileInfoDataLayout(op);
278}
279
280template <>
281LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::GatherOp op) {
282 addValue(op.getValues());
283 addValue(op.getIndices());
284 addValue(op.getOutput());
285 return success();
286}
287
288template <>
289LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::RowGatherOp op) {
290 addValue(op.getValues());
291 addValue(op.getIndices());
292 addValue(op.getOutput());
293 return success();
294}
295
296template <>
297LogicalResult
298ProfileInfoDepot::populateProfileInfo(tosa::RowGatherBlockScaledOp op) {
299 for (Value value : op.getValues())
300 addValue(value);
301 addValue(op.getIndices());
302 addValue(op.getRowCount());
303 for (Value result : op.getOutput())
305 return success();
306}
307
308template <>
309LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::ScatterOp op) {
310 addValue(op.getValuesIn());
311 addValue(op.getIndices());
312 addValue(op.getInput());
313 addValue(op.getValuesOut());
314 return success();
315}
316
317template <>
318LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::MulOp op) {
319 addValue(op.getInput1());
320 addValue(op.getInput2());
321 addValue(op.getOutput());
322 return success();
323}
324
325template <>
326LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::ResizeOp op) {
327 addValue(op.getInput());
328 addValue(op.getOutput());
329 return success();
330}
331
332template <>
333LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::SelectOp op) {
334 addValue(op.getOnTrue());
335 addValue(op.getOnFalse());
336 addValue(op.getOutput());
337 return success();
338}
339
340template <>
341LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::RescaleOp op) {
342 addValue(op.getInput());
343 addValue(op.getInputZp());
344 addValue(op.getOutputZp());
345 addValue(op.getOutput());
346 return success();
347}
348
349template <>
350LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::MatMulOp op) {
351 addValue(op.getA());
352 addValue(op.getB());
353 addValue(op.getAZp());
354 addValue(op.getBZp());
355 addValue(op.getOutput());
356 return success();
357}
358
359template <>
360LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::MatMulTOp op) {
361 addValue(op.getA());
362 addValue(op.getB());
363 addValue(op.getAZp());
364 addValue(op.getBZp());
365 addValue(op.getOutput());
366 return success();
367}
368
369template <>
370LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::VariableOp op) {
371 addType(op.getType());
372 return success();
373}
374
375template <>
376LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::VariableWriteOp op) {
377 addValue(op.getInput1());
378 return success();
379}
380
381template <>
382LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::DimOp op) {
383 addValue(op.getInput1());
384 return success();
385}
386
387LogicalResult ProfileInfoDepot::populatationDispatch(Operation *op) {
388// This helper function only populates the info for the customised operands.
389#define POPULATE_PROFILE_INFO_CUSTOM(tosaOp) \
390 if (isa<tosa::tosaOp##Op>(op)) { \
391 return populateProfileInfo(cast<tosa::tosaOp##Op>(op)); \
392 }
393
394#define POPULATE_PROFILE_INFO_SKIP(tosaOp) \
395 if (isa<tosa::tosaOp##Op>(op)) \
396 return success();
397
398// This helper function populates the info for all operands.
399#define POPULATE_PROFILE_INFO_COMMON(tosaOp) \
400 if (isa<tosa::tosaOp##Op>(op)) { \
401 return populateProfileInfo(op->getOperands(), op->getResults()); \
402 }
403
404 // Skip irrelevant operands when they are independent and not tied to any
405 // specific profile/extension.
407 POPULATE_PROFILE_INFO_CUSTOM(AvgPool2dAdaptive)
408 POPULATE_PROFILE_INFO_CUSTOM(TransposeConv2D)
410 POPULATE_PROFILE_INFO_CUSTOM(Conv2DBlockScaled)
412 POPULATE_PROFILE_INFO_CUSTOM(DepthwiseConv2D)
422 POPULATE_PROFILE_INFO_CUSTOM(RowGatherBlockScaled)
430 POPULATE_PROFILE_INFO_CUSTOM(VariableWrite)
432 POPULATE_PROFILE_INFO_CUSTOM(MaxPool2dAdaptive)
433
434 // For the most of tosa operators, all operands are profile/extension related
435 // and hence are all considered in this profile-based compilance check.
436 POPULATE_PROFILE_INFO_COMMON(MatmulTBlockScaled)
440 POPULATE_PROFILE_INFO_COMMON(CastFromBlockScaled)
441 POPULATE_PROFILE_INFO_COMMON(CastToBlockScaled)
454 POPULATE_PROFILE_INFO_COMMON(ArithmeticRightShift)
459 POPULATE_PROFILE_INFO_COMMON(LogicalLeftShift)
460 POPULATE_PROFILE_INFO_COMMON(LogicalRightShift)
483 POPULATE_PROFILE_INFO_COMMON(ReduceProduct)
486 POPULATE_PROFILE_INFO_COMMON(GreaterEqual)
490 POPULATE_PROFILE_INFO_COMMON(VariableRead)
491
492 // Type Invariant Extension, a capability extension that is independent
493 // of the data type, meaning any compatible type can be used. No type
494 // constraint for those operations.
496 POPULATE_PROFILE_INFO_SKIP(AssertEqualShape)
497 POPULATE_PROFILE_INFO_SKIP(ConcatShape)
499 POPULATE_PROFILE_INFO_SKIP(DivCeilShape)
500 POPULATE_PROFILE_INFO_SKIP(DivFloorShape)
502 POPULATE_PROFILE_INFO_SKIP(Log2CeilShape)
503 POPULATE_PROFILE_INFO_SKIP(Log2FloorShape)
513
514 return failure();
515}
516
517//===----------------------------------------------------------------------===//
518// Tosa Profile And Extension Compliance Checker
519//===----------------------------------------------------------------------===//
520
521template <typename T>
522FailureOr<SmallVector<OpComplianceInfo<T>>>
523TosaProfileCompliance::getOperatorMatchedEntries(Operation *op) {
524 const std::string opName = op->getName().getStringRef().str();
525 const auto &complianceMap = getProfileComplianceMap<T>();
526 const auto it = complianceMap.find(opName);
527 if (it == complianceMap.end())
528 return {};
529
530 return findMatchedEntries<T>(op, it->second);
531}
532
533template <typename T>
535 Operation *op, const tosa::TargetEnv &targetEnv) {
536 const auto maybeOpEntries = getOperatorMatchedEntries<T>(op);
537 if (failed(maybeOpEntries))
538 return success();
539
540 const auto &opEntries = maybeOpEntries.value();
541 if (opEntries.size() == 0) {
542 // No matched restriction found.
543 return success();
544 }
545
546 // Check the profile/extension requirement according to the current target
547 // profiles/extensions.
548 const auto isModeAllowed = [&](const OpComplianceInfo<T> &info) -> bool {
549 if (info.condition == CheckCondition::allOf)
550 return targetEnv.allowsAllOf(info.mode);
551 return targetEnv.allowsAnyOf(info.mode);
552 };
553
554 // Check the matched op compliance version does not exceed the target
555 // specification version.
556 const TosaSpecificationVersion targetVersion{targetEnv.getSpecVersion()};
557 const auto isVersionCompatible =
558 [&targetVersion](const OpComplianceInfo<T> &info) -> bool {
559 // Assume compatible if there are no versioned type constraints
560 if (info.operandTypeInfoSet.empty())
561 return true;
562 const TosaSpecificationVersion complianceVersion{
563 info.operandTypeInfoSet.front().second};
564 return targetVersion.isBackwardsCompatibleWith(complianceVersion);
565 };
566
567 for (const auto &info : opEntries) {
568 // Type constraints exist, check if they are compatible with the current
569 // target definition, including: profile, extension and specification
570 // version
571 if (isModeAllowed(info) && isVersionCompatible(info))
572 return success();
573 }
574
575 // No valid entry was found, now emit appropriate error message and return
576 // failure
577 std::string message;
578 llvm::raw_string_ostream os(message);
579
580 os << "illegal: ";
581 const size_t numOpEntries = opEntries.size();
582 for (const auto &[index, info] : llvm::enumerate(opEntries)) {
583 bool mismatchedVersion = false;
584 if (!isVersionCompatible(info)) {
585 mismatchedVersion = true;
586 os << "requires specification version compatible with "
587 << stringifyVersion(info.operandTypeInfoSet.front().second) << " (got "
588 << stringifyVersion(targetVersion) << ") ";
589 }
590
591 if (!isModeAllowed(info)) {
592 if (mismatchedVersion)
593 os << "and ";
594 os << "requires "
595 << (info.condition == CheckCondition::allOf ? "all of " : "any of ")
596 << "[" << llvm::join(stringifyProfile<T>(info.mode), ", ")
597 << "] profiles/extensions ";
598 }
599
600 if (index != numOpEntries - 1)
601 os << "OR ";
602 }
603 os << "to be specified in the target environment";
604
605 return op->emitOpError(message);
606}
607
608LogicalResult
610 const tosa::TargetEnv &targetEnv) {
611 return checkProfileOrExtension<Profile>(op, targetEnv);
612}
613
614LogicalResult
619
621 const auto maybeProfEntries = getOperatorMatchedEntries<Profile>(op);
622 const auto maybeExtEntries = getOperatorMatchedEntries<Extension>(op);
623 if (failed(maybeProfEntries) && failed(maybeExtEntries))
624 return success();
625
626 const bool hasEntry =
627 (succeeded(maybeProfEntries) && !maybeProfEntries.value().empty()) ||
628 (succeeded(maybeExtEntries) && !maybeExtEntries.value().empty());
629
630 if (!hasEntry) {
631 std::string message;
632 llvm::raw_string_ostream os(message);
633 os << "illegal: operation operand/result data types did not align with any "
634 "profile or extension, got (";
635
636 ProfileInfoDepot depot(op);
637 const ArrayRef<TypeInfo> current = depot.getInfo();
638 for (const auto &typeInfo : llvm::drop_end(current))
639 os << stringifyTypeInfo(typeInfo) << ",";
640 os << stringifyTypeInfo(current.back()) << ")";
641
642 // avoid polluting the error message output by outputting only
643 // the best match
644 const std::string opName = op->getName().getStringRef().str();
645 int maxMatches = -1;
646 ArrayRef<TypeInfo> bestTypeInfo;
647 const auto searchBestMatch = [&](const auto &map) {
648 const auto it = map.find(opName);
649 if (it == map.end())
650 return;
651 for (const auto &complianceInfos : it->second) {
652 for (const auto &versionedTypeInfos :
653 complianceInfos.operandTypeInfoSet) {
654 const ArrayRef<TypeInfo> typeInfos = versionedTypeInfos.first;
655 if (current.size() != typeInfos.size())
656 continue;
657 const int matches = llvm::count_if(
658 llvm::zip_equal(current, typeInfos), [&](const auto zipType) {
659 return isSameTypeInfo(std::get<0>(zipType),
660 std::get<1>(zipType));
661 });
662 if (matches > maxMatches) {
663 maxMatches = matches;
664 bestTypeInfo = typeInfos;
665 }
666 }
667 }
668 };
669 searchBestMatch(getProfileComplianceMap<Profile>());
670 searchBestMatch(getProfileComplianceMap<Extension>());
671
672 os << ", did you mean (";
673 for (const auto &typeInfo : llvm::drop_end(bestTypeInfo))
674 os << stringifyTypeInfo(typeInfo) << ",";
675 os << stringifyTypeInfo(bestTypeInfo.back()) << ")? ";
676 os << "Otherwise, please refer to the 'supported data types' for '"
677 << opName << "' in the specification.";
678 op->emitOpError(message);
679 return failure();
680 }
681
682 return success();
683}
684
685// Find the profiles or extensions requirement according to the signature of
686// type of the operand list.
687template <typename T>
689 Operation *op, ArrayRef<OpComplianceInfo<T>> compInfo) {
690 assert(compInfo.size() != 0 &&
691 "profile-based compliance information is empty");
692
693 // If there are no type constraints for the given operation, return the
694 // matched entries directly so required profile/extension information can
695 // be checked
697 if (llvm::all_of(compInfo, [&matchedInfos](const OpComplianceInfo<T> &info) {
698 if (info.operandTypeInfoSet.empty()) {
699 matchedInfos.push_back(info);
700 return true;
701 }
702 return false;
703 }))
704 return matchedInfos;
705
706 // Get the type information of the operator we're trying to match
707 ProfileInfoDepot depot(op);
708 ArrayRef<TypeInfo> present = depot.getInfo();
709 if (present.size() == 0)
710 return {};
711
712 // Compare 'present' against known type signatures in the compliance metadata
713 for (const auto &comp : compInfo) {
714 for (const auto &set : comp.operandTypeInfoSet) {
715 ArrayRef<TypeInfo> expected = set.first;
716 // Tensor-list operators can legitimately have multiple valid signatures
717 // with different operand/result counts, e.g. data-only and data+scale
718 // forms. Treat those as non-matches instead of asserting.
719 if (present.size() != expected.size())
720 continue;
721
722 bool isFound = true;
723 // Compare the type signature between the given operation and the
724 // compliance metadata.
725 for (size_t j = 0; j < expected.size(); j++) {
726 if (!isSameTypeInfo(present[j], expected[j])) {
727 // Verify the next mode set from the list.
728 isFound = false;
729 break;
730 }
731 }
732
733 if (isFound == true) {
734 SmallVector<VersionedTypeInfo> typeInfoSet{set};
735 matchedInfos.emplace_back(comp.mode, std::move(typeInfoSet),
736 comp.condition);
737 }
738 }
739 }
740
741 return matchedInfos;
742}
743
744// Debug utilites.
745template <typename T>
748 SmallVector<StringRef> debugStrings;
749 for (const auto &profile : profiles) {
750 if constexpr (std::is_same_v<T, Profile>)
751 debugStrings.push_back(tosa::stringifyProfile(profile));
752 else
753 debugStrings.push_back(tosa::stringifyExtension(profile));
754 }
755 return debugStrings;
756}
757
758template <typename T>
760 const SmallVector<ArrayRef<T>> &profileSet) {
761 SmallVector<StringRef> debugStrings;
762
763 for (const auto &profiles : profileSet) {
764 auto tempStrings = stringifyProfile<T>(profiles);
765 llvm::append_range(debugStrings, tempStrings);
766 }
767
768 return debugStrings;
769}
770
773 const auto stringifyScalarTypeInfo =
774 [](const TypeInfo &typeInfo) -> llvm::SmallString<32> {
775 if (typeInfo.typeID == mlir::IntegerType::getTypeID()) {
776 return {"i" + llvm::utostr(typeInfo.bitWidth)};
777 }
778 if (typeInfo.typeID == mlir::Float16Type::getTypeID()) {
779 return {"f16"};
780 } else if (typeInfo.typeID == mlir::Float32Type::getTypeID()) {
781 return {"f32"};
782 } else if (typeInfo.typeID == mlir::BFloat16Type::getTypeID()) {
783 return {"bf16"};
784 } else if (typeInfo.typeID == mlir::Float8E4M3FNType::getTypeID()) {
785 return {"fp8e4m3"};
786 } else if (typeInfo.typeID == mlir::Float8E5M2Type::getTypeID()) {
787 return {"fp8e5m2"};
788 } else if (typeInfo.typeID == mlir::Float6E2M3FNType::getTypeID()) {
789 return {"fp6e2m3"};
790 } else if (typeInfo.typeID == mlir::Float6E3M2FNType::getTypeID()) {
791 return {"fp6e3m2"};
792 } else if (typeInfo.typeID == mlir::Float4E2M1FNType::getTypeID()) {
793 return {"fp4e2m1"};
794 } else if (typeInfo.typeID == mlir::Float8E8M0FNUType::getTypeID()) {
795 return {"fp8e8m0"};
796 } else if (typeInfo.typeID == MXI8Type::getTypeID()) {
797 return {"mxint8"};
798 }
799 llvm_unreachable("unknown type");
800 };
801
802 if (typeInfo.typeID == tosa::BlockScaledType::getTypeID()) {
803 TypeInfo valueInfo = {typeInfo.valueTypeID, typeInfo.bitWidth};
804 TypeInfo scaleInfo = {typeInfo.scaleTypeID, 8};
806 llvm::raw_svector_ostream os(result);
807 os << "bs"
808 << tosa::BlockShapeAttr::getBlockShapeValue(typeInfo.blockShape.value())
809 << "_" << stringifyScalarTypeInfo(scaleInfo) << "_"
810 << stringifyScalarTypeInfo(valueInfo);
811 return result;
812 }
813
814 return stringifyScalarTypeInfo(typeInfo);
815}
816} // namespace tosa
817} // namespace mlir
for(Operation *op :ops)
return success()
#define POPULATE_PROFILE_INFO_CUSTOM(tosaOp)
#define POPULATE_PROFILE_INFO_COMMON(tosaOp)
#define POPULATE_PROFILE_INFO_SKIP(tosaOp)
@ Gather
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
This class provides an efficient unique identifier for a specific C++ type.
Definition TypeID.h:107
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:392
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
ArrayRef< TypeInfo > getInfo() const
This class represents the capability enabled in the target implementation such as profile,...
Definition TargetEnv.h:119
bool allowsAllOf(ArrayRef< Profile > profs) const
Definition TargetEnv.h:145
bool allowsAnyOf(ArrayRef< Profile > profs) const
Definition TargetEnv.h:141
TosaSpecificationVersion getSpecVersion() const
Definition TargetEnv.h:132
static llvm::SmallString< 32 > stringifyTypeInfo(const TypeInfo &typeInfo)
LogicalResult checkExtension(Operation *op, const tosa::TargetEnv &targetEnv)
LogicalResult checkInvalid(Operation *op)
SmallVector< OpComplianceInfo< T > > findMatchedEntries(Operation *op, ArrayRef< OpComplianceInfo< T > > compInfo)
LogicalResult checkProfileOrExtension(Operation *op, const tosa::TargetEnv &targetEnv)
LogicalResult checkProfile(Operation *op, const tosa::TargetEnv &targetEnv)
const std::unordered_map< std::string, SmallVector< OpComplianceInfo< T > > > & getProfileComplianceMap() const
SmallVector< StringRef > stringifyProfile(ArrayRef< T > profiles)
bool isSameTypeInfo(const TypeInfo &a, const TypeInfo &b)
A thin wrapper around the SpecificationVersion enum to represent and provide utilities around the TOS...
Definition TargetEnv.h:60
bool isBackwardsCompatibleWith(TosaSpecificationVersion baseVersion) const
Definition TargetEnv.h:69
llvm::SmallString< 4 > stringifyVersion(TosaSpecificationVersion version)
Definition TargetEnv.cpp:25
std::unordered_map< std::string, SmallVector< OpComplianceInfo< Extension > > > OperationExtensionComplianceMap
std::unordered_map< std::string, SmallVector< OpComplianceInfo< Profile > > > OperationProfileComplianceMap
Include the generated interface declarations.
@ Mul
RHS of mul is always a constant or a symbolic expression.
Definition AffineExpr.h:43
SmallVector< VersionedTypeInfo > operandTypeInfoSet
OpComplianceInfo & operator=(const OpComplianceInfo &other)
std::optional< tosa::BlockShape > blockShape
VersionedTypeInfo & operator=(const VersionedTypeInfo &other)
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.