Skip to content

[Relax][PyTorch] Cast non-bool inputs to bool in logical_and converter - #19679

Merged
tlopex merged 1 commit into
apache:mainfrom
javierdejesusda:relax-torch-logical-and-bool
Jun 8, 2026
Merged

tlopex merged 1 commit into
apache:mainfrom
javierdejesusda:relax-torch-logical-and-bool

Conversation

@javierdejesusda

Copy link
Copy Markdown
Contributor

Motivation

torch.logical_and accepts input tensors of any dtype (treating any nonzero
element as True) and always returns a bool tensor.

The PyTorch frontend did not produce that bool result. The ExportedProgram
frontend lowered logical_and.default with
self._binary_op(relax.op.logical_and, operator.and_), which kept the operand
dtype and emitted relax.op.logical_and on non-bool inputs (for example
float32). relax.op.logical_and requires boolean inputs and otherwise fails
LegalizeOps in the TOPI logical_and. The FX frontend did not register
logical_and at all, so the op was unsupported there.

Changes

  • Add a shared _logical_and converter in BaseFXGraphImporter that casts
    non-bool operands to bool before applying relax.op.logical_and. Bool
    operands are passed through unchanged (no redundant cast).
  • Point the logical_and.default (ExportedProgram) registration at the new
    converter, and add a logical_and (FX) registration that was previously
    missing, matching the existing logical_not converter.
  • Add a standalone test_logical_and to both the FX and ExportedProgram test
    suites asserting the corrected IR (astype to bool on each operand, then
    logical_and, producing a bool output).

Notes

The cast to bool lowers to an elementwise nonzero test, so it matches
PyTorch's "nonzero is True" semantics for float, integer, and NaN inputs.

torch.logical_and returns a boolean tensor for any input dtype, but relax.op.logical_and requires boolean inputs. The exported-program frontend lowered logical_and directly to relax.op.logical_and, which fails LegalizeOps for non-bool inputs, and the FX frontend did not support logical_and at all. Add a shared converter that casts non-bool operands to bool first, matching torch and the existing logical_not converter, and register it for both frontends.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements a custom translator for torch.logical_and in the TVM Relax PyTorch frontend. The new _logical_and method casts non-boolean inputs to boolean first, aligning with PyTorch's behavior. This translator is registered in both FX and Exported Program translators, and corresponding tests are added. A review comment suggests adding safety checks to ensure struct_info is an instance of relax.TensorStructInfo before accessing its dtype to prevent potential AttributeErrors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread python/tvm/relax/frontend/torch/base_fx_graph_translator.py

@cchung100m cchung100m left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thanks to @javierdejesusda

@tlopex tlopex left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@tlopex
tlopex merged commit 0e32507 into apache:main Jun 8, 2026
13 checks passed
tlopex pushed a commit that referenced this pull request Jun 13, 2026
### Motivation

`torch.logical_or` and `torch.logical_xor` accept input tensors of any
dtype
(treating any nonzero element as `True`) and always return a `bool`
tensor.

Neither op was handled by the PyTorch frontend. The ExportedProgram
frontend did
not register `logical_or.default` / `logical_xor.default`, and the FX
frontend
did not register `logical_or` / `logical_xor`, so importing a model that
uses
either op failed early with `Unsupported function types`.

This follows up on #19679 (`logical_and`) and addresses the explicit
question
raised in #19743: whether `logical_or` and `logical_xor` need the same
handling.

### Changes

- Add shared `_logical_or` and `_logical_xor` converters in
`BaseFXGraphImporter`
that cast non-bool operands to `bool` before applying
`relax.op.logical_or` /
  `relax.op.logical_xor`. Bool operands are passed through unchanged (no
  redundant cast).
- Register `logical_or.default` / `logical_xor.default`
(ExportedProgram) and
  `logical_or` / `logical_xor` (FX), matching the existing `logical_and`
  converter.
- Add standalone `test_logical_or` and `test_logical_xor` to both the FX
and
ExportedProgram test suites, asserting the corrected IR (`astype` to
bool on
  each operand, then the logical op, producing a `bool` output).

### Notes

The cast to `bool` lowers to an elementwise nonzero test, so it matches
PyTorch's "nonzero is True" semantics for float, integer, and NaN
inputs.
MasterJH5574 pushed a commit to MasterJH5574/tvm that referenced this pull request Jun 15, 2026
apache#19679)

### Motivation

`torch.logical_and` accepts input tensors of any dtype (treating any
nonzero
element as `True`) and always returns a `bool` tensor.

The PyTorch frontend did not produce that `bool` result. The
ExportedProgram
frontend lowered `logical_and.default` with
`self._binary_op(relax.op.logical_and, operator.and_)`, which kept the
operand
dtype and emitted `relax.op.logical_and` on non-bool inputs (for example
`float32`). `relax.op.logical_and` requires boolean inputs and otherwise
fails
`LegalizeOps` in the TOPI `logical_and`. The FX frontend did not
register
`logical_and` at all, so the op was unsupported there.

### Changes

- Add a shared `_logical_and` converter in `BaseFXGraphImporter` that
casts
non-bool operands to `bool` before applying `relax.op.logical_and`. Bool
  operands are passed through unchanged (no redundant cast).
- Point the `logical_and.default` (ExportedProgram) registration at the
new
converter, and add a `logical_and` (FX) registration that was previously
  missing, matching the existing `logical_not` converter.
- Add a standalone `test_logical_and` to both the FX and ExportedProgram
test
suites asserting the corrected IR (`astype` to bool on each operand,
then
  `logical_and`, producing a `bool` output).

### Notes

The cast to `bool` lowers to an elementwise nonzero test, so it matches
PyTorch's "nonzero is True" semantics for float, integer, and NaN
inputs.

(cherry picked from commit 0e32507)
MasterJH5574 pushed a commit to MasterJH5574/tvm that referenced this pull request Jun 15, 2026
apache#19679)

### Motivation

`torch.logical_and` accepts input tensors of any dtype (treating any
nonzero
element as `True`) and always returns a `bool` tensor.

The PyTorch frontend did not produce that `bool` result. The
ExportedProgram
frontend lowered `logical_and.default` with
`self._binary_op(relax.op.logical_and, operator.and_)`, which kept the
operand
dtype and emitted `relax.op.logical_and` on non-bool inputs (for example
`float32`). `relax.op.logical_and` requires boolean inputs and otherwise
fails
`LegalizeOps` in the TOPI `logical_and`. The FX frontend did not
register
`logical_and` at all, so the op was unsupported there.

### Changes

- Add a shared `_logical_and` converter in `BaseFXGraphImporter` that
casts
non-bool operands to `bool` before applying `relax.op.logical_and`. Bool
  operands are passed through unchanged (no redundant cast).
- Point the `logical_and.default` (ExportedProgram) registration at the
new
converter, and add a `logical_and` (FX) registration that was previously
  missing, matching the existing `logical_not` converter.
- Add a standalone `test_logical_and` to both the FX and ExportedProgram
test
suites asserting the corrected IR (`astype` to bool on each operand,
then
  `logical_and`, producing a `bool` output).

### Notes

The cast to `bool` lowers to an elementwise nonzero test, so it matches
PyTorch's "nonzero is True" semantics for float, integer, and NaN
inputs.

(cherry picked from commit 0e32507)
MasterJH5574 pushed a commit to MasterJH5574/tvm that referenced this pull request Jun 15, 2026
)

### Motivation

`torch.logical_or` and `torch.logical_xor` accept input tensors of any
dtype
(treating any nonzero element as `True`) and always return a `bool`
tensor.

Neither op was handled by the PyTorch frontend. The ExportedProgram
frontend did
not register `logical_or.default` / `logical_xor.default`, and the FX
frontend
did not register `logical_or` / `logical_xor`, so importing a model that
uses
either op failed early with `Unsupported function types`.

This follows up on apache#19679 (`logical_and`) and addresses the explicit
question
raised in apache#19743: whether `logical_or` and `logical_xor` need the same
handling.

### Changes

- Add shared `_logical_or` and `_logical_xor` converters in
`BaseFXGraphImporter`
that cast non-bool operands to `bool` before applying
`relax.op.logical_or` /
  `relax.op.logical_xor`. Bool operands are passed through unchanged (no
  redundant cast).
- Register `logical_or.default` / `logical_xor.default`
(ExportedProgram) and
  `logical_or` / `logical_xor` (FX), matching the existing `logical_and`
  converter.
- Add standalone `test_logical_or` and `test_logical_xor` to both the FX
and
ExportedProgram test suites, asserting the corrected IR (`astype` to
bool on
  each operand, then the logical op, producing a `bool` output).

### Notes

The cast to `bool` lowers to an elementwise nonzero test, so it matches
PyTorch's "nonzero is True" semantics for float, integer, and NaN
inputs.

(cherry picked from commit f5e8a3a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants