Skip to content

[TorchToLinalg] Segfault instead of a clean failure when lowering 8-bit integer matmul / mm / bmm / convolution #4725

Description

@dudgus1727

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:

  1. 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.
  2. 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
convertScalarToDtypeLinear.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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions