Skip to content

[mlir][vector] Allow integer indices in vector.extract/insert ops #115808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions mlir/include/mlir/Dialect/Vector/IR/VectorOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -695,14 +695,14 @@ def Vector_ExtractOp :
%1 = vector.extract %0[3]: vector<8x16xf32> from vector<4x8x16xf32>
%2 = vector.extract %0[2, 1, 3]: f32 from vector<4x8x16xf32>
%3 = vector.extract %1[]: vector<f32> from vector<f32>
%4 = vector.extract %0[%a, %b, %c]: f32 from vector<4x8x16xf32>
%5 = vector.extract %0[2, %b]: vector<16xf32> from vector<4x8x16xf32>
%4 = vector.extract %0[%a, %b, %c : index] : f32 from vector<4x8x16xf32>
%5 = vector.extract %0[2, %b : index] : vector<16xf32> from vector<4x8x16xf32>
```
}];

let arguments = (ins
AnyVectorOfAnyRank:$vector,
Variadic<Index>:$dynamic_position,
Variadic<AnySignlessIntegerOrIndex>:$dynamic_position,
DenseI64ArrayAttr:$static_position
);
let results = (outs AnyType:$result);
Expand Down Expand Up @@ -737,7 +737,8 @@ def Vector_ExtractOp :

let assemblyFormat = [{
$vector ``
custom<DynamicIndexList>($dynamic_position, $static_position)
custom<SameTypeDynamicIndexList>($dynamic_position, $static_position,
type($dynamic_position))
attr-dict `:` type($result) `from` type($vector)
}];

Expand Down Expand Up @@ -883,15 +884,15 @@ def Vector_InsertOp :
%2 = vector.insert %0, %1[3] : vector<8x16xf32> into vector<4x8x16xf32>
%5 = vector.insert %3, %4[2, 1, 3] : f32 into vector<4x8x16xf32>
%8 = vector.insert %6, %7[] : f32 into vector<f32>
%11 = vector.insert %9, %10[%a, %b, %c] : vector<f32> into vector<4x8x16xf32>
%12 = vector.insert %4, %10[2, %b] : vector<16xf32> into vector<4x8x16xf32>
%11 = vector.insert %9, %10[%a, %b, %c : index] : vector<f32> into vector<4x8x16xf32>
%12 = vector.insert %4, %10[2, %b : index] : vector<16xf32> into vector<4x8x16xf32>
```
}];

let arguments = (ins
AnyType:$source,
AnyVectorOfAnyRank:$dest,
Variadic<Index>:$dynamic_position,
Variadic<AnySignlessIntegerOrIndex>:$dynamic_position,
DenseI64ArrayAttr:$static_position
);
let results = (outs AnyVectorOfAnyRank:$result);
Expand Down Expand Up @@ -926,7 +927,9 @@ def Vector_InsertOp :
}];

let assemblyFormat = [{
$source `,` $dest custom<DynamicIndexList>($dynamic_position, $static_position)
$source `,` $dest
custom<SameTypeDynamicIndexList>($dynamic_position, $static_position,
type($dynamic_position))
attr-dict `:` type($source) `into` type($dest)
}];

Expand Down Expand Up @@ -1344,7 +1347,7 @@ def Vector_TransferReadOp :
%a = load %A[%expr1 + %k, %expr2, %expr3 + %i, %expr4] : memref<?x?x?x?xf32>
// Update the temporary gathered slice with the individual element
%slice = memref.load %tmp : memref<vector<3x4x5xf32>> -> vector<3x4x5xf32>
%updated = vector.insert %a, %slice[%i, %j, %k] : f32 into vector<3x4x5xf32>
%updated = vector.insert %a, %slice[%i, %j, %k : index] : f32 into vector<3x4x5xf32>
memref.store %updated, %tmp : memref<vector<3x4x5xf32>>
}}}
// At this point we gathered the elements from the original
Expand All @@ -1367,7 +1370,7 @@ def Vector_TransferReadOp :
%a = load %A[%expr1 + %k, %expr2, %expr3 + %i, %expr4] : memref<?x?x?x?xf32>
%slice = memref.load %tmp : memref<vector<3x4x5xf32>> -> vector<3x4x5xf32>
// Here we only store to the first element in dimension one
%updated = vector.insert %a, %slice[%i, 0, %k] : f32 into vector<3x4x5xf32>
%updated = vector.insert %a, %slice[%i, 0, %k : index] : f32 into vector<3x4x5xf32>
memref.store %updated, %tmp : memref<vector<3x4x5xf32>>
}}
// At this point we gathered the elements from the original
Expand Down
21 changes: 17 additions & 4 deletions mlir/include/mlir/IR/OpImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,16 +794,26 @@ class AsmParser {
};

