diff --git a/backends/arm/_passes/match_arg_ranks_pass.py b/backends/arm/_passes/match_arg_ranks_pass.py index 2cfc9b2b86a..9f966596de3 100644 --- a/backends/arm/_passes/match_arg_ranks_pass.py +++ b/backends/arm/_passes/match_arg_ranks_pass.py @@ -48,6 +48,8 @@ def __init__(self, exported_program): exir_ops.edge.aten.bitwise_right_shift.Tensor, exir_ops.edge.aten.bitwise_left_shift.Tensor, exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.lt.Tensor, exir_ops.edge.aten.pow.Tensor_Tensor, exir_ops.edge.aten.where.self, ] diff --git a/backends/arm/_passes/replace_scalar_with_tensor_pass.py b/backends/arm/_passes/replace_scalar_with_tensor_pass.py index 97e89132979..f24d53215f5 100644 --- a/backends/arm/_passes/replace_scalar_with_tensor_pass.py +++ b/backends/arm/_passes/replace_scalar_with_tensor_pass.py @@ -26,6 +26,8 @@ exir_ops.edge.aten.__rshift__.Scalar: exir_ops.edge.aten.bitwise_right_shift.Tensor, exir_ops.edge.aten.__lshift__.Scalar: exir_ops.edge.aten.bitwise_left_shift.Tensor, exir_ops.edge.aten.eq.Scalar: exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.gt.Scalar: exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.lt.Scalar: exir_ops.edge.aten.lt.Tensor, torch.ops.aten.add.Scalar: torch.ops.aten.add.Tensor, torch.ops.aten.sub.Scalar: torch.ops.aten.sub.Tensor, torch.ops.aten.mul.Scalar: torch.ops.aten.mul.Tensor, @@ -33,6 +35,8 @@ torch.ops.aten.__rshift__.Scalar: torch.ops.aten.bitwise_right_shift.Tensor, torch.ops.aten.__lshift__.Scalar: torch.ops.aten.bitwise_left_shift.Tensor, torch.ops.aten.eq.Scalar: torch.ops.aten.eq.Tensor, + torch.ops.aten.gt.Scalar: torch.ops.aten.gt.Tensor, + torch.ops.aten.lt.Scalar: torch.ops.aten.lt.Tensor, } diff --git a/backends/arm/operator_support/ethos_u55_support.py b/backends/arm/operator_support/ethos_u55_support.py index 69fda636423..b716acd0867 100644 --- a/backends/arm/operator_support/ethos_u55_support.py +++ b/backends/arm/operator_support/ethos_u55_support.py @@ -135,8 +135,10 @@ class EthosU55NotSupported(OperatorSupportBase): exir_ops.edge.aten.eq.Scalar, exir_ops.edge.aten.ge.Tensor, exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, exir_ops.edge.aten.le.Tensor, exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, exir_ops.edge.aten.flip.default, # REVERSE exir_ops.edge.aten.grid_sampler_2d, # GATHER exir_ops.edge.aten.scatter.src, diff --git a/backends/arm/operator_support/tosa_supported_operators.py b/backends/arm/operator_support/tosa_supported_operators.py index 09230e44257..24f8b1deeec 100644 --- a/backends/arm/operator_support/tosa_supported_operators.py +++ b/backends/arm/operator_support/tosa_supported_operators.py @@ -176,8 +176,10 @@ def is_node_supported( exir_ops.edge.aten.full_like.default, exir_ops.edge.aten.ge.Tensor, exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, exir_ops.edge.aten.le.Tensor, exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, exir_ops.edge.aten.mul.Tensor, exir_ops.edge.aten.add.Scalar, exir_ops.edge.aten.sub.Scalar, diff --git a/backends/arm/test/ops/test_eq.py b/backends/arm/test/ops/test_eq.py index 7cbba632696..e3bcf877ffe 100644 --- a/backends/arm/test/ops/test_eq.py +++ b/backends/arm/test/ops/test_eq.py @@ -96,8 +96,16 @@ def test_eq_scalar_tosa_MI(test_module): pipeline.run() -@common.parametrize("test_module", test_data_tensor | test_data_scalar) -def test_eq_tosa_BI(test_module): +@common.parametrize("test_module", test_data_tensor) +def test_eq_tensor_tosa_BI(test_module): + pipeline = TosaPipelineBI[input_t]( + test_module, test_module.get_inputs(), Equal.aten_op_Tensor, Equal.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_eq_scalar_tosa_BI(test_module): pipeline = TosaPipelineBI[input_t]( test_module, test_module.get_inputs(), Equal.aten_op_Tensor, Equal.exir_op ) @@ -133,15 +141,34 @@ def test_eq_scalar_u55_BI(test_module): @common.parametrize( "test_module", - test_data_tensor | test_data_scalar, + test_data_tensor, xfails={ "eq_tensor_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", + }, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_eq_tensor_u85_BI(test_module): + pipeline = EthosU85PipelineBI[input_t]( + test_module, + test_module.get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, + xfails={ "eq_scalar_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", }, strict=False, ) @common.XfailIfNoCorstone320 -def test_eq_u85_BI(test_module): +def test_eq_scalar_u85_BI(test_module): pipeline = EthosU85PipelineBI[input_t]( test_module, test_module.get_inputs(), diff --git a/backends/arm/test/ops/test_gt.py b/backends/arm/test/ops/test_gt.py index 2095f781bdb..15515958c85 100644 --- a/backends/arm/test/ops/test_gt.py +++ b/backends/arm/test/ops/test_gt.py @@ -5,7 +5,6 @@ from typing import Tuple -import pytest import torch from executorch.backends.arm.test import common @@ -16,13 +15,15 @@ TosaPipelineMI, ) -aten_op = "torch.ops.aten.gt.Tensor" -exir_op = "executorch_exir_dialects_edge__ops_aten_gt_Tensor" input_t = Tuple[torch.Tensor] class Greater(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.gt.Tensor" + aten_op_scalar = "torch.ops.aten.gt.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_gt_Tensor" + def __init__(self, input, other): super().__init__() self.input_ = input @@ -31,7 +32,7 @@ def __init__(self, input, other): def forward( self, input_: torch.Tensor, - other_: torch.Tensor, + other_: torch.Tensor | int | float, ): return input_ > other_ @@ -39,98 +40,135 @@ def get_inputs(self): return (self.input_, self.other_) -op_gt_rank1_ones = Greater( +op_gt_tensor_rank1_ones = Greater( torch.ones(5), torch.ones(5), ) -op_gt_rank2_rand = Greater( +op_gt_tensor_rank2_rand = Greater( torch.rand(4, 5), torch.rand(1, 5), ) -op_gt_rank3_randn = Greater( +op_gt_tensor_rank3_randn = Greater( torch.randn(10, 5, 2), torch.randn(10, 5, 2), ) -op_gt_rank4_randn = Greater( +op_gt_tensor_rank4_randn = Greater( torch.randn(3, 2, 2, 2), torch.randn(3, 2, 2, 2), ) -test_data_common = { - "gt_rank1_ones": op_gt_rank1_ones, - "gt_rank2_rand": op_gt_rank2_rand, - "gt_rank3_randn": op_gt_rank3_randn, - "gt_rank4_randn": op_gt_rank4_randn, +op_gt_scalar_rank1_ones = Greater(torch.ones(5), 1.0) +op_gt_scalar_rank2_rand = Greater(torch.rand(4, 5), 0.2) +op_gt_scalar_rank3_randn = Greater(torch.randn(10, 5, 2), -0.1) +op_gt_scalar_rank4_randn = Greater(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "gt_tensor_rank1_ones": op_gt_tensor_rank1_ones, + "gt_tensor_rank2_rand": op_gt_tensor_rank2_rand, + "gt_tensor_rank3_randn": op_gt_tensor_rank3_randn, + "gt_tensor_rank4_randn": op_gt_tensor_rank4_randn, +} + +test_data_scalar = { + "gt_scalar_rank1_ones": op_gt_scalar_rank1_ones, + "gt_scalar_rank2_rand": op_gt_scalar_rank2_rand, + "gt_scalar_rank3_randn": op_gt_scalar_rank3_randn, + "gt_scalar_rank4_randn": op_gt_scalar_rank4_randn, } -@common.parametrize("test_module", test_data_common) -def test_gt_tosa_MI(test_module): +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_MI(test_module): + pipeline = TosaPipelineMI[input_t]( + test_module, test_module.get_inputs(), Greater.aten_op_tensor, Greater.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_gt_scalar_tosa_MI(test_module): pipeline = TosaPipelineMI[input_t]( - test_module, test_module.get_inputs(), aten_op, exir_op + test_module, test_module.get_inputs(), Greater.aten_op_scalar, Greater.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_BI(test_module): + pipeline = TosaPipelineBI[input_t]( + test_module, test_module.get_inputs(), Greater.aten_op_tensor, Greater.exir_op ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_gt_tosa_BI(test_module): +@common.parametrize("test_module", test_data_scalar) +def test_gt_scalar_tosa_BI(test_module): pipeline = TosaPipelineBI[input_t]( - test_module, test_module.get_inputs(), aten_op, exir_op + test_module, test_module.get_inputs(), Greater.aten_op_tensor, Greater.exir_op ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_gt_u55_BI(test_module): - # GREATER is not supported on U55. +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_gt_tensor_u55_BI(test_module): + # Greater is not supported on U55. pipeline = OpNotSupportedPipeline[input_t]( test_module, test_module.get_inputs(), "TOSA-0.80+BI+u55", - {exir_op: 1}, + {Greater.exir_op: 1}, ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_gt_u85_BI(test_module): - pipeline = EthosU85PipelineBI[input_t]( +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_gt_scalar_u55_BI(test_module): + # Greater is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( test_module, test_module.get_inputs(), - aten_op, - exir_op, - run_on_fvp=False, - use_to_edge_transform_and_lower=True, + "TOSA-0.80+BI+u55", + {Greater.exir_op: 1}, + n_expected_delegates=1, ) pipeline.run() -@common.parametrize("test_module", test_data_common) -@pytest.mark.skip(reason="The same as test_gt_u55_BI") -def test_gt_u55_BI_on_fvp(test_module): - # GREATER is not supported on U55. - pipeline = OpNotSupportedPipeline[input_t]( +@common.parametrize( + "test_module", + test_data_tensor, + xfails={ + "gt_tensor_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", + }, +) +@common.XfailIfNoCorstone320 +def test_gt_tensor_u85_BI(test_module): + pipeline = EthosU85PipelineBI[input_t]( test_module, test_module.get_inputs(), - "TOSA-0.80+BI+u55", - {exir_op: 1}, + Greater.aten_op_tensor, + Greater.exir_op, + run_on_fvp=True, ) pipeline.run() @common.parametrize( "test_module", - test_data_common, - xfails={"gt_rank4_randn": "4D fails because boolean Tensors can't be subtracted"}, + test_data_scalar, + xfails={ + "gt_scalar_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", + }, ) -@common.SkipIfNoCorstone320 -def test_gt_u85_BI_on_fvp(test_module): +@common.XfailIfNoCorstone320 +def test_gt_scalar_u85_BI(test_module): pipeline = EthosU85PipelineBI[input_t]( test_module, test_module.get_inputs(), - aten_op, - exir_op, + Greater.aten_op_tensor, + Greater.exir_op, run_on_fvp=True, - use_to_edge_transform_and_lower=True, ) pipeline.run() diff --git a/backends/arm/test/ops/test_lt.py b/backends/arm/test/ops/test_lt.py index cae119cd7a8..f5664b7895d 100644 --- a/backends/arm/test/ops/test_lt.py +++ b/backends/arm/test/ops/test_lt.py @@ -5,7 +5,6 @@ from typing import Tuple -import pytest import torch from executorch.backends.arm.test import common @@ -16,13 +15,15 @@ TosaPipelineMI, ) -aten_op = "torch.ops.aten.lt.Tensor" -exir_op = "executorch_exir_dialects_edge__ops_aten_lt_Tensor" input_t = Tuple[torch.Tensor] class LessThan(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.lt.Tensor" + aten_op_scalar = "torch.ops.aten.lt.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_lt_Tensor" + def __init__(self, input, other): super().__init__() self.input_ = input @@ -31,7 +32,7 @@ def __init__(self, input, other): def forward( self, input_: torch.Tensor, - other_: torch.Tensor, + other_: torch.Tensor | int | float, ): return input_ < other_ @@ -39,98 +40,135 @@ def get_inputs(self): return (self.input_, self.other_) -op_lt_rank1_ones = LessThan( +op_lt_tensor_rank1_ones = LessThan( torch.ones(5), torch.ones(5), ) -op_lt_rank2_rand = LessThan( +op_lt_tensor_rank2_rand = LessThan( torch.rand(4, 5), torch.rand(1, 5), ) -op_lt_rank3_randn = LessThan( +op_lt_tensor_rank3_randn = LessThan( torch.randn(10, 5, 2), torch.randn(10, 5, 2), ) -op_lt_rank4_randn = LessThan( +op_lt_tensor_rank4_randn = LessThan( torch.randn(3, 2, 2, 2), torch.randn(3, 2, 2, 2), ) -test_data_common = { - "lt_rank1_ones": op_lt_rank1_ones, - "lt_rank2_rand": op_lt_rank2_rand, - "lt_rank3_randn": op_lt_rank3_randn, - "lt_rank4_randn": op_lt_rank4_randn, +op_lt_scalar_rank1_ones = LessThan(torch.ones(5), 1.0) +op_lt_scalar_rank2_rand = LessThan(torch.rand(4, 5), 0.2) +op_lt_scalar_rank3_randn = LessThan(torch.randn(10, 5, 2), -0.1) +op_lt_scalar_rank4_randn = LessThan(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "lt_tensor_rank1_ones": op_lt_tensor_rank1_ones, + "lt_tensor_rank2_rand": op_lt_tensor_rank2_rand, + "lt_tensor_rank3_randn": op_lt_tensor_rank3_randn, + "lt_tensor_rank4_randn": op_lt_tensor_rank4_randn, +} + +test_data_scalar = { + "lt_scalar_rank1_ones": op_lt_scalar_rank1_ones, + "lt_scalar_rank2_rand": op_lt_scalar_rank2_rand, + "lt_scalar_rank3_randn": op_lt_scalar_rank3_randn, + "lt_scalar_rank4_randn": op_lt_scalar_rank4_randn, } -@common.parametrize("test_module", test_data_common) -def test_lt_tosa_MI(test_module): +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_MI(test_module): + pipeline = TosaPipelineMI[input_t]( + test_module, test_module.get_inputs(), LessThan.aten_op_tensor, LessThan.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_lt_scalar_tosa_MI(test_module): pipeline = TosaPipelineMI[input_t]( - test_module, test_module.get_inputs(), aten_op, exir_op + test_module, test_module.get_inputs(), LessThan.aten_op_scalar, LessThan.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_BI(test_module): + pipeline = TosaPipelineBI[input_t]( + test_module, test_module.get_inputs(), LessThan.aten_op_tensor, LessThan.exir_op ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_lt_tosa_BI(test_module): +@common.parametrize("test_module", test_data_scalar) +def test_lt_scalar_tosa_BI(test_module): pipeline = TosaPipelineBI[input_t]( - test_module, test_module.get_inputs(), aten_op, exir_op + test_module, test_module.get_inputs(), LessThan.aten_op_tensor, LessThan.exir_op ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_lt_u55_BI(test_module): - # GREATER is not supported on U55. LT uses the GREATER Tosa operator. +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_lt_tensor_u55_BI(test_module): + # LessThan is not supported on U55. pipeline = OpNotSupportedPipeline[input_t]( test_module, test_module.get_inputs(), "TOSA-0.80+BI+u55", - {exir_op: 1}, + {LessThan.exir_op: 1}, ) pipeline.run() -@common.parametrize("test_module", test_data_common) -def test_lt_u85_BI(test_module): - pipeline = EthosU85PipelineBI[input_t]( +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_lt_scalar_u55_BI(test_module): + # LessThan is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( test_module, test_module.get_inputs(), - aten_op, - exir_op, - run_on_fvp=False, - use_to_edge_transform_and_lower=True, + "TOSA-0.80+BI+u55", + {LessThan.exir_op: 1}, + n_expected_delegates=1, ) pipeline.run() -@common.parametrize("test_module", test_data_common) -@pytest.mark.skip(reason="The same as test_lt_u55_BI") -def test_lt_u55_BI_on_fvp(test_module): - # GREATER is not supported on U55. LT uses the GREATER Tosa operator. - pipeline = OpNotSupportedPipeline[input_t]( +@common.parametrize( + "test_module", + test_data_tensor, + xfails={ + "lt_tensor_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", + }, +) +@common.XfailIfNoCorstone320 +def test_lt_tensor_u85_BI(test_module): + pipeline = EthosU85PipelineBI[input_t]( test_module, test_module.get_inputs(), - "TOSA-0.80+BI+u55", - {exir_op: 1}, + LessThan.aten_op_tensor, + LessThan.exir_op, + run_on_fvp=True, ) pipeline.run() @common.parametrize( "test_module", - test_data_common, - xfails={"lt_rank4_randn": "4D fails because boolean Tensors can't be subtracted"}, + test_data_scalar, + xfails={ + "lt_scalar_rank4_randn": "MLETORCH-847: Boolean eq result unstable on U85", + }, ) -@common.SkipIfNoCorstone320 -def test_lt_u85_BI_on_fvp(test_module): +@common.XfailIfNoCorstone320 +def test_lt_scalar_u85_BI(test_module): pipeline = EthosU85PipelineBI[input_t]( test_module, test_module.get_inputs(), - aten_op, - exir_op, + LessThan.aten_op_tensor, + LessThan.exir_op, run_on_fvp=True, - use_to_edge_transform_and_lower=True, ) pipeline.run() diff --git a/backends/arm/test/ops/test_where.py b/backends/arm/test/ops/test_where.py index bf127460f3e..dd4f3326f8e 100644 --- a/backends/arm/test/ops/test_where.py +++ b/backends/arm/test/ops/test_where.py @@ -173,14 +173,9 @@ def test_where_u55_BI(test_module): get_symmetric_quantization_config() ) - # If condition is tensor_condition then there will be one full_like op which will be - # delegated. - if test_module.condition == tensor_condition: - num_delegates = 1 - num_exir = 0 - else: - num_delegates = 0 - num_exir = 0 + # There will be one full_like op which will be delegated. + num_delegates = 1 + num_exir = 0 pipeline = OpNotSupportedPipeline[input_t]( test_module, @@ -223,14 +218,9 @@ def test_where_u55_BI_on_fvp(test_module): get_symmetric_quantization_config() ) - # If condition is tensor_condition then there will be one full_like op which will be - # delegated. - if test_module.condition == tensor_condition: - num_delegates = 1 - num_exir = 0 - else: - num_delegates = 0 - num_exir = 0 + # There will be one full_like op which will be delegated. + num_delegates = 1 + num_exir = 0 pipeline = OpNotSupportedPipeline[input_t]( test_module, @@ -249,18 +239,7 @@ def test_where_u55_BI_on_fvp(test_module): pipeline.run() -@common.parametrize( - "test_module", - test_modules_BI, - xfails={ - "two_dim_scalar_cond": "E [executorch:method.cpp:601] Missing operator: " - "[2] aten::gt.Scalar_out", - "three_dim_scalar_cond": "E [executorch:method.cpp:601] Missing operator: " - "[2] aten::gt.Scalar_out", - "float32_scalar_cond": "E [executorch:method.cpp:601] Missing operator: " - "[2] aten::gt.Scalar_out", - }, -) +@common.parametrize("test_module", test_modules_BI) @common.XfailIfNoCorstone320 def test_where_u85_BI_on_fvp(test_module): compile_spec = common.get_u85_compile_spec()