diff --git a/backends/arm/scripts/docgen/generate_op_support.py b/backends/arm/scripts/docgen/generate_op_support.py index 33c85007dee..75d71e64230 100644 --- a/backends/arm/scripts/docgen/generate_op_support.py +++ b/backends/arm/scripts/docgen/generate_op_support.py @@ -11,6 +11,7 @@ Examples: python backends/arm/scripts/docgen/generate_op_support.py --backend vgf python backends/arm/scripts/docgen/generate_op_support.py --backend u55 + python backends/arm/scripts/docgen/generate_op_support.py --backend u85 python backends/arm/scripts/docgen/generate_op_support.py --backend u55 --debug --html python backends/arm/scripts/docgen/generate_op_support.py --backend vgf --check --strict-ast @@ -104,6 +105,22 @@ class BackendConfig: filter_u55_unsupported_ops=True, max_missing_profile_cells=4, ), + "u85": BackendConfig( + key="u85", + name="Ethos-U85", + pipeline_class_names=frozenset({"EthosU85PipelineINT"}), + pipeline_label="EthosU85PipelineINT", + tosa_spec="TOSA-1.0+INT+int16+int4+cf", + default_output=Path("docs/source/backends/arm-ethos-u/U85_op_support.md"), + quantize_keyword=None, + quantize_default=True, + default_profile="INT", + support_profile_order=("INT",), + # A missing Corstone-320 FVP is infrastructure, not evidence that the + # operator itself is unsupported. + infrastructure_xfail_markers=frozenset({"XfailIfNoCorstone320"}), + max_missing_profile_cells=10, + ), } # Compatibility globals used by the mature scanner implementation. They are @@ -418,6 +435,25 @@ def _activate_backend(backend: str | BackendConfig) -> BackendConfig: }, } +# Existing U85 runtime tests below intentionally suppress direct ATen/Edge +# assertions because quantization/decomposition changes the graph. They still +# provide positive runtime coverage for the exported operator. +U85_EXPLICIT_BACKEND_COVERAGE: dict[tuple[str, str], dict[str, set[str]]] = { + ( + "backends/arm/test/ops/test_div_tensor_mode.py", + "test_div_tensor_mode_u85_INT", + ): { + "INT": {"torch.ops.aten.div.Tensor_mode"}, + }, + ( + "backends/arm/test/ops/test_silu.py", + "test_silu_u85_INT", + ): { + "INT": {"torch.ops.aten.silu.default"}, + }, +} + + # These exported operators pass a generic TOSA positive-support declaration, # but their actual U55 lowering path reaches an unsupported operation or a # restriction that cannot support the general exported operator. Keep these @@ -438,6 +474,8 @@ def _active_explicit_backend_coverage() -> dict[tuple[str, str], dict[str, set[s return VGF_EXPLICIT_BACKEND_COVERAGE if ACTIVE_BACKEND_KEY == "u55": return U55_EXPLICIT_BACKEND_COVERAGE + if ACTIVE_BACKEND_KEY == "u85": + return U85_EXPLICIT_BACKEND_COVERAGE return {} @@ -2369,6 +2407,9 @@ def _collect_backend_custom_partition_ops( to the profiles for which they are actually registered. """ + if ACTIVE_BACKEND_KEY != "vgf": + return {} + from executorch.backends.arm.vgf import VgfCompileSpec, VgfPartitioner enabled_profiles = { diff --git a/backends/arm/scripts/pre-push b/backends/arm/scripts/pre-push index 96284645402..6fa37b35a2d 100755 --- a/backends/arm/scripts/pre-push +++ b/backends/arm/scripts/pre-push @@ -35,6 +35,7 @@ DOCGEN_OUTPUTS=( OP_SUPPORT_SCRIPT="backends/arm/scripts/docgen/generate_op_support.py" VGF_OP_SUPPORT_OUTPUT="docs/source/backends/arm-vgf/VGF_op_support.md" U55_OP_SUPPORT_OUTPUT="docs/source/backends/arm-ethos-u/U55_op_support.md" +U85_OP_SUPPORT_OUTPUT="docs/source/backends/arm-ethos-u/U85_op_support.md" RUN_DOCGEN=0 @@ -353,6 +354,7 @@ fi run_op_support_checks "vgf" "VGF" "$VGF_OP_SUPPORT_OUTPUT" run_op_support_checks "u55" "Ethos-U55" "$U55_OP_SUPPORT_OUTPUT" +run_op_support_checks "u85" "Ethos-U85" "$U85_OP_SUPPORT_OUTPUT" run_public_api_validator if [[ $FAILED ]]; then diff --git a/backends/arm/test/misc/test_docgen_op_support.py b/backends/arm/test/misc/test_docgen_op_support.py index 9f3c251478b..6c2916dd0ec 100644 --- a/backends/arm/test/misc/test_docgen_op_support.py +++ b/backends/arm/test/misc/test_docgen_op_support.py @@ -151,6 +151,79 @@ def test_u55_infrastructure_xfail_is_not_treated_as_unsupported() -> None: docgen._activate_backend(original) +def test_u85_backend_configuration_and_profile() -> None: + original = docgen.ACTIVE_BACKEND_KEY + try: + config = docgen._activate_backend("u85") + assert config.pipeline_class_names == frozenset({"EthosU85PipelineINT"}) + assert docgen.BACKEND_NAME == "Ethos-U85" + assert docgen.BACKEND_TOSA_SPEC == "TOSA-1.0+INT+int16+int4+cf" + assert docgen.DEFAULT_OUTPUT == Path( + "docs/source/backends/arm-ethos-u/U85_op_support.md" + ) + assert docgen.SUPPORT_PROFILE_ORDER == ["INT"] + + stmt = ast.parse("EthosU85PipelineINT(quantize=False)").body[0] + assert isinstance(stmt, ast.Expr) + call = stmt.value + assert isinstance(call, ast.Call) + # U85 is integer-only; an irrelevant quantize kwarg cannot turn it FP. + assert docgen._pipeline_profile(call) == "INT" + finally: + docgen._activate_backend(original) + + +def test_u85_infrastructure_xfail_is_not_treated_as_unsupported() -> None: + original = docgen.ACTIVE_BACKEND_KEY + try: + docgen._activate_backend("u85") + tree = ast.parse( + "@common.XfailIfNoCorstone320\n" "def test_u85():\n" " pass\n" + ) + function = tree.body[0] + assert isinstance(function, ast.FunctionDef) + assert not docgen._function_is_skipped_or_xfailed(function) + + semantic_tree = ast.parse( + "@pytest.mark.xfail(reason='unsupported')\n" + "def test_u85():\n" + " pass\n" + ) + semantic_function = semantic_tree.body[0] + assert isinstance(semantic_function, ast.FunctionDef) + assert docgen._function_is_skipped_or_xfailed(semantic_function) + finally: + docgen._activate_backend(original) + + +def test_u85_explicit_coverage_attribution() -> None: + original = docgen.ACTIVE_BACKEND_KEY + try: + docgen._activate_backend("u85") + coverage = docgen._active_explicit_backend_coverage() + + assert coverage[ + ( + "backends/arm/test/ops/test_div_tensor_mode.py", + "test_div_tensor_mode_u85_INT", + ) + ]["INT"] == {"torch.ops.aten.div.Tensor_mode"} + assert coverage[("backends/arm/test/ops/test_silu.py", "test_silu_u85_INT")][ + "INT" + ] == {"torch.ops.aten.silu.default"} + finally: + docgen._activate_backend(original) + + +def test_non_vgf_backend_does_not_collect_vgf_custom_partition_ops() -> None: + original = docgen.ACTIVE_BACKEND_KEY + try: + docgen._activate_backend("u85") + assert docgen._collect_backend_custom_partition_ops(object()) == {} # type: ignore[arg-type] + finally: + docgen._activate_backend(original) + + def test_backend_registry_filter_removes_unconditional_rejections( monkeypatch: pytest.MonkeyPatch, ) -> None: diff --git a/docs/source/backends/arm-ethos-u/U85_op_support.md b/docs/source/backends/arm-ethos-u/U85_op_support.md index 3f2c4cc25da..69e5635f168 100644 --- a/docs/source/backends/arm-ethos-u/U85_op_support.md +++ b/docs/source/backends/arm-ethos-u/U85_op_support.md @@ -1,136 +1,131 @@ -# EdgeIR Operator support for the U85 backend -This list contains operators with silicon acceleration support. -The ExecuTorch portable kernels allow running more operations with a fallback. -8x8 designates 8-bit activation and 8-bit weight. 16x8 means 16-bit activation and 8-bit weight. -Per-tensor and per-channel quantization are supported. +# PyTorch operator support for the Ethos-U85 backend -| EdgeIR operator | Compute DType | Quantization | -| --------------- | ------------------------------| ------------ | -| _log_softmax.default | Static integer quantization | 8x8 | -| _softmax.default | Static integer quantization | 8x8 | -| abs.default | Static integer quantization | 8x8 | -| acos.default | Static integer quantization | 8x8 | -| adaptive_avg_pool2d.default | Static integer quantization | 16x8 / 8x8 | -| add.Tensor | Static integer quantization | 16x8 / 8x8 | -| addmm.default | Static integer quantization | 16x8 / 8x8 | -| alias_copy.default | Static integer quantization | 8x8 | -| amax.default | Static integer quantization | 16x8 / 8x8 | -| amin.default | Static integer quantization | 16x8 / 8x8 | -| any.default | Static integer quantization | 8x8 | -| arange.start_step | Static integer quantization | 8x8 | -| asin.default | Static integer quantization | 8x8 | -| asinh.default | Static integer quantization | 8x8 | -| atan.default | Static integer quantization | 8x8 | -| atanh.default | Static integer quantization | 8x8 | -| avg_pool2d.default | Static integer quantization | 16x8 / 8x8 | -| bitwise_and.Scalar | Static integer quantization | 8x8 | -| bitwise_left_shift.Scalar | Static integer quantization | 8x8 | -| bitwise_left_shift.Tensor | Static integer quantization | 8x8 | -| bitwise_not.default | Static integer quantization | 8x8 | -| bitwise_or.Scalar | Static integer quantization | 8x8 | -| bitwise_right_shift.Scalar | Static integer quantization | 8x8 | -| bitwise_right_shift.Tensor | Static integer quantization | 8x8 | -| bitwise_xor.Scalar | Static integer quantization | 8x8 | -| bmm.default | Static integer quantization | 8x8 | -| cat.default | Static integer quantization | 16x8 / 8x8 | -| ceil.default | Static integer quantization | 8x8 | -| clamp.default | Static integer quantization | 16x8 / 8x8 | -| clone.default | Static integer quantization | 8x8 | -| conv_transpose2d.default | Static integer quantization | 8x8 | -| convolution.default | Static integer quantization | 16x8 / 8x8 | -| copy.default | Static integer quantization | 8x8 | -| cos.default | Static integer quantization | 8x8 | -| cosh.default | Static integer quantization | 8x8 | -| cumsum.default | Static integer quantization | 8x8 | -| div.Tensor | Static integer quantization | 8x8 | -| div.Tensor_mode | Static integer quantization | 8x8 | -| elu.default | Static integer quantization | 8x8 | -| eq.Scalar | Static integer quantization | 16x8 / 8x8 | -| erf.default | Static integer quantization | 8x8 | -| exp.default | Static integer quantization | 8x8 | -| expand_copy.default | Static integer quantization | 8x8 | -| expm1.default | Static integer quantization | 8x8 | -| eye.default | Static integer quantization | 8x8 | -| fill.Scalar | Static integer quantization | 8x8 | -| floor.default | Static integer quantization | 8x8 | -| floor_divide.default | Static integer quantization | 8x8 | -| full.default | Static integer quantization | 8x8 | -| gather.default | Static integer quantization | 8x8 | -| ge.Scalar | Static integer quantization | 16x8 / 8x8 | -| ge.Tensor | Static integer quantization | 16x8 / 8x8 | -| gelu.default | Static integer quantization | 8x8 | -| glu.default | Static integer quantization | 8x8 | -| gt.Scalar | Static integer quantization | 16x8 / 8x8 | -| gt.Tensor | Static integer quantization | 16x8 / 8x8 | -| hardsigmoid.default | Static integer quantization | 8x8 | -| hardswish.default | Static integer quantization | 8x8 | -| hardtanh.default | Static integer quantization | 8x8 | -| index_put.default | Static integer quantization | 8x8 | -| index_select.default | Static integer quantization | 8x8 | -| le.Scalar | Static integer quantization | 16x8 / 8x8 | -| le.Tensor | Static integer quantization | 16x8 / 8x8 | -| leaky_relu.default | Static integer quantization | 8x8 | -| linear.default | Static integer quantization | 16x8 / 8x8 | -| log.default | Static integer quantization | 8x8 | -| logical_and.default | Static integer quantization | 8x8 | -| logical_not.default | Static integer quantization | 8x8 | -| logical_or.default | Static integer quantization | 8x8 | -| logical_xor.default | Static integer quantization | 8x8 | -| logit.default | Static integer quantization | 8x8 | -| lt.Scalar | Static integer quantization | 16x8 / 8x8 | -| lt.Tensor | Static integer quantization | 16x8 / 8x8 | -| masked_fill.Scalar | Static integer quantization | 8x8 | -| maximum.default | Static integer quantization | 16x8 / 8x8 | -| mean.dim | Static integer quantization | 8x8 | -| minimum.default | Static integer quantization | 16x8 / 8x8 | -| mm.default | Static integer quantization | 8x8 | -| mul.Tensor | Static integer quantization | 16x8 / 8x8 | -| multihead_attention.default | Static integer quantization | 8x8 | -| native_group_norm.default | Static integer quantization | 8x8 | -| ne.Scalar | Static integer quantization | 8x8 | -| ne.Tensor | Static integer quantization | 8x8 | -| neg.default | Static integer quantization | 16x8 / 8x8 | -| ones.default | Static integer quantization | 8x8 | -| permute_copy.default | Static integer quantization | 16x8 / 8x8 | -| pow.Tensor_Scalar | Static integer quantization | 8x8 | -| reciprocal.default | Static integer quantization | 8x8 | -| relu.default | Static integer quantization | 8x8 | -| remainder.Scalar | Static integer quantization | 8x8 | -| remainder.Tensor | Static integer quantization | 8x8 | -| repeat.default | Static integer quantization | 16x8 / 8x8 | -| round.default | Static integer quantization | 8x8 | -| rsqrt.default | Static integer quantization | 16x8 / 8x8 | -| rsub.Scalar | Static integer quantization | 8x8 | -| scalar_tensor.default | Static integer quantization | 8x8 | -| sdpa.default | Static integer quantization | 8x8 | -| select_copy.int | Static integer quantization | 8x8 | -| select_scatter.default | Static integer quantization | 8x8 | -| sigmoid.default | Static integer quantization | 16x8 / 8x8 | -| sign.default | Static integer quantization | 8x8 | -| silu.default | Static integer quantization | 8x8 | -| sin.default | Static integer quantization | 8x8 | -| sinh.default | Static integer quantization | 8x8 | -| slice_copy.Tensor | Static integer quantization | 16x8 / 8x8 | -| slice_scatter.default | Static integer quantization | 8x8 | -| split_copy.Tensor | Static integer quantization | 8x8 | -| split_with_sizes_copy.default | Static integer quantization | 8x8 | -| sqrt.default | Static integer quantization | 8x8 | -| squeeze_copy.dim | Static integer quantization | 8x8 | -| squeeze_copy.dims | Static integer quantization | 8x8 | -| stack.default | Static integer quantization | 8x8 | -| sub.Tensor | Static integer quantization | 16x8 / 8x8 | -| sum.default | Static integer quantization | 8x8 | -| t_copy.default | Static integer quantization | 8x8 | -| tan.default | Static integer quantization | 8x8 | -| tanh.default | Static integer quantization | 16x8 / 8x8 | -| transpose_copy.int | Static integer quantization | 8x8 | -| tril.default | Static integer quantization | 16x8 / 8x8 | -| unflatten.int | Static integer quantization | 8x8 | -| unsqueeze_copy.default | Static integer quantization | 8x8 | -| upsample_bilinear2d.vec | Static integer quantization | 16x8 / 8x8 | -| var.dim | Static integer quantization | 8x8 | -| vector_norm.default | Static integer quantization | 8x8 | -| view_copy.default | Static integer quantization | 16x8 / 8x8 | -| where.self | Static integer quantization | 8x8 | -| while_loop.default | Static integer quantization | 8x8 | -| zeros.default | Static integer quantization | 8x8 | + + +This page lists Ethos-U85-supported PyTorch APIs and the dtype and quantization modes covered by the Ethos-U85 backend test pipeline. + +`8x8` means 8-bit activations and 8-bit weights. `16x8` means 16-bit activations and 8-bit weights. `8x4` means 8-bit activations and 4-bit weights. + +Total supported PyTorch APIs: **119**. + +| PyTorch API | Support profile | DType | Quantization mode | +| --- | --- | --- | --- | +| `torch.abs` | INT | `INT8` | 8x8 | +| `torch.acos` | INT | `INT8` | 8x8 | +| `torch.acosh` | INT | `INT8` | 8x8 | +| `torch.add` / `+` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.addmm` | INT | `INT16` | 16x8 | +| `torch.alias_copy` | INT | `INT8` | 8x8 | +| `torch.amax` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.amin` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.any` | INT | `INT8` | 8x8 | +| `torch.arange` | INT | `INT8` | 8x8 | +| `torch.asin` | INT | `INT8` | 8x8 | +| `torch.asinh` | INT | `INT8` | 8x8 | +| `torch.atan` | INT | `INT8` | 8x8 | +| `torch.atanh` | INT | `INT8` | 8x8 | +| `torch.bitwise_and` / `&` | INT | `INT8` | 8x8 | +| `torch.bitwise_left_shift` / `<<` | INT | `INT8` | 8x8 | +| `torch.bitwise_not` / `~` | INT | `INT8` | 8x8 | +| `torch.bitwise_or` / `\|` | INT | `INT8` | 8x8 | +| `torch.bitwise_right_shift` / `>>` | INT | `INT8` | 8x8 | +| `torch.bitwise_xor` / `^` | INT | `INT8` | 8x8 | +| `torch.bmm` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.cat` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.ceil` | INT | `INT8` | 8x8 | +| `torch.clamp` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.clone` / `torch.Tensor.clone` | INT | `INT8` | 8x8 | +| `torch.cond` | INT | `INT8` | 8x8 | +| `torch.conv1d` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.conv2d` | INT | `INT8`, `INT16`, `INT4` | 8x8, 8x4, 16x8 | +| `torch.conv3d` | INT | `INT8`, `INT4` | 8x8, 8x4 | +| `torch.conv_transpose2d` | INT | `INT8` | 8x8 | +| `torch.cos` | INT | `INT8` | 8x8 | +| `torch.cosh` | INT | `INT8` | 8x8 | +| `torch.cumsum` | INT | `INT8` | 8x8 | +| `torch.div` | INT | `INT8` | 8x8 | +| `torch.div` / `/` | INT | `INT8` | 8x8 | +| `torch.eq` / `==` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.erf` | INT | `INT8` | 8x8 | +| `torch.erfinv` | INT | `INT8` | 8x8 | +| `torch.exp` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.expm1` | INT | `INT8` | 8x8 | +| `torch.eye` | INT | `INT8` | 8x8 | +| `torch.fill_` | INT | `INT8` | 8x8 | +| `torch.flip` | INT | `INT8` | 8x8 | +| `torch.floor` | INT | `INT8` | 8x8 | +| `torch.full` | INT | `INT8` | 8x8 | +| `torch.full_like` | INT | `INT8` | 8x8 | +| `torch.gather` | INT | `INT8` | 8x8 | +| `torch.ge` / `>=` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.gt` / `>` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.index_put_` | INT | `INT8` | 8x8 | +| `torch.index_select` | INT | `INT8` | 8x8 | +| `torch.le` / `<=` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.log` | INT | `INT8` | 8x8 | +| `torch.log10` | INT | `INT8` | 8x8 | +| `torch.log_softmax` | INT | `INT8` | 8x8 | +| `torch.logical_and` | INT | `INT8` | 8x8 | +| `torch.logical_not` | INT | `INT8` | 8x8 | +| `torch.logical_or` | INT | `INT8` | 8x8 | +| `torch.logical_xor` | INT | `INT8` | 8x8 | +| `torch.lt` / `<` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.masked_fill` / `torch.Tensor.masked_fill` | INT | `INT8` | 8x8 | +| `torch.max_pool2d` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.maximum` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.mean` | INT | `INT8` | 8x8 | +| `torch.minimum` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.mm` | INT | `INT8` | 8x8 | +| `torch.mul` / `*` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.neg` / `unary -` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.nn.AvgPool2d` / `torch.nn.functional.avg_pool2d` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.nn.Conv2d` / `torch.nn.functional.conv2d` | INT | `INT8`, `INT16`, `INT4` | 8x8, 8x4, 16x8 | +| `torch.nn.ELU` / `torch.nn.functional.elu` | INT | `INT8` | 8x8 | +| `torch.nn.GELU` / `torch.nn.functional.gelu` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.nn.Hardsigmoid` / `torch.nn.functional.hardsigmoid` | INT | `INT8` | 8x8 | +| `torch.nn.Hardswish` / `torch.nn.functional.hardswish` | INT | `INT8` | 8x8 | +| `torch.nn.Hardtanh` / `torch.nn.functional.hardtanh` | INT | `INT8` | 8x8 | +| `torch.nn.LeakyReLU` / `torch.nn.functional.leaky_relu` | INT | `INT8` | 8x8 | +| `torch.nn.Linear` / `torch.nn.functional.linear` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.nn.SiLU` / `torch.nn.functional.silu` | INT | `INT8` | 8x8 | +| `torch.ones` | INT | `INT8` | 8x8 | +| `torch.permute` / `torch.Tensor.permute` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.pixel_shuffle` | INT | `INT8` | 8x8 | +| `torch.pixel_unshuffle` | INT | `INT8` | 8x8 | +| `torch.pow` / `**` | INT | `INT8` | 8x8 | +| `torch.prelu` | INT | `INT8` | 8x8 | +| `torch.reciprocal` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.relu` / `torch.nn.ReLU` | INT | `INT8` | 8x8 | +| `torch.remainder` | INT | `INT8` | 8x8 | +| `torch.repeat_interleave` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.round` | INT | `INT8` | 8x8 | +| `torch.rsqrt` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.scalar_tensor` | INT | `INT8` | 8x8 | +| `torch.select` / `torch.Tensor.select` | INT | `INT8` | 8x8 | +| `torch.sigmoid` / `torch.nn.Sigmoid` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.sign` | INT | `INT8` | 8x8 | +| `torch.sin` | INT | `INT8` | 8x8 | +| `torch.sinh` | INT | `INT8` | 8x8 | +| `torch.softmax` | INT | `INT8` | 8x8 | +| `torch.split` / `torch.Tensor.split` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.squeeze` | INT | `INT8` | 8x8 | +| `torch.squeeze` / `torch.Tensor.squeeze` | INT | `INT8` | 8x8 | +| `torch.stack` | INT | `INT8` | 8x8 | +| `torch.sub` / `-` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.sum` | INT | `INT8` | 8x8 | +| `torch.t` / `torch.Tensor.t` | INT | `INT8` | 8x8 | +| `torch.tan` | INT | `INT8` | 8x8 | +| `torch.tanh` / `torch.nn.Tanh` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.Tensor.__getitem__` / `tensor slicing` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.Tensor.__setitem__` / `tensor indexing assignment` | INT | `INT8` | 8x8 | +| `torch.Tensor.copy_` | INT | `INT8` | 8x8 | +| `torch.Tensor.expand` | INT | `INT8` | 8x8 | +| `torch.Tensor.repeat` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.Tensor.unfold` | INT | `INT8` | 8x8 | +| `torch.Tensor.view` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.transpose` / `torch.Tensor.transpose` | INT | `INT8` | 8x8 | +| `torch.unflatten` | INT | `INT8` | 8x8 | +| `torch.unsqueeze` / `torch.Tensor.unsqueeze` | INT | `INT8` | 8x8 | +| `torch.where` | INT | `INT8`, `INT16` | 8x8, 16x8 | +| `torch.while_loop` | INT | `INT8` | 8x8 | +| `torch.zeros` | INT | `INT8` | 8x8 |