/// Parse a list of comma-separated items with an optional delimiter. If a
/// delimiter is provided, then an empty list is allowed. If not, then at
/// delimiter is provided, then an empty list is allowed. If not, then at
/// least one element will be parsed.
///
/// `parseSuffixFn` is an optional function to parse any suffix that can be
/// appended to the comma separated list within the delimiter.
///
/// contextMessage is an optional message appended to "expected '('" sorts of
/// diagnostics when parsing the delimeters.
virtual ParseResult
virtual ParseResult parseCommaSeparatedList(
Delimiter delimiter, function_ref<ParseResult()> parseElementFn,
std::optional<function_ref<ParseResult()>> parseSuffixFn = std::nullopt,
StringRef contextMessage = StringRef()) = 0;
ParseResult
parseCommaSeparatedList(Delimiter delimiter,
function_ref<ParseResult()> parseElementFn,
StringRef contextMessage = StringRef()) = 0;

StringRef contextMessage) {
return parseCommaSeparatedList(delimiter, parseElementFn,
/*parseSuffixFn=*/std::nullopt,
contextMessage);
}
/// Parse a comma separated list of elements that must have at least one entry
/// in it.
ParseResult
Expand Down Expand Up @@ -1319,6 +1329,9 @@ class AsmParser {
virtual ParseResult
parseOptionalColonTypeList(SmallVectorImpl<Type> &result) = 0;

/// Parse an optional colon followed by a type.
virtual ParseResult parseOptionalColonType(Type &result) = 0;

/// Parse a keyword followed by a type.
ParseResult parseKeywordType(const char *keyword, Type &result) {
return failure(parseKeyword(keyword) || parseType(result));
Expand Down
29 changes: 25 additions & 4 deletions mlir/include/mlir/Interfaces/ViewLikeInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ class OpWithOffsetSizesAndStridesConstantArgumentFolder final
/// in `integers` is `kDynamic` or (2) the next value otherwise. If `valueTypes`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The grammar in this sentence is broken: is kDynamic. Can you fix that also?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this function have valueTypes parameter? The type can be taken from the SSA values in values. Is it possible to remove valueTypes? I think a bool printTypes should be sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valueTypes is needed for integers. We are representing integers with int64_t but their actual type comes from valueTypes. Perhaps we should rename this to itemTypes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

values can also be empty

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, the types are not used for integers (!). I think valueTypes is needed to match the function signature expected by custom($values, $integers, type($values)). We could verify that both $values and $type($values) match and then use just one of them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this a bit. I think valueTypes in needed in the parser, so that the user-specified types can be checked against the actual types in resolveOperands. printDynamicIndexList just has it for consistency.

/// is non-empty, it is expected to contain as many elements as `values`
/// indicating their types. This allows idiomatic printing of mixed value and
/// integer attributes in a list. E.g.
/// `[%arg0 : index, 7, 42, %arg42 : i32]`.
/// integer attributes in a list. E.g., `[%arg0 : index, 7, 42, %arg42 : i32]`.
/// If `hasSameTypeDynamicValues` is `true`, `valueTypes` are expected to be the
/// same and only one type is printed at the end of the list. E.g.,
/// `[0, %arg2, 3, %arg42, 2 : i8]`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify that the number of types in valueTypes must match the number of dynamic elements, even if hasSameTypeDynamicValues is set.

Btw, have you considered changing the API such that valueTypes contains only a single value in case of hasSameTypeDynamicValues? That would seem more natural to me.

///
/// Indices can be scalable. For example, "4" in "[2, [4], 8]" is scalable.
/// This notation is similar to how scalable dims are marked when defining
Expand All @@ -108,7 +110,8 @@ void printDynamicIndexList(
OpAsmPrinter &printer, Operation *op, OperandRange values,
ArrayRef<int64_t> integers, ArrayRef<bool> scalables,
TypeRange valueTypes = TypeRange(),
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square);
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square,
bool hasSameTypeDynamicValues = false);
inline void printDynamicIndexList(OpAsmPrinter &printer, Operation *op,
OperandRange values,
ArrayRef<int64_t> integers,
Expand All @@ -123,6 +126,13 @@ inline void printDynamicIndexList(
return printDynamicIndexList(printer, op, values, integers, {}, valueTypes,
delimiter);
}
inline void printSameTypeDynamicIndexList(
OpAsmPrinter &printer, Operation *op, OperandRange values,
ArrayRef<int64_t> integers, TypeRange valueTypes = TypeRange(),
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square) {
return printDynamicIndexList(printer, op, values, integers, {}, valueTypes,
delimiter, /*hasSameTypeDynamicValues=*/true);
}

/// Parser hook for custom directive in assemblyFormat.
///
Expand Down Expand Up @@ -150,7 +160,8 @@ ParseResult parseDynamicIndexList(
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values,
DenseI64ArrayAttr &integers, DenseBoolArrayAttr &scalableVals,
SmallVectorImpl<Type> *valueTypes = nullptr,
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square);
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square,
bool hasSameTypeDynamicValues = false);
inline ParseResult
parseDynamicIndexList(OpAsmParser &parser,
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values,
Expand Down Expand Up @@ -188,6 +199,16 @@ inline ParseResult parseDynamicIndexList(
return parseDynamicIndexList(parser, values, integers, scalableVals,
&valueTypes, delimiter);
}
inline ParseResult parseSameTypeDynamicIndexList(
OpAsmParser &parser,
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values,
DenseI64ArrayAttr &integers, SmallVectorImpl<Type> &valueTypes,
AsmParser::Delimiter delimiter = AsmParser::Delimiter::Square) {
DenseBoolArrayAttr scalableVals = {};
return parseDynamicIndexList(parser, values, integers, scalableVals,
&valueTypes, delimiter,
/*hasSameTypeDynamicValues=*/true);
}

/// Verify that a the `values` has as many elements as the number of entries in
/// `attr` for which `isDynamic` evaluates to true.
Expand Down
23 changes: 19 additions & 4 deletions mlir/lib/AsmParser/AsmParserImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,16 @@ class AsmParserImpl : public BaseT {
/// Parse a list of comma-separated items with an optional delimiter. If a
/// delimiter is provided, then an empty list is allowed. If not, then at
/// least one element will be parsed.
ParseResult parseCommaSeparatedList(Delimiter delimiter,
function_ref<ParseResult()> parseElt,
StringRef contextMessage) override {
return parser.parseCommaSeparatedList(delimiter, parseElt, contextMessage);
ParseResult parseCommaSeparatedList(
Delimiter delimiter, function_ref<ParseResult()> parseElt,
std::optional<function_ref<ParseResult()>> parseSuffix,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move parseSuffix to the end and make it function_ref<ParseResult()> parseSuffix = nullptr? function_ref is rarely used with std::optional. Also, maybe this function would not be needed at all then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is needed to parse the suffix, which is optional. I'm using a function_ref similar to what we do for parseElt.

StringRef contextMessage) override {
return parser.parseCommaSeparatedList(delimiter, parseElt, parseSuffix,
contextMessage);
}

using BaseT::parseCommaSeparatedList;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there two overloads, one calling the super implementation and the other one calling parser.parseCommaSeparatedList?


//===--------------------------------------------------------------------===//
// Keyword Parsing
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -590,6 +594,17 @@ class AsmParserImpl : public BaseT {
return parser.parseTypeListNoParens(result);
}

/// Parse an optional colon followed by a type.
ParseResult parseOptionalColonType(Type &result) override {
SmallVector<Type, 1> types;
ParseResult parseResult = parseOptionalColonTypeList(types);
if (llvm::succeeded(parseResult) && types.size() > 1)
return emitError(getCurrentLocation(), "expected single type");
if (!types.empty())
result = types[0];
return parseResult;
}

ParseResult parseDimensionList(SmallVectorImpl<int64_t> &dimensions,
bool allowDynamic,
bool withTrailingX) override {
Expand Down
11 changes: 7 additions & 4 deletions mlir/lib/AsmParser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ AsmParserCodeCompleteContext::~AsmParserCodeCompleteContext() = default;
/// Parse a list of comma-separated items with an optional delimiter. If a
/// delimiter is provided, then an empty list is allowed. If not, then at
/// least one element will be parsed.
ParseResult
Parser::parseCommaSeparatedList(Delimiter delimiter,
function_ref<ParseResult()> parseElementFn,
StringRef contextMessage) {
ParseResult Parser::parseCommaSeparatedList(
Delimiter delimiter, function_ref<ParseResult()> parseElementFn,
std::optional<function_ref<ParseResult()>> parseSuffixFn,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't function_ref nullable on its own? This is the case for plain std::function. I'd like to avoid double nullability where possible.

StringRef contextMessage) {
switch (delimiter) {
case Delimiter::None:
break;
Expand Down Expand Up @@ -144,6 +144,9 @@ Parser::parseCommaSeparatedList(Delimiter delimiter,
return failure();
}

if (parseSuffixFn && (*parseSuffixFn)())
return failure();

switch (delimiter) {
case Delimiter::None:
return success();
Expand Down
9 changes: 8 additions & 1 deletion mlir/lib/AsmParser/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,17 @@ class Parser {
/// Parse a list of comma-separated items with an optional delimiter. If a
/// delimiter is provided, then an empty list is allowed. If not, then at
/// least one element will be parsed.
ParseResult parseCommaSeparatedList(
Delimiter delimiter, function_ref<ParseResult()> parseElementFn,
std::optional<function_ref<ParseResult()>> parseSuffixFn = std::nullopt,
StringRef contextMessage = StringRef());
ParseResult
parseCommaSeparatedList(Delimiter delimiter,
function_ref<ParseResult()> parseElementFn,
StringRef contextMessage = StringRef());
StringRef contextMessage) {
return parseCommaSeparatedList(delimiter, parseElementFn, std::nullopt,
contextMessage);
}

/// Parse a comma separated list of elements that must have at least one entry
/// in it.
Expand Down
10 changes: 6 additions & 4 deletions mlir/lib/Conversion/VectorToArmSME/VectorToArmSME.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,13 +501,14 @@ struct VectorOuterProductToArmSMELowering
///
/// Example:
/// ```
/// %el = vector.extract %tile[%row, %col]: i32 from vector<[4]x[4]xi32>
/// %el = vector.extract %tile[%row, %col : index] : i32 from
/// vector<[4]x[4]xi32>
/// ```
/// Becomes:
/// ```
/// %slice = arm_sme.extract_tile_slice %tile[%row]
/// : vector<[4]xi32> from vector<[4]x[4]xi32>
/// %el = vector.extract %slice[%col] : i32 from vector<[4]xi32>
/// %el = vector.extract %slice[%col : index] : i32 from vector<[4]xi32>
/// ```
struct VectorExtractToArmSMELowering
: public OpRewritePattern<vector::ExtractOp> {
Expand Down Expand Up @@ -561,8 +562,9 @@ struct VectorExtractToArmSMELowering
/// ```
/// %slice = arm_sme.extract_tile_slice %tile[%row]
/// : vector<[4]xi32> from vector<[4]x[4]xi32>
/// %new_slice = vector.insert %el, %slice[%col] : i32 into vector<[4]xi32>
/// %new_tile = arm_sme.insert_tile_slice %new_slice, %tile[%row]
/// %new_slice = vector.insert %el, %slice[%col : index] : i32 into
/// vector<[4]xi32> %new_tile = arm_sme.insert_tile_slice %new_slice,
/// %tile[%row]
/// : vector<[4]xi32> into vector<[4]x[4]xi32>
/// ```
struct VectorInsertToArmSMELowering
Expand Down
8 changes: 4 additions & 4 deletions mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,10 +1050,10 @@ getMaskDimSizes(Value mask, VscaleConstantBuilder &createVscaleMultiple) {
/// %vscale = vector.vscale
/// %c4_vscale = arith.muli %vscale, %c4 : index
/// scf.for %idx = %c0 to %c4_vscale step %c1 {
/// %4 = vector.extract %0[%idx] : f32 from vector<[4]xf32>
/// %5 = vector.extract %1[%idx] : f32 from vector<[4]xf32>
/// %6 = vector.extract %2[%idx] : f32 from vector<[4]xf32>
/// %7 = vector.extract %3[%idx] : f32 from vector<[4]xf32>
/// %4 = vector.extract %0[%idx : index] : f32 from vector<[4]xf32>
/// %5 = vector.extract %1[%idx : index] : f32 from vector<[4]xf32>
/// %6 = vector.extract %2[%idx : index] : f32 from vector<[4]xf32>
/// %7 = vector.extract %3[%idx : index] : f32 from vector<[4]xf32>
/// %slice_i = affine.apply #map(%idx)[%i]
/// %slice = vector.from_elements %4, %5, %6, %7 : vector<4xf32>
/// vector.transfer_write %slice, %arg1[%slice_i, %j] {in_bounds = [true]}
Expand Down
46 changes: 40 additions & 6 deletions mlir/lib/Interfaces/ViewLikeInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ void mlir::printDynamicIndexList(OpAsmPrinter &printer, Operation *op,
OperandRange values,
ArrayRef<int64_t> integers,
ArrayRef<bool> scalables, TypeRange valueTypes,
AsmParser::Delimiter delimiter) {
AsmParser::Delimiter delimiter,
bool hasSameTypeDynamicValues) {
char leftDelimiter = getLeftDelimiter(delimiter);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case we keep the valueTypes parameter, I think there should be an assert that checks the number of elements in valueTypes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, can we assert that TypeRange(values) == valueTypes?

char rightDelimiter = getRightDelimiter(delimiter);
printer << leftDelimiter;
Expand All @@ -130,7 +131,7 @@ void mlir::printDynamicIndexList(OpAsmPrinter &printer, Operation *op,
printer << "[";
if (ShapedType::isDynamic(integer)) {
printer << values[dynamicValIdx];
if (!valueTypes.empty())
if (!hasSameTypeDynamicValues && !valueTypes.empty())
printer << " : " << valueTypes[dynamicValIdx];
++dynamicValIdx;
} else {
Expand All @@ -142,14 +143,22 @@ void mlir::printDynamicIndexList(OpAsmPrinter &printer, Operation *op,
scalableIndexIdx++;
});

if (hasSameTypeDynamicValues && !valueTypes.empty()) {
assert(std::all_of(valueTypes.begin(), valueTypes.end(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

llvm::all_equal

[&](Type type) { return type == valueTypes[0]; }) &&
"Expected the same value types");
printer << " : " << valueTypes[0];
}

printer << rightDelimiter;
}

ParseResult mlir::parseDynamicIndexList(
OpAsmParser &parser,
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values,
DenseI64ArrayAttr &integers, DenseBoolArrayAttr &scalables,
SmallVectorImpl<Type> *valueTypes, AsmParser::Delimiter delimiter) {
SmallVectorImpl<Type> *valueTypes, AsmParser::Delimiter delimiter,
bool hasSameTypeDynamicValues) {

SmallVector<int64_t, 4> integerVals;
SmallVector<bool, 4> scalableVals;
Expand All @@ -163,7 +172,8 @@ ParseResult mlir::parseDynamicIndexList(
if (res.has_value() && succeeded(res.value())) {
values.push_back(operand);
integerVals.push_back(ShapedType::kDynamic);
if (valueTypes && parser.parseColonType(valueTypes->emplace_back()))
if (!hasSameTypeDynamicValues && valueTypes &&
parser.parseColonType(valueTypes->emplace_back()))
return failure();
} else {
int64_t integer;
Expand All @@ -178,10 +188,34 @@ ParseResult mlir::parseDynamicIndexList(
return failure();
return success();
};
auto parseColonType = [&]() -> ParseResult {
if (hasSameTypeDynamicValues) {
assert(valueTypes && "Expected non-null value types");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is valueTypes requires when hasSameTypeDynamicValues is "true", but it is not required when hasSameTypeDynamicValues is "false"?

assert(valueTypes->empty() && "Expected no parsed value types");

Type dynValType;
if (parser.parseOptionalColonType(dynValType))
return failure();

if (!dynValType && !values.empty())
return parser.emitError(parser.getNameLoc())
<< "expected a type for dynamic indices";
if (dynValType) {
if (values.empty())
return parser.emitError(parser.getNameLoc())
<< "expected no type for constant indices";

// Broadcast the single type to all the dynamic values.
valueTypes->append(values.size(), dynValType);
}
}
return success();
};
if (parser.parseCommaSeparatedList(delimiter, parseIntegerOrValue,
" in dynamic index list"))
parseColonType, " in dynamic index list"))
return parser.emitError(parser.getNameLoc())
<< "expected SSA value or integer";
<< "expected a valid list of SSA values or integers";

integers = parser.getBuilder().getDenseI64ArrayAttr(integerVals);
scalables = parser.getBuilder().getDenseBoolArrayAttr(scalableVals);
return success();
Expand Down
Loading
Loading