Summary
--convert-torch-to-linalg segfaults on any aten.matmul, aten.mm, aten.bmm, or
aten.convolution whose result dtype is an 8-bit integer (si8 or ui8).
An unimplemented: diagnostic is emitted first, but the pass then builds a
linalg.yield from a null Value and the process dies. In torch-mlir-opt this
prints an LLVM crash dump; from the Python bindings the interpreter dies with
Segmentation fault and the diagnostic never reaches the caller, so there is no
actionable signal at all.
The underlying unimplemented case is already known — AtenMmInt8Types_basic and
AtenMmInt8ZeroK_basic sit in projects/pt1/e2e_testing/xfail_sets.py citing this exact
message. This issue is only about the crash: the pattern should report a legalization
failure, not take the process down.
Reproducer
No PyTorch, no Python — six lines of MLIR:
// repro.mlir
func.func @int8_matmul(%lhs: !torch.vtensor<[4,4],si8>,
%rhs: !torch.vtensor<[4,4],si8>) -> !torch.vtensor<[4,4],si8> {
%0 = torch.aten.matmul %lhs, %rhs
: !torch.vtensor<[4,4],si8>, !torch.vtensor<[4,4],si8>
-> !torch.vtensor<[4,4],si8>
return %0 : !torch.vtensor<[4,4],si8>
}
$ torch-mlir-opt --convert-torch-to-linalg repro.mlir
repro.mlir:5:8: error: unimplemented: for conversion to byte or char type dstOriginalDtype has to be passed to convertScalarToDtype
%0 = torch.aten.matmul %lhs, %rhs
^
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ ...
Stack dump:
#8 mlir::linalg::YieldOp::create(mlir::OpBuilder&, mlir::Location, mlir::ValueRange)
#9 ...convertTensorToElementType(...)::'lambda'(...)
#13 mlir::torch::torch_to_linalg::createElementwiseLinalgGeneric(...)
#14 mlir::torch::torch_to_linalg::convertTensorToElementType(...)
#15 (anonymous namespace)::ConvertAtenMatmulOp::matchAndRewrite(...)
#22 mlir::applyPartialConversion(...)
#23 mlir::torch::(anonymous namespace)::ConvertTorchToLinalg::runOnOperation()
$ echo $?
245
Expected: error: failed to legalize operation 'torch.aten.matmul', exit code 1.
Actual: segmentation fault, exit code 245.
Root cause
convertScalarToDtype returns nullptr for a byte/char destination when
dstOriginalDtype is absent — lib/Conversion/Utils/Utils.cpp:
if (isByteOrChar(dtype)) {
if (!dstOriginalDtype.has_value()) {
mlir::emitError(loc)
<< "unimplemented: for conversion to byte or char type "
"dstOriginalDtype has to be passed to convertScalarToDtype";
return nullptr;
}
convertTensorToElementType calls it without that argument — and cannot pass it, since
its signature carries only a signless Type and never sees the Torch dtype —
then yields the result unchecked. lib/Conversion/TorchToLinalg/Utils.cpp:
Value torch_to_linalg::convertTensorToElementType(OpBuilder &b, Location loc,
Value tensor,
Type elementType) {
auto dtypePromoteBody = [&](OpBuilder &builder, Location loc,
ValueRange payloadArgs) {
Value elem =
convertScalarToDtype(builder, loc, payloadArgs[0], elementType);
linalg::YieldOp::create(builder, loc, elem); // <-- elem is null here
};
ConvertAtenMatmulOp and friends reach this whenever the accumulator type chosen by
getDefaultAccType differs from the result element type, which for an 8-bit integer
result is always. There are ~20 such call sites in
lib/Conversion/TorchToLinalg/Linear.cpp.
Affected combinations
Each cell is torch-mlir-opt --convert-torch-to-linalg on a minimal function containing
only that op.
| op |
si8 |
ui8 |
si32 |
f32 |
aten.matmul (2-D) |
CRASH |
CRASH |
ok |
ok |
aten.matmul (1-D dot) |
CRASH |
CRASH |
ok |
ok |
aten.mm |
CRASH |
CRASH |
ok |
ok |
aten.bmm |
CRASH |
CRASH |
ok |
ok |
aten.convolution |
CRASH |
CRASH |
ok |
ok |
si16 behaves like si32 (the guard is getWidth() == 8). Signedness is irrelevant:
ui8 crashes for the same reason.
Suggested fix
The precondition is knowable before any IR is built, so it can be checked where a
notifyMatchFailure is still possible. Two shapes, whichever suits the codebase:
- Change
convertTensorToElementType to return FailureOr<Value>, bailing out up front
when elementType is an 8-bit integer and no Torch dtype was supplied, and have the
call sites propagate the failure.
- Keep the signature and add a small
canConvertTensorToElementType(...) predicate that
patterns consult before calling, returning rewriter.notifyMatchFailure(...) otherwise.
Either way the result is a legalization failure that a caller can act on.
Note on the underlying gap
The real fix for 8-bit integer matmul is to thread the Torch result dtype through to
convertScalarToDtype — Linear.cpp already holds it via the op's result type, so it is
mostly a matter of adding an optional parameter to convertTensorToElementType and
forwarding it. That would let AtenMmInt8Types_basic and AtenMmInt8ZeroK_basic come off
the xfail list. I'm happy to send that as a separate PR if it's wanted; filing the crash
on its own first since it is orthogonal and much smaller.
Environment
- torch-mlir
20260812.843 (pip wheel, includes torch-mlir-opt)
- torch
2.14.0.dev20260811+cpu
- Linux x86_64, Python 3.11
Summary
--convert-torch-to-linalgsegfaults on anyaten.matmul,aten.mm,aten.bmm, oraten.convolutionwhose result dtype is an 8-bit integer (si8orui8).An
unimplemented:diagnostic is emitted first, but the pass then builds alinalg.yieldfrom a nullValueand the process dies. Intorch-mlir-optthisprints an LLVM crash dump; from the Python bindings the interpreter dies with
Segmentation faultand the diagnostic never reaches the caller, so there is noactionable signal at all.
The underlying unimplemented case is already known —
AtenMmInt8Types_basicandAtenMmInt8ZeroK_basicsit inprojects/pt1/e2e_testing/xfail_sets.pyciting this exactmessage. This issue is only about the crash: the pattern should report a legalization
failure, not take the process down.
Reproducer
No PyTorch, no Python — six lines of MLIR:
Expected:
error: failed to legalize operation 'torch.aten.matmul', exit code 1.Actual: segmentation fault, exit code 245.
Root cause
convertScalarToDtypereturnsnullptrfor a byte/char destination whendstOriginalDtypeis absent —lib/Conversion/Utils/Utils.cpp:convertTensorToElementTypecalls it without that argument — and cannot pass it, sinceits signature carries only a signless
Typeand never sees the Torch dtype —then yields the result unchecked.
lib/Conversion/TorchToLinalg/Utils.cpp:ConvertAtenMatmulOpand friends reach this whenever the accumulator type chosen bygetDefaultAccTypediffers from the result element type, which for an 8-bit integerresult is always. There are ~20 such call sites in
lib/Conversion/TorchToLinalg/Linear.cpp.Affected combinations
Each cell is
torch-mlir-opt --convert-torch-to-linalgon a minimal function containingonly that op.
si8ui8si32f32aten.matmul(2-D)aten.matmul(1-D dot)aten.mmaten.bmmaten.convolutionsi16behaves likesi32(the guard isgetWidth() == 8). Signedness is irrelevant:ui8crashes for the same reason.Suggested fix
The precondition is knowable before any IR is built, so it can be checked where a
notifyMatchFailureis still possible. Two shapes, whichever suits the codebase:convertTensorToElementTypeto returnFailureOr<Value>, bailing out up frontwhen
elementTypeis an 8-bit integer and no Torch dtype was supplied, and have thecall sites propagate the failure.
canConvertTensorToElementType(...)predicate thatpatterns consult before calling, returning
rewriter.notifyMatchFailure(...)otherwise.Either way the result is a legalization failure that a caller can act on.
Note on the underlying gap
The real fix for 8-bit integer matmul is to thread the Torch result dtype through to
convertScalarToDtype—Linear.cppalready holds it via the op's result type, so it ismostly a matter of adding an optional parameter to
convertTensorToElementTypeandforwarding it. That would let
AtenMmInt8Types_basicandAtenMmInt8ZeroK_basiccome offthe xfail list. I'm happy to send that as a separate PR if it's wanted; filing the crash
on its own first since it is orthogonal and much smaller.
Environment
20260812.843(pip wheel, includestorch-mlir-opt)2.14.0.dev20260811+cpu