[Mlir-commits] [mlir] [mlir][ArmSVE] Implement `ConvertToLLVMPatternInterface` (PR #236760)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Oct 29 06:07:11 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-sve
Author: Markus Böck (zero9178)
<details>
<summary>Changes</summary>
ArmSVE could only be lowered to LLVM through
`convert-vector-to-llvm{enable-arm-sve}`. This PR implements the `ConvertToLLVMPatternInterface` for the ArmSVE dialect so that `convert-to-llvm` lowers ArmSVE operations as well.
Since there are `arm_sve` dialect lowering patterns (`vector.create_mask`) that lower from vector dialect, an `add-lowering` pass option was also added to `convert-to-llvm` that allows loading a dialect and its conversion patterns, even if the dialect is not part of the input.
Part of a greater work in trying to make the VectorToLLVM pass not require linking every target dialect it can lower to.
---
Full diff: https://github.com/llvm/llvm-project/pull/236760.diff
9 Files Affected:
- (modified) mlir/docs/ReleaseNotes.md (+12)
- (modified) mlir/include/mlir/Conversion/Passes.td (+7)
- (modified) mlir/include/mlir/Dialect/ArmSVE/Transforms/Transforms.h (+5-3)
- (modified) mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp (+46-21)
- (modified) mlir/lib/Dialect/ArmSVE/Transforms/CMakeLists.txt (+1)
- (modified) mlir/lib/Dialect/ArmSVE/Transforms/LegalizeForLLVMExport.cpp (+62-27)
- (modified) mlir/lib/RegisterAllExtensions.cpp (+2)
- (added) mlir/test/Conversion/ConvertToLLVM/add-lowering.mlir (+15)
- (modified) mlir/test/Dialect/ArmSVE/legalize-for-llvm.mlir (+1-1)
``````````diff
diff --git a/mlir/docs/ReleaseNotes.md b/mlir/docs/ReleaseNotes.md
index f57642308f4528..b21ca22124aad5 100644
--- a/mlir/docs/ReleaseNotes.md
+++ b/mlir/docs/ReleaseNotes.md
@@ -73,6 +73,18 @@ Each header provides its own registration function (for example
to match, e.g. `mlirCreateGPUGpuNVVMAttachTarget` is now
`mlirCreateGPUNVVMGpuNVVMAttachTarget`.
+### ArmSVE Lowering via `convert-to-llvm`
+
+The ArmSVE dialect now implements `ConvertToLLVMPatternInterface`; register it
+with `registerConvertArmSVEToLLVMInterface()`. `convert-to-llvm` therefore
+lowers ArmSVE operations, and, when the ArmSVE dialect is loaded, lowers
+predicate-sized 1-D scalable `vector.create_mask` ops to
+`arm_sve.intr.whilelt`. The new `convert-to-llvm{add-lowering=...}` option
+loads the listed dialects and uses their conversion patterns regardless of the
+input (and of `filter-dialects`), so `add-lowering=arm_sve` enables this
+lowering for inputs without ArmSVE ops. `configureArmSVELegalizeForExportTarget`
+now takes a `ConversionTarget`.
+
## LLVM 21
### GPU/NVVM Changes
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 14f2158b312968..42059e05b722f7 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -47,11 +47,18 @@ def ConvertToLLVMPass : Pass<"convert-to-llvm"> {
the conversion process. This option also uses the `DataLayoutAnalysis`
analysis to configure the type converter. Enabling this option incurs in
extra overhead.
+
+ The dialects listed in `add-lowering` are loaded before the conversion, so
+ that their `ConvertToLLVMPatternInterface` patterns are used even if the
+ input contains no operation of them. They must implement the interface. If
+ `filter-dialects` is set, the `add-lowering` dialects are added to it.
}];
let options = [
ListOption<"filterDialects", "filter-dialects", "std::string",
"Test conversion patterns of only the specified dialects">,
+ ListOption<"addLowering", "add-lowering", "std::string",
+ "Load the specified dialects and use their conversion patterns">,
Option<"useDynamic", "dynamic", "bool", "false",
"Use op conversion attributes to configure the conversion">,
Option<"allowPatternRollback", "allow-pattern-rollback", "bool", "true",
diff --git a/mlir/include/mlir/Dialect/ArmSVE/Transforms/Transforms.h b/mlir/include/mlir/Dialect/ArmSVE/Transforms/Transforms.h
index 26f5199b5f4d59..874aa84758e546 100644
--- a/mlir/include/mlir/Dialect/ArmSVE/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/ArmSVE/Transforms/Transforms.h
@@ -10,8 +10,8 @@
#define MLIR_DIALECT_ARMSVE_TRANSFORMS_H
namespace mlir {
-
-class LLVMConversionTarget;
+class ConversionTarget;
+class DialectRegistry;
class LLVMTypeConverter;
class RewritePatternSet;
@@ -27,8 +27,10 @@ void populateArmSVELegalizeForLLVMExportPatterns(
/// Configure the target to support lowering ArmSVE ops to ops that map to LLVM
/// intrinsics.
-void configureArmSVELegalizeForExportTarget(LLVMConversionTarget &target);
+void configureArmSVELegalizeForExportTarget(ConversionTarget &target);
+/// Register the LLVM conversion interface for the ArmSVE dialect.
+void registerConvertArmSVEToLLVMInterface(DialectRegistry ®istry);
} // namespace mlir
#endif // MLIR_DIALECT_ARMSVE_TRANSFORMS_H
diff --git a/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp b/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
index 92fbb9fa591763..08b60572c0c882 100644
--- a/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
+++ b/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
@@ -14,6 +14,7 @@
#include "mlir/IR/PatternMatch.h"
#include "mlir/Rewrite/FrozenRewritePatternSet.h"
#include "mlir/Transforms/DialectConversion.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Support/DebugLog.h"
#include <memory>
@@ -33,6 +34,7 @@ class ConvertToLLVMPassInterface {
public:
ConvertToLLVMPassInterface(MLIRContext *context,
ArrayRef<std::string> filterDialects,
+ ArrayRef<std::string> addLowering,
bool allowPatternRollback = true);
virtual ~ConvertToLLVMPassInterface() = default;
@@ -56,12 +58,15 @@ class ConvertToLLVMPassInterface {
/// Visit the `ConvertToLLVMPatternInterface` dialect interfaces and call
/// `visitor` with each of the interfaces. If `filterDialects` is non-empty,
/// then `visitor` is invoked only with the dialects in the `filterDialects`
- /// list.
+ /// and `addLowering` lists. Fails if a dialect in `addLowering` does not
+ /// implement the interface.
LogicalResult visitInterfaces(
llvm::function_ref<void(ConvertToLLVMPatternInterface *)> visitor);
MLIRContext *context;
/// List of dialects names to use as filters.
ArrayRef<std::string> filterDialects;
+ /// List of dialect names whose patterns are always used.
+ ArrayRef<std::string> addLowering;
/// An experimental flag to disallow pattern rollback. This is more efficient
/// but not supported by all lowering patterns.
bool allowPatternRollback;
@@ -209,17 +214,21 @@ class ConvertToLLVMPass
using impl::ConvertToLLVMPassBase<ConvertToLLVMPass>::ConvertToLLVMPassBase;
void getDependentDialects(DialectRegistry ®istry) const final {
ConvertToLLVMPassInterface::getDependentDialects(registry);
+ // The allocators of the dialects named via `add-lowering` are resolved
+ // from the MLIRContext's own registry when the pass manager loads them.
+ for (const std::string &name : addLowering)
+ registry.addDialectToPreload(name);
}
LogicalResult initialize(MLIRContext *context) final {
std::shared_ptr<ConvertToLLVMPassInterface> impl;
// Choose the pass implementation.
if (useDynamic)
- impl = std::make_shared<DynamicConvertToLLVM>(context, filterDialects,
- allowPatternRollback);
+ impl = std::make_shared<DynamicConvertToLLVM>(
+ context, filterDialects, addLowering, allowPatternRollback);
else
- impl = std::make_shared<StaticConvertToLLVM>(context, filterDialects,
- allowPatternRollback);
+ impl = std::make_shared<StaticConvertToLLVM>(
+ context, filterDialects, addLowering, allowPatternRollback);
if (failed(impl->initialize()))
return failure();
this->impl = impl;
@@ -240,9 +249,9 @@ class ConvertToLLVMPass
ConvertToLLVMPassInterface::ConvertToLLVMPassInterface(
MLIRContext *context, ArrayRef<std::string> filterDialects,
- bool allowPatternRollback)
+ ArrayRef<std::string> addLowering, bool allowPatternRollback)
: context(context), filterDialects(filterDialects),
- allowPatternRollback(allowPatternRollback) {}
+ addLowering(addLowering), allowPatternRollback(allowPatternRollback) {}
void ConvertToLLVMPassInterface::getDependentDialects(
DialectRegistry ®istry) {
@@ -252,23 +261,39 @@ void ConvertToLLVMPassInterface::getDependentDialects(
LogicalResult ConvertToLLVMPassInterface::visitInterfaces(
llvm::function_ref<void(ConvertToLLVMPatternInterface *)> visitor) {
+ // Produce an error if the dialect is not loaded or does not implement the
+ // interface.
+ auto getInterface =
+ [&](StringRef dialectName) -> FailureOr<ConvertToLLVMPatternInterface *> {
+ Dialect *dialect = context->getLoadedDialect(dialectName);
+ if (!dialect)
+ return emitError(UnknownLoc::get(context))
+ << "dialect not loaded: " << dialectName << "\n";
+ auto *iface = dyn_cast<ConvertToLLVMPatternInterface>(dialect);
+ if (!iface)
+ return emitError(UnknownLoc::get(context))
+ << "dialect does not implement ConvertToLLVMPatternInterface: "
+ << dialectName << "\n";
+ return iface;
+ };
+
if (!filterDialects.empty()) {
- // Test mode: Populate only patterns from the specified dialects. Produce
- // an error if the dialect is not loaded or does not implement the
- // interface.
- for (StringRef dialectName : filterDialects) {
- Dialect *dialect = context->getLoadedDialect(dialectName);
- if (!dialect)
- return emitError(UnknownLoc::get(context))
- << "dialect not loaded: " << dialectName << "\n";
- auto *iface = dyn_cast<ConvertToLLVMPatternInterface>(dialect);
- if (!iface)
- return emitError(UnknownLoc::get(context))
- << "dialect does not implement ConvertToLLVMPatternInterface: "
- << dialectName << "\n";
- visitor(iface);
+ // Test mode: Populate only patterns from the specified dialects, including
+ // the ones of `addLowering`.
+ llvm::SetVector<StringRef> dialectNames;
+ dialectNames.insert_range(filterDialects);
+ dialectNames.insert_range(addLowering);
+ for (StringRef dialectName : dialectNames) {
+ FailureOr<ConvertToLLVMPatternInterface *> iface =
+ getInterface(dialectName);
+ if (failed(iface))
+ return failure();
+ visitor(*iface);
}
} else {
+ for (StringRef dialectName : addLowering)
+ if (failed(getInterface(dialectName)))
+ return failure();
// Normal mode: Populate all patterns from all dialects that implement the
// interface.
// First time we encounter this dialect: if it implements the interface,
diff --git a/mlir/lib/Dialect/ArmSVE/Transforms/CMakeLists.txt b/mlir/lib/Dialect/ArmSVE/Transforms/CMakeLists.txt
index c29eaca244b4af..fc03226bd09a05 100644
--- a/mlir/lib/Dialect/ArmSVE/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/ArmSVE/Transforms/CMakeLists.txt
@@ -9,6 +9,7 @@ add_mlir_dialect_library(MLIRArmSVETransforms
LINK_LIBS PUBLIC
MLIRArmSVEDialect
+ MLIRConvertToLLVMInterface
MLIRFuncDialect
MLIRVectorDialect
MLIRIR
diff --git a/mlir/lib/Dialect/ArmSVE/Transforms/LegalizeForLLVMExport.cpp b/mlir/lib/Dialect/ArmSVE/Transforms/LegalizeForLLVMExport.cpp
index 6f2e0a0889b403..0418b7b610b407 100644
--- a/mlir/lib/Dialect/ArmSVE/Transforms/LegalizeForLLVMExport.cpp
+++ b/mlir/lib/Dialect/ArmSVE/Transforms/LegalizeForLLVMExport.cpp
@@ -6,9 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"
-#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/ArmSVE/IR/ArmSVEDialect.h"
#include "mlir/Dialect/ArmSVE/Transforms/Transforms.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
@@ -55,7 +55,6 @@ using ScalableMaskedDivFOpLowering =
ScalableMaskedDivFIntrOp>;
namespace {
-
/// Unrolls a conversion to/from equivalent vector types, to allow using a
/// conversion intrinsic that only supports 1-D vector types.
///
@@ -65,31 +64,42 @@ namespace {
/// ```
/// is rewritten into:
/// ```
-/// %cst = arith.constant dense<false> : vector<2x[16]xi1>
-/// %1 = vector.extract %source[0] : vector<[4]xi1> from vector<2x[4]xi1>
+/// %cst = llvm.mlir.constant(dense<false> : vector<2x[16]xi1>)
+/// : !llvm.array<2 x vector<[16]xi1>>
+/// %1 = llvm.extractvalue %source[0] : !llvm.array<2 x vector<[4]xi1>>
/// %2 = "arm_sve.intr.convert.to.svbool"(%1)
/// : (vector<[4]xi1>) -> vector<[16]xi1>
-/// %3 = vector.insert %2, %cst[0] : vector<[16]xi1> into vector<2x[16]xi1>
-/// %4 = vector.extract %source[1] : vector<[4]xi1> from vector<2x[4]xi1>
+/// %3 = llvm.insertvalue %2, %cst[0] : !llvm.array<2 x vector<[16]xi1>>
+/// %4 = llvm.extractvalue %source[1] : !llvm.array<2 x vector<[4]xi1>>
/// %5 = "arm_sve.intr.convert.to.svbool"(%4)
/// : (vector<[4]xi1>) -> vector<[16]xi1>
-/// %result = vector.insert %5, %3[1] : vector<[16]xi1> into vector<2x[16]xi1>
+/// %result = llvm.insertvalue %5, %3[1] : !llvm.array<2 x vector<[16]xi1>>
/// ```
template <typename Op, typename IntrOp>
struct SvboolConversionOpLowering : public ConvertOpToLLVMPattern<Op> {
using ConvertOpToLLVMPattern<Op>::ConvertOpToLLVMPattern;
LogicalResult
- matchAndRewrite(Op convertOp, typename Op::Adaptor,
+ matchAndRewrite(Op convertOp, typename Op::Adaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
auto loc = convertOp.getLoc();
- auto source = convertOp.getSource();
- VectorType sourceType = source.getType();
+ VectorType sourceType = convertOp.getSource().getType();
VectorType resultType = convertOp.getResult().getType();
+ auto convertedType =
+ VectorType::get(resultType.getShape().back(),
+ resultType.getElementType(), /*scalableDims=*/true);
+ if (sourceType.getRank() == 1) {
+ rewriter.replaceOpWithNewOp<IntrOp>(convertOp, convertedType,
+ adaptor.getSource());
+ return success();
+ }
- Value result = arith::ConstantOp::create(rewriter, loc, resultType,
- rewriter.getZeroAttr(resultType));
+ Type llvmResultType = this->getTypeConverter()->convertType(resultType);
+ if (!llvmResultType)
+ return failure();
+ Value result = LLVM::ConstantOp::create(rewriter, loc, llvmResultType,
+ rewriter.getZeroAttr(resultType));
// We want to iterate over the input vector in steps of the trailing
// dimension. So this creates tile shape where all leading dimensions are 1,
@@ -100,16 +110,13 @@ struct SvboolConversionOpLowering : public ConvertOpToLLVMPattern<Op> {
// Iterate over all scalable mask/predicate slices of the source vector.
for (SmallVector<int64_t> index :
StaticTileOffsetRange(sourceType.getShape(), tileShape)) {
- auto extractOrInsertPosition = ArrayRef(index).drop_back();
- auto sourceVector = vector::ExtractOp::create(rewriter, loc, source,
- extractOrInsertPosition);
- VectorType convertedType =
- VectorType::Builder(llvm::cast<VectorType>(sourceVector.getType()))
- .setDim(0, resultType.getShape().back());
- auto convertedVector =
+ auto position = ArrayRef(index).drop_back();
+ Value sourceVector = LLVM::ExtractValueOp::create(
+ rewriter, loc, adaptor.getSource(), position);
+ Value convertedVector =
IntrOp::create(rewriter, loc, TypeRange{convertedType}, sourceVector);
- result = vector::InsertOp::create(rewriter, loc, convertedVector, result,
- extractOrInsertPosition);
+ result = LLVM::InsertValueOp::create(rewriter, loc, result,
+ convertedVector, position);
}
rewriter.replaceOp(convertOp, result);
@@ -138,10 +145,15 @@ struct PselOpLowering : public ConvertOpToLLVMPattern<PselOp> {
auto loc = pselOp.getLoc();
auto svboolP1 = ConvertToSvboolIntrOp::create(rewriter, loc, svboolType,
adaptor.getP1());
- auto indexI32 = arith::IndexCastOp::create(
- rewriter, loc, rewriter.getI32Type(), pselOp.getIndex());
+ Value index = adaptor.getIndex();
+ unsigned indexWidth = cast<IntegerType>(index.getType()).getWidth();
+ Type i32Type = rewriter.getI32Type();
+ if (indexWidth > 32)
+ index = LLVM::TruncOp::create(rewriter, loc, i32Type, index);
+ else if (indexWidth < 32)
+ index = LLVM::SExtOp::create(rewriter, loc, i32Type, index);
auto pselIntr = PselIntrOp::create(rewriter, loc, svboolType, svboolP1,
- pselOp.getP2(), indexI32);
+ adaptor.getP2(), index);
rewriter.replaceOpWithNewOp<ConvertFromSvboolIntrOp>(
pselOp, adaptor.getP1().getType(), pselIntr);
return success();
@@ -181,7 +193,6 @@ struct CreateMaskOpLowering
return success();
}
};
-
} // namespace
/// Populate the given list with patterns that convert from ArmSVE to LLVM.
@@ -216,8 +227,7 @@ void mlir::populateArmSVELegalizeForLLVMExportPatterns(
// clang-format on
}
-void mlir::configureArmSVELegalizeForExportTarget(
- LLVMConversionTarget &target) {
+void mlir::configureArmSVELegalizeForExportTarget(ConversionTarget &target) {
// clang-format off
target.addLegalOp<BfmmlaOp,
ConvertFromSvboolIntrOp,
@@ -263,3 +273,28 @@ void mlir::configureArmSVELegalizeForExportTarget(
SdotOp>();
// clang-format on
}
+
+namespace {
+/// Implement the interface to convert ArmSVE to LLVM.
+struct ArmSVEToLLVMDialectInterface : ConvertToLLVMPatternInterface {
+ explicit ArmSVEToLLVMDialectInterface(Dialect *dialect)
+ : ConvertToLLVMPatternInterface(dialect) {}
+
+ void loadDependentDialects(MLIRContext *context) const final {
+ context->loadDialect<LLVM::LLVMDialect>();
+ }
+
+ void populateConvertToLLVMConversionPatterns(
+ ConversionTarget &target, LLVMTypeConverter &typeConverter,
+ RewritePatternSet &patterns) const final {
+ configureArmSVELegalizeForExportTarget(target);
+ populateArmSVELegalizeForLLVMExportPatterns(typeConverter, patterns);
+ }
+};
+} // namespace
+
+void mlir::registerConvertArmSVEToLLVMInterface(DialectRegistry ®istry) {
+ registry.addExtension(+[](MLIRContext *ctx, ArmSVEDialect *dialect) {
+ dialect->addInterfaces<ArmSVEToLLVMDialectInterface>();
+ });
+}
diff --git a/mlir/lib/RegisterAllExtensions.cpp b/mlir/lib/RegisterAllExtensions.cpp
index ff7810c8c6430a..d39e21666da471 100644
--- a/mlir/lib/RegisterAllExtensions.cpp
+++ b/mlir/lib/RegisterAllExtensions.cpp
@@ -36,6 +36,7 @@
#include "mlir/Dialect/Affine/TransformOps/AffineTransformOps.h"
#include "mlir/Dialect/ArmNeon/TransformOps/ArmNeonVectorTransformOps.h"
#include "mlir/Dialect/ArmSVE/TransformOps/ArmSVEVectorTransformOps.h"
+#include "mlir/Dialect/ArmSVE/Transforms/Transforms.h"
#include "mlir/Dialect/Bufferization/Extensions/AllExtensions.h"
#include "mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h"
#include "mlir/Dialect/DLTI/TransformOps/DLTITransformOps.h"
@@ -98,6 +99,7 @@ void mlir::registerAllExtensions(DialectRegistry ®istry) {
gpu::registerConvertGpuToLLVMInterface(registry);
NVVM::registerConvertGpuToNVVMInterface(registry);
vector::registerConvertVectorToLLVMInterface(registry);
+ registerConvertArmSVEToLLVMInterface(registry);
registerConvertX86ToLLVMInterface(registry);
// Register all transform dialect extensions.
diff --git a/mlir/test/Conversion/ConvertToLLVM/add-lowering.mlir b/mlir/test/Conversion/ConvertToLLVM/add-lowering.mlir
new file mode 100644
index 00000000000000..13d99d30a3bd15
--- /dev/null
+++ b/mlir/test/Conversion/ConvertToLLVM/add-lowering.mlir
@@ -0,0 +1,15 @@
+// RUN: mlir-opt %s -convert-to-llvm="filter-dialects=func add-lowering=arm_sve" | FileCheck %s
+// RUN: not mlir-opt %s -convert-to-llvm="add-lowering=tensor" 2>&1 | FileCheck %s --check-prefix=NO-IFACE
+
+// The dialects of `add-lowering` are loaded even if the input contains no
+// operation of them, and their patterns extend `filter-dialects`.
+
+// CHECK-LABEL: llvm.func @create_mask(
+// CHECK: "arm_sve.intr.whilelt"
+// CHECK-NOT: vector.create_mask
+
+// NO-IFACE: error: dialect does not implement ConvertToLLVMPatternInterface: tensor
+func.func @create_mask(%index: index) -> vector<[4]xi1> {
+ %0 = vector.create_mask %index : vector<[4]xi1>
+ return %0 : vector<[4]xi1>
+}
diff --git a/mlir/test/Dialect/ArmSVE/legalize-for-llvm.mlir b/mlir/test/Dialect/ArmSVE/legalize-for-llvm.mlir
index 8c658db009adf3..f6ab0983cc0575 100644
--- a/mlir/test/Dialect/ArmSVE/legalize-for-llvm.mlir
+++ b/mlir/test/Dialect/ArmSVE/legalize-for-llvm.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt -convert-vector-to-llvm="enable-arm-sve" -convert-func-to-llvm -convert-arith-to-llvm -cse -reconcile-unrealized-casts -split-input-file %s | FileCheck %s
+// RUN: mlir-opt -convert-to-llvm="add-lowering=arm_sve" -cse -reconcile-unrealized-casts -split-input-file %s | FileCheck %s
func.func @arm_sve_sdot(%a: vector<[16]xi8>,
%b: vector<[16]xi8>,
``````````
</details>
https://github.com/llvm/llvm-project/pull/236760
More information about the Mlir-commits
mailing